About OpenGL Methods Used in This Tutorial

As with ambient reflection, objects must have a material color versus a "simple" color when using lighting. In turn, before making function calls that draw the geometry, we must make a call to set the geometry's material (see tutorial on ambient reflection). In the case of diffuse reflection versus ambient reflection, we use the constant GL_DIFFUSE in the call. If we wish to have both ambient and diffuse reflection computed using the same color, we can make a single call as seen in the following OpenGL function call

glMaterialfv(GL_FRONT,
             GL_AMBIENT_AND_DIFFUSE, C);

where C again represents an array of four float values and establishes the object's material color. As noted in the ambient reflection tutorial, the GL constants GL_BACK and GL_FRONT_BACK can be used in place of GL_FRONT.

We establish a light source (omni, directional or spot) using the OpenGL function glLight. OpenGL provides for at least eight light sources and are identified by the constants GL_LIGHT0 .. GL_LIGHT7. Keep in mind that the actual number allowed is dependent upon the particular implementation. Various properties must be set depending on the light source we are modeling. Besides ambient light, we are using omni and directional lights in this tutorial (see the tutorial Specular Reflection for setting the properties of a spotlight). The function calls for defining an omni (positional) light are as follows:

glLightfv(GL_LIGHT1,
             GL_DIFFUSE,  C);
glLightfv(GL_LIGHT1,
             GL_POSITION, P);

where again C represents an array of four float values that hold the light's color. P is an array of four float values that hold the coordinates of the omni light's position in homogeneous coordinates. We use for the first three components the world coordinates of the light's position and 1.0 for the fourth component.

The OpenGL calls for establishing a directional light are similar except the value for position has a different meaning. The calls used in this tutorial are

glLightfv(GL_LIGHT3,
          GL_DIFFUSE,  C);
glLightfv(GL_LIGHT3,
          GL_POSITION, P);

where C is again an array of color values. P is also an array of four float values in homogeneous coordinates but for a directional light the fourth component is set to 0.0 and the first three components specify a direction versus a position.

As with ambient reflection, we must not only enable lighting with the call

glEnable(GL_LIGHTING);

but we must also enable the individual lights with calls such as

glEnable(GL_LIGHT1);

As seen with this tutorial, we set vertex normals for use in the illumination calculations. The function we use to define a vertex normal is

glNormal3dv(N);

where N represents an array of three double values. The values are the x, y and z coordinates of the normal and, in particular, the coordinates of a direction vector versus a point. You can also give the normal as three individual double values using the function glNormal3d. Data types other than double may also be used such as float with the methods glNormal3fv and glNormal3f. Last, a normal need not be normalized (be of unit length) when specified. But keep in mind that normals of unit length are used in the illumination calculations. In turn, the following function call requests that our normals be normalized by OpenGL

glEnable(GL_NORMALIZE);

Last, the call to a glNormal function is made just prior to a call for setting the corresponding vertex. An example of this sequence of calls as used in this tutorial follows.

glBegin(GL_POLYGON);
   glNormal3dv(leftVaringNormal);
   glVertex3dv(vertex0);
   glVertex3dv(vertex1);
   glNormal3dv(leftNormal
   glVertex3dv(vertex2);
   glVertex3dv(vertex3);
glEnd();

The parameter leftVaringNormal is an array of three doubles representing the normal at the two common vertices, vertex0 and vertex1. The normal at the other vertices of the left face, vertex2 and vertex3, is represent by the array leftNormal.