Open GL Super Bible

Previous Table of Contents Next


Specifying the Polygons

The rendering code from the first two JET samples changes considerably now, to support the new lighting model. Listing 9-5 is taken from the RenderScene() function from LITJET.

Listing 9-5 Code sample that sets color, calculates and specifies normals and polygons

        float normal[3];   // Storage for calculated surface normal
        …
        …
        // Set material color
        glRGB(0, 255, 0);
        glBegin(GL_TRIANGLES);
                glNormal3f(0.0f, -1.0f, 0.0f);
                glVertex3f(0.0f, 0.0f, 60.0f);
                glVertex3f(-15.0f, 0.0f, 30.0f);
                glVertex3f(15.0f,0.0f,30.0f);
        //glEnd();


        {
        // Vertices for this triangle
        float v[3][3] = {{ 15.0f, 0.0f, 30.0f},
                        { 0.0f, 15.0f, 30.0f},
                        { 0.0f, 0.0f, 60.0f}};

        // Calculate the normal for the plane
        calcNormal(v,normal);

        // Draw the triangle using the plane normal
        // for all the vertices
        //glBegin(GL_TRIANGLES);
                  glNormal3fv(normal);
                  glVertex3fv(v[0]);
                  glVertex3fv(v[1]);
                  glVertex3fv(v[2]);
        //glEnd();

        }

You’ll notice that we are calculating the normal vector using our code in Listing 9-3. Also, the material properties are now following the colors set by glColor (which is wrapped by our glRGB macro). One other thing you’ll notice is that not every triangle is blocked by glBegin()/glEnd() functions. You can specify once that you are drawing triangles, and every three vertices will be used for a new triangle until you specify otherwise with glEnd(). For very large numbers of polygons, this can considerably boost performance by eliminating many unnecessary function calls.

Figure 9-16 shows the output from the completed LITJET example program. By rotating the jet around with the arrow keys, you can see the dramatic shading effects as the surface of the jet moves in the light.


Figure 9-16  Output from LITJET sample


Performance Tip:  
The most obvious way to improve the performance of this code would be to calculate all the normal vectors ahead of time and store them for use in the Render function. Before you pursue this, read Chapter 10’s material on display lists. Display lists provide a means of storing calculated values not only for the normal vectors, but for the polygon data as well. Remember, these examples are meant to demonstrate the concepts. They are not necessarily the most efficient code possible.

Lighting Effects

The ambient and diffuse light from the LITJET example are sufficient to provide the illusion of lighting. The surface of the jet appears shaded according to the angle of the incident light. As the jet rotates, these angles change and you can see the lighting effects changing in such a way that you can easily guess where the light is coming from.

We ignored the specular component of the light source, however, as well as the specular reflectivity of the material properties on the jet. Although the lighting effects are pronounced, the surface of the jet is rather flatly colored. Ambient and diffuse lighting and material properties are all you need if you are modeling clay, wood, cardboard, cloth, or some other flatly colored object. But for metallic surfaces like the skin of an airplane, some shine is often necessary.

Specular Highlights

Specular lighting and material properties add needed gloss to the surface of your objects. This shininess has a whitening effect on an object’s color and can produce specular highlights when the angle of incident light is sharp in relation to the viewer. A specular highlight is what occurs when nearly all the light striking the surface of an object is reflected away. The white sparkle on a shiny red ball in the sunlight is good example of a specular highlight.

Specular Light

Adding a specular component to a light source is very easily done. The following code shows the light source setup for the LITJET program, modified to add a specular component to the light.

// Light values and coordinates
// Light values and coordinates
GLfloat  ambientLight[] = { 0.3f, 0.3f, 0.3f, 1.0f };
GLfloat  diffuseLight[] = { 0.7f, 0.7f, 0.7f, 1.0f };
GLfloat  specular[] = { 1.0f, 1.0f, 1.0f, 1.0f};
Glfloat  lightPos[] = { 0.0f, 150.0f, 150.0f, 1.0f };
…
…

// Enable lighting
glEnable(GL_LIGHTING);

// Setup and enable light 0
glLightfv(GL_LIGHT0,GL_AMBIENT,ambientLight);
glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuseLight);
glLightfv(GL_LIGHT0,GL_SPECULAR,specular);
glLightfv(GL_LIGHT0,GL_POSITION,lightPos);
glEnable(GL_LIGHT0);

The specular[] array specifies a very bright white light source for the specular component of the light. Our purpose here is to model bright sunlight. The line

glLightfv(GL_LIGHT0,GL_SPECULAR,specular);

simply adds this specular component to the light source GL_LIGHT0.

If this were the only change you made to LITJET, you wouldn’t see any difference in the jet’s appearance. This is because we haven’t yet defined any specular reflectance properties for the material properties.

Specular Reflectance

Adding specular reflectance to material properties is just as easy as adding the specular component to the light source. This next code segment shows the code from LITJET, again modified to add specular reflectance to the material properties.

// Light values and coordinates
GLfloat  specref[] =  { 1.0f, 1.0f, 1.0f, 1.0f };

…
…

// Enable color tracking
glEnable(GL_COLOR_MATERIAL);

// Set Material properties to follow glColor values
glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);

// All materials hereafter have full specular reflectivity
// with a high shine
glMaterialfv(GL_FRONT, GL_SPECULAR,specref);
glMateriali(GL_FRONT,GL_SHININESS,128);

As before, we enable color tracking so that the ambient and diffuse reflectance of the materials follow the current color set by the glColor() functions. (Of course, we don’t want the specular reflectance to track glColor, because we are specifying it separately and it doesn’t change.)

Now we’ve added an array specref[] that contains the RGBA values for our specular reflectance. This array of all 1’s will produce a surface that reflects nearly all incident specular light. The line

glMaterialfv(GL_FRONT, GL_SPECULAR,specref);

sets the material properties for all subsequent polygons to have this reflectance. Since we do not call glMaterial again with the GL_SPECULAR property, all materials will have this property. We did this on purpose because we want the entire jet to appear made of metal or very shiny composites.

What we have done here in our setup routine is important: We have specified that the ambient and diffuse reflective material properties of all future polygons (until we say otherwise with another call to glMaterial or glColorMaterial) will change as the current color changes, but that the specular reflective properties will remain the same.


Previous Table of Contents Next