Normal Vectors (State Management and Drawing Geometric Objects) (OpenGL Programming)

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.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

Surface Normals at Vertices


void glNormal3{bsidf|(TYP£ nx, TYPE ny, TYPE nz);

void glNormal3{bsidf}v(const TYPE *v);

Sets the current normal vector as specified by the arguments. The nonvector version (without the v) takes three arguments, which specify an {nx, ny, nz) vector that’s taken to be the normal. Alternatively, you can use the vector version of this function (with the v) and supply a single array of three elements to specify the desired normal. The b, s, and i versions scale their parameter values linearly to the range [-1.0, 1.0].

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.

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 fromtmp5324-84_thumb

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:

tmp5324-85_thumb

 

tmp5324-86_thumb

 

Normal vectors remain normalized as long as your model transformations include only rotations and translations. 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.

Next post:

Previous post: