Open GL Super Bible

Previous Table of Contents Next


Diffuse and Specular Effects

For ambient light, this is as simple as it gets. Diffuse light, too, has RGB intensities that interact in the same way with material properties. However, diffuse light is directional, and the intensity at the surface of the object will vary depending on the angle between the surface and the light source. The same goes for specular light sources and intensities. The net effect in terms of RGB values is figured the same way as for ambient light, with the intensity of the light source (adjusted for the angle of incidence) being multiplied by the material reflectance. Finally, all three RGB terms are added to yield a final color for the object. If any single color component is above 1.0, it is clamped to that value (you canít get more intense than full intensity!).

Generally, the ambient and diffuse components of light sources and materials are the same and have the greatest effect in determining the color of the object. Specular light and material properties tend to be light gray or white. The specular component depends significantly on the angle of incidence, and specular highlights on an object are usually white.

Adding Light to a Scene

This may seem like a lot of theory to digest all of a sudden. So letís slow down and start exploring some examples of the OpenGL code needed for lighting; this will also help reinforce what youíve just learned. We will also be demonstrating some additional features and requirements of lighting in OpenGL. The next few examples build on our JET program. The initial version contains no lighting code and just draws triangles with hidden surface elimination enabled. But when weíre done, the jetís metallic surface will glisten in the sunlight as you rotate it with the arrow keys.

Enable the Lighting

To tell OpenGL to use lighting calculations, call glEnable() with the GL_LIGHTING parameter, like this:

glEnable(GL_LIGHTING);

This alone tells OpenGL to use material properties and lighting parameters in determining the color for each vertex in your scene. However, without any specified material properties or lighting parameters, your object will remain dark and unlit as shown in Figure 9-6. Look at the code for any of the JET-based example programs, and youíll see that we have called a function SetupRC() right after creating the rendering context. This is where we will do any initialization of lighting parameters.


Figure 9-6  Jet with lighting enabled, but no light or material properties defined

Set Up the Lighting Model

After enabling lighting calculations, the first thing you need to do is set up the lighting model. The three parameters that affect the lighting model are set with the glLightModel() function.

The first lighting parameter used in our next example is GL_LIGHT_MODEL_AMBIENT. This allows a global ambient light to be specified that illuminates all objects evenly from all sides. The following code specifies that a bright white light is to be used:

// Bright white light - full intensity RGB values
GLfloat ambientLight[] = { 1.0f, 1.0f, 1.0f, 1.0f };

// Enable lighting
glEnable(GL_LIGHTING);

// Set light model to use ambient light specified by ambientLight[]
glLightModelfv(GL_LIGHT_MODEL_AMBIENT,ambientLight);

The variation of glLightModel shown here, glLightModelfv, takes as its first parameter the lighting model parameter being modified or set, and then an array of the RGBA values that make up the light. The default RGBA values of this global ambient light are (0.2, 0.2, 0.2, 1.0), which is fairly dim. Other lighting model parameters allow you to determine if the front, back, or both sides of polygons are illuminated, and the calculation of specular lighting angles. See the Reference Section for more information on these parameters.

Set Material Properties

Now that we have an ambient light source, we need to set some material properties so that our polygons reflect light and we can see our jet. There are two ways to set material properties. The first is to use the function glMaterial before specifying each polygon or set of polygons. Examine the following code fragment:

Glfloat gray[] = { 0.75f, 0.75f, 0.75f, 1.0f };
Ö
Ö
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, gray);

glBegin(GL_TRIANGLES);
        glVertex3f(-15.0f,0.0f,30.0f);
        glVertex3f(0.0f, 15.0f, 30.0f);
        glVertex3f(0.0f, 0.0f, -56.0f);
glEnd();

The first parameter to glMaterialfv specifies whether the front, back, or both (GL_FRONT, GL_BACK, or GL_FRONT_AND_BACK) take on the material properties specified. The second parameter tells which properties are being set; in this instance both the ambient and diffuse reflectances are being set to the same values. The final parameter is an array containing the RGBA values that make up these properties. All primitives specified after the glMaterial call are affected by the last values set, until another call to glMaterial is made.

Under most circumstances, the ambient and diffuse components are the same, and unless you want specular highlights (sparkling, shiny spots), you donít need to define specular reflective properties. Even so, it would still be quite tedious if we had to define an array for every color in our object and call glMaterial() before each polygon or group of polygons.


Previous Table of Contents Next