A normal vector (or normal, for short) is a vector that points in a direction that’s perpendicular to a surface. For a flat surface, one perpendicular direction is the same for every point on the surface, but for a general curved surface, the normal direction might be different at each point on the surface. With OpenGL, you can specify a normal for each polygon or for each vertex. Vertices of the same polygon might share the same normal (for a flat surface) or have different normals (for a curved surface). You can’t assign normals anywhere other than at the vertices.
An object’s normal vectors define the orientation of its surface in space—in particular, its orientation relative to light sources. These vectors are used by OpenGL to determine how much light the object receives at its vertices. Lighting—a large topic by itself—is the subject of Chapter 5, and you might want to review the following information after you’ve read that chapter. Normal vectors are discussed briefly here because you define normal vectors for an object at the same time you define the object’s geometry.
You use glNormal*() to set the current normal to the value of the argument passed in. Subsequent calls to glVertex*() cause the specified vertices to be assigned the current normal. Often, each vertex has a different normal, which necessitates a series of alternating calls, as in Example 2-8.
Example 2-8. Surface Normals at Vertices
glBegin (GL_POLYGON); glNormal3fv(n0); glVertex3fv(v0); glNormal3fv(n1); glVertex3fv(v1); glNormal3fv(n2); glVertex3fv(v2); glNormal3fv(n3); glVertex3fv(v3); glEnd();
There’s no magic to finding the normals for an object—most likely, you have to perform some calculations that might include taking derivatives—but there are several techniques and tricks you can use to achieve certain effects. Appendix H, “Calculating Normal Vectors,”1 explains how to find normal vectors for surfaces. If you already know how to do this, if you can count on always being supplied with normal vectors, or if you don’t want to use the OpenGL lighting facilities, you don’t need to read this appendix.
Note that at a given point on a surface, two vectors are perpendicular to the surface, and they point in opposite directions. By convention, the normal is the one that points to the outside of the surface being modeled. (If you get inside and outside reversed in your model, just change every normal vector from (x, y, z) to (−x, −y, −z)).
Also, keep in mind that since normal vectors indicate direction only, their lengths are mostly irrelevant. You can specify normals of any length, but eventually they have to be converted to a length of 1 before lighting calculations are performed. (A vector that has a length of 1 is said to be of unit length, or normalized.) In general, you should supply normalized normal vectors. To make a normal vector of unit length, divide each of its x-, y-, z-components by the length of the normal:
Normal vectors remain normalized as long as your model transformations include only rotations and translations. (See Chapter 3 for a discussion of transformations.) If you perform irregular transformations (such as scaling or multiplying by a shear matrix), or if you specify nonunit-length normals, then you should have OpenGL automatically normalize your normal vectors after the transformations. To do this, call glEnable(GL_NORMALIZE).
If you supply unit-length normals, and you perform only uniform scaling (that is, the same scaling value for x, y, and z), you can use glEnable(GL_RESCALE_NORMAL) to scale the normals by a constant factor, derived from the modelview transformation matrix, to return them to unit length after transformation.
Note that automatic normalization or rescaling typically requires additional calculations that might reduce the performance of your application. Rescaling normals uniformly with GL_RESCALE_NORMAL is usually less expensive than performing full-fledged normalization with GL_NORMALIZE. By default, both automatic normalizing and rescaling operations are disabled.