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.