user3085239
user3085239

Reputation: 3

Trouble Calculating Vertex Normals (in C++, for openGL project)

i have a project where i must read an OBJ file and display a model using GLUT. im reading and displaying the model fine but i can't get the normals to work ok. I have saved all faces in a Faces[] array of 3 vtx[] (=points) arrays with x,y,z and a normal also with x,y,z coordinates. I calculate 2 vectors that correspond to each one of the 3 Vertexes of each face, the i get their Cross Product, I Normalize it and I add its x,y,z coodrdinates to the Normal parameter (so that if there is more than one Normal for each Vertex we add them an get somthing like the average of all the normal vectors) and I normalize again. When i print out the some Normal coordinates to see what happens it prints out 0,0,(something weird) as x,y,z. Anyway here's the code.

     for (int i = 0 ; i<triangle_index; i++)
    {
        float ux,uy,uz,vx,vy,vz,nn,nx,ny,nz;

    //get vectors from first vertex of face
        ux= Faces[triangle_index].vtx[1].x - Faces[triangle_index].vtx[0].x ;
        uy= Faces[triangle_index].vtx[1].y - Faces[triangle_index].vtx[0].y ;
        uz= Faces[triangle_index].vtx[1].z - Faces[triangle_index].vtx[0].z ;

        vx= Faces[triangle_index].vtx[2].x - Faces[triangle_index].vtx[0].x ;
        vy= Faces[triangle_index].vtx[2].y - Faces[triangle_index].vtx[0].y ;
        vz= Faces[triangle_index].vtx[2].z - Faces[triangle_index].vtx[0].z ;
   //CrossProduct 
        nx = (uy*vz) - (vy*uz);
        ny = (vx*uz) - (ux*vz);
        nz = (ux*vy) - (uy*vx);
   //Length         
        nn = sqrt((nx*nx)+(ny*ny)+(nz*nz));
   //Normalize                  
        nx = nx/nn;
        ny = ny/nn;
        nz = nz/nn;
    //Save to Vertex.Normal (plus any previous data)
    Faces[triangle_index].vtx[0].norm.x =(Faces[triangle_index].vtx[0].norm.x + nx);
    Faces[triangle_index].vtx[0].norm.y =(Faces[triangle_index].vtx[0].norm.y + ny);
    Faces[triangle_index].vtx[0].norm.z =(Faces[triangle_index].vtx[0].norm.z + nz);

  //get length again 

  nn =  sqrt((Faces[triangle_index].vtx[0].norm.x*Faces[triangle_index].vtx[0].norm.x)+(Faces[triangle_index].vtx[0].norm.y*Faces[triangle_index].vtx[0].norm.y)+(Faces[triangle_index].vtx[0].norm.z*Faces[triangle_index].vtx[0].norm.z));

    //Normalize again

        Faces[triangle_index].vtx[0].norm.x =(Faces[triangle_index].vtx[0].norm.x)/nn;
        Faces[triangle_index].vtx[0].norm.y =(Faces[triangle_index].vtx[0].norm.y)/nn;
        Faces[triangle_index].vtx[0].norm.z =(Faces[triangle_index].vtx[0].norm.z)/nn;

   //---------------Same For Second Vertex of the Same Face---------------------------/

        ux= Faces[triangle_index].vtx[2].x - Faces[triangle_index].vtx[1].x ;
        uy= Faces[triangle_index].vtx[2].y - Faces[triangle_index].vtx[1].y ;
        uz= Faces[triangle_index].vtx[2].z - Faces[triangle_index].vtx[1].z ;

        vx= Faces[triangle_index].vtx[0].x - Faces[triangle_index].vtx[1].x ;
        vy= Faces[triangle_index].vtx[0].y - Faces[triangle_index].vtx[1].y ;
        vz= Faces[triangle_index].vtx[0].z - Faces[triangle_index].vtx[1].z ;

        nx = (uy*vz) - (vy*uz);
        ny = (vx*uz) - (ux*vz);
        nz = (ux*vy) - (uy*vx);

        nn = sqrt((nx*nx)+(ny*ny)+(nz*nz));

        nx = nx/nn;
        ny = ny/nn;
        nz = nz/nn;

        Faces[triangle_index].vtx[1].norm.x =(Faces[triangle_index].vtx[1].norm.x + nx);
        Faces[triangle_index].vtx[1].norm.y =(Faces[triangle_index].vtx[1].norm.y + ny);
        Faces[triangle_index].vtx[1].norm.z =(Faces[triangle_index].vtx[1].norm.z + nz);

    nn =sqrt((Faces[triangle_index].vtx[1].norm.x*Faces[triangle_index].vtx[1].norm.x)+(Faces[triangle_index].vtx[1].norm.y*Faces[triangle_index].vtx[1].norm.y)+(Faces[triangle_index].vtx[1].norm.z*Faces[triangle_index].vtx[1].norm.z));

        Faces[triangle_index].vtx[1].norm.x =(Faces[triangle_index].vtx[1].norm.x)/nn;
        Faces[triangle_index].vtx[1].norm.y =(Faces[triangle_index].vtx[1].norm.y)/nn;
        Faces[triangle_index].vtx[1].norm.z =(Faces[triangle_index].vtx[1].norm.z)/nn;
    //------------------Again for number three--------------------------------
    ux= Faces[triangle_index].vtx[0].x - Faces[triangle_index].vtx[2].x ;
    uy= Faces[triangle_index].vtx[0].y - Faces[triangle_index].vtx[2].y ;
    uz= Faces[triangle_index].vtx[0].z - Faces[triangle_index].vtx[2].z ;

    vx= Faces[triangle_index].vtx[1].x - Faces[triangle_index].vtx[2].x ;
    vy= Faces[triangle_index].vtx[1].y - Faces[triangle_index].vtx[2].y ;
    vz= Faces[triangle_index].vtx[1].z - Faces[triangle_index].vtx[2].z ;

    nx = (uy*vz) - (vy*uz);
    ny = (vx*uz) - (ux*vz);
    nz = (ux*vy) - (uy*vx);

    nn = sqrt((nx*nx)+(ny*ny)+(nz*nz));

    nx = nx/nn;
    ny = ny/nn;
    nz = nz/nn;

    Faces[triangle_index].vtx[2].norm.x =(Faces[triangle_index].vtx[2].norm.x + nx);
    Faces[triangle_index].vtx[2].norm.y =(Faces[triangle_index].vtx[2].norm.y + ny);
    Faces[triangle_index].vtx[2].norm.z =(Faces[triangle_index].vtx[2].norm.z + nz);

    nn =  sqrt((Faces[triangle_index].vtx[2].norm.x*Faces[triangle_index].vtx[2].norm.x)+(Faces[triangle_index].vtx[2].norm.y*Faces[triangle_index].vtx[2].norm.y)+(Faces[triangle_index].vtx[2].norm.z*Faces[triangle_index].vtx[2].norm.z));

    Faces[triangle_index].vtx[2].norm.x =(Faces[triangle_index].vtx[2].norm.x)/nn;
    Faces[triangle_index].vtx[2].norm.y =(Faces[triangle_index].vtx[2].norm.y)/nn;
    Faces[triangle_index].vtx[2].norm.z =(Faces[triangle_index].vtx[2].norm.z)/nn;

   } 

if i add this loop just to see what goes on after the normals are calculated

for (int i =0 ; i<100;i++)
cout << "n "<<  Faces[i].vtx[0].norm.x<< " "<< Faces[i].vtx[0].norm.x <<" "<<  Faces[i].vtx[0].norm.x <<"\n";

i get all zeros for the norm.x,y,z. can anyone see whats wrong with the code?

Upvotes: 0

Views: 509

Answers (2)

Joe Z
Joe Z

Reputation: 17936

You're using triangle_index for your array indexing everywhere:

    ux= Faces[triangle_index].vtx[1].x - Faces[triangle_index].vtx[0].x ;
    uy= Faces[triangle_index].vtx[1].y - Faces[triangle_index].vtx[0].y ;
    uz= Faces[triangle_index].vtx[1].z - Faces[triangle_index].vtx[0].z ;

I think you want to use your loop index instead:

    ux= Faces[i].vtx[1].x - Faces[i].vtx[0].x ;
    uy= Faces[i].vtx[1].y - Faces[i].vtx[0].y ;
    uz= Faces[i].vtx[1].z - Faces[i].vtx[0].z ;

You need to fix this throughout the loop.

Also, to properly average the normals at the vertices, you should only accumulate them in this loop, and renormalize them in a new, second loop. That is, put these two steps in two passes:

    Faces[i].vtx[0].norm.x += nx;
    Faces[i].vtx[0].norm.y += ny;
    Faces[i].vtx[0].norm.z += nz;

and

    nn = sqrt( (Faces[i].vtx[0].norm.x*Faces[i].vtx[0].norm.x)
             + (Faces[i].vtx[0].norm.y*Faces[i].vtx[0].norm.y)
             + (Faces[i].vtx[0].norm.z*Faces[i].vtx[0].norm.z) );

    Faces[i].vtx[0].norm.x /= nn;
    Faces[i].vtx[0].norm.y /= nn;
    Faces[i].vtx[0].norm.z /= nn;

That way each triangle that's coincident on that vertex carries equal weight.

Upvotes: 1

Floris
Floris

Reputation: 46365

It is possible that your code is perfectly valid, and that the problem lies in the direction of your normals. If you have two triangles in the same plane meeting at a point, then the normal computed at the vertex may be in the opposite direction (say if the points are in the XY plane, you could have one normal [0 0 1] and the other [0 0 -1]), depending on the order of the vertices.

When you add these two vectors, you may get a vector with a length of zero, which will give you trouble during normalization.

I would check the length of the vectors, and maybe choose a "dominant direction" to prevent this problem. Or always assign the value of the triangle "whose centroid is closest to the vertex", or "centroid with lowest X, Y value" - etc.

Upvotes: 0

Related Questions