Vertex Normals

A facet normal is a vector that is perpendicular to each polygon in a mesh. From that definition it would seem that a vertex normal is a vector that is perpendicular to each vertex in a mesh. That definition would be incorrect, since a vertex is simply a point and cannot have a vector that is perpendicular to it. In its simplest form, a vertex normal is the average of the facet normals for each facet that contains the vertex. This provides a smoother looking surface when using lighting calculations.

 1. int main(int argc, char **argv)
 2. {
 3.    Cvector3 *vertex, *vertex_normal, a, b, c;
 4.    :
 5.    :
 6. //
 7. // Step 1. Loop thru faces; calculate face normals
 8. //
 9.    for(i=0;i<number_of_triangles;i++) {
10.      index1 = face[3*i+0];
11.      index2 = face[3*i+1];
12.      index3 = face[3*i+2];
13.      a = vertex[index2] - vertex[index3];
14.      b = vertex[index1] - vertex[index3];
15.      c.Cross(a,b);
16.      vertex_normal[index2] += c;
17.      vertex_normal[index3] += c;
18.      vertex_normal[index1] += c;
19.      count[index2] += 1.0;
20.      count[index3] += 1.0;
21.      count[index1] += 1.0;
22.    }
23. //
24. // Step 2. Loop thru vertex normals and normalize
25. //
26.    for(i=0;i<nv;i++) {
27.      vertex_normal[i] = vertex_normal[i]/count[i];
28.    }
29.    for(i=0;i<nv;i++) {
30.      vertex_normal[i].Normalize();
31.    }
32.    :
33.    :
34.    return 0;
35. }

However, it easy to think a case where using vertex normals as the average of surrounding facet normals, would give incorrect lighting results. One case in which this would be true is a pyramid. Averaging the vertex normals at any of its vertices would give incorrect lighting results. In general then, anywhere there is a sharp boundary in a mesh, the vertex normals should not be calculated as an average. In that case, the vertex normal could have the same value as that of the facet normal.

To take this into account, one could take the dot product between the facet normals of adjacent polygons. The dot product is simply the cosine of the angle between two vectors. If the dot product is greater than some value (say 0.707 for a 45 degree angle), then we use the average of surrounding facet normals. Otherwise we just use the facet normal.

There is another improvement that can be made to computing vertex normals. The vertex most likely is used by multiple polygons. The polygons probably have different sizes. The vertex normal can then be weighted by the areas of the polygons to which it belongs.

The source code from which the above pseudo-code is derived can be found in the PLY with Vertex Normals tutorial.


Back to Types of Normal Vectors