0
votes

I'm trying to write a program that loads .obj files. For some reason, my model only lights up with incorrectly calculated normal vectors. I haven't been able to find anything online that explains this anomaly.

This is how I am calculating the normals, which I believe to be the correct way.

vector<float> Vertex::findNormal(Vertex v2, Vertex v3)
{
    float va[3], vb[3], vr[3], val;
    /* Calculate 1st Vector */
    va[0] = v2.getX() - x;
    va[1] = v2.getY() - y;
    va[2] = v2.getZ() - z;
    /* Calculate 2nd Vector */
    vb[0] = v3.getX() - v2.getX();
    vb[1] = v3.getY() - v2.getY();
    vb[2] = v3.getZ() - v2.getZ();

    /* Cross Product */
    vr[0] = va[1] * vb[2] - vb[1] * va[2];
    vr[1] = vb[0] * va[2] - va[0] * vb[2];
    vr[2] = va[0] * vb[1] - vb[0] * va[1];

    /* Normalization Factor */
    val = sqrt(vr[0]*vr[0] + vr[1]*vr[1] + vr[2]*vr[2]);

    normal.push_back(vr[0]/val);
    normal.push_back(vr[1]/val);
    normal.push_back(vr[2]/val);

   return normal;
}

But this is the result : Correct Normals

Angel data set courtesy of the U.C. Berkeley Computer Animation and Modeling Group.

(won't let me post images because <10 reputation)

If I switch the direction of ONE of the vectors, like:

 /* Calculate 1st Vector */
    va[0] = x - v2.getX();
    va[1] = y - v2.getY();
    va[2] = z - v2.getZ();

Then it renders correctly:

Incorrect Normals

But it shouldn't, because the orientation of the vertices is counter clockwise. So by the right hand rule, the first calculation should produce the correct, outward facing normal vector.

I have tried to reverse the winding via,

glFrontFace(GL_CW);

I've unit tested my code to ensure the vertices are being read in counter clockwise order from the file, I've made countless modifications to the lighting settings to no avail.

Can anyone explain why this is happening? Is there an error in my vertex calculations that I am missing? Or any other ideas about what could be going wrong?

1
Rehost those images on stack.imgur.genpfault

1 Answers

2
votes

The problem is with how you are calculating the a and b vectors. Take a look at this image showing the right-hand-rule:

enter image description here

Vectors a and b both originate from the same point and point off in different directions. Vector b does not start from the tip of vector a.

However in your code, it's as if the base of the middle finger (vector b) starts from the tip of the index finger (vector a), because you are going around the triangle instead of choosing two vectors emanating from the same vertex. This is equivalent to using the tip of vector a as your common vertex, but with vector a pointing the wrong way

Picture a triangle overlaid on the image with clockwise numbered vertices:

enter image description here

(You could number the vertices in 3 different ways, but I've chosen the numbering that matches the working version of your code.)

To get vector a, which goes from vertex 2 to vertex 1, subtract vertex 2 from vertex 1:

/* Calculate 1st Vector */
va[0] = x - v2.getX();
va[1] = y - v2.getY();
va[2] = z - v2.getZ();

To get vector b, which goes from vertex 2 to vertex 3, subtract vertex 2 from vertex 3:

/* Calculate 2nd Vector */
vb[0] = v3.getX() - v2.getX();
vb[1] = v3.getY() - v2.getY();
vb[2] = v3.getZ() - v2.getZ();