Open GL Super Bible

Previous Table of Contents Next


The Shaft

The shaft of the bolt is nothing more than a cylinder with a bottom on it. We compose a cylinder by plotting xy values around in a circle, and then take two z values at these points and get polygons that approximate the wall of a cylinder. Once again, however, we will compose this wall entirely out of triangles. Figure 10-4 shows the outline of the cylinder.


Figure 10-4  Triangle outline of the bolt shaft

We also create the bottom of the shaft with a triangle fan. Notice that the smaller the step size is around the circle, the smaller the flat facets that make up the cylinder wall and the more closely the wall will approximate a smooth curve.

Listing 10-5 is the code to produce this cylinder. Notice that the normals are not calculated for the triangles using the vertices of the triangles. We usually set the normal to be the same for all vertices, but here we’ll break with this tradition to specify a new normal for each vertex. Since we are simulating a curved surface, the normal specified for each vertex would be normal to the actual curve.

Listing 10-5 Rendering the shaft of the bolt

// Creates the shaft of the bolt as a cylinder with one end
// closed.
void RenderShaft(void)
        {
        float x,y,angle;                  // Used to calculate cylinder
                                           wall
        float height = 75.0f;             // Height of the cylinder
        float diameter = 20.0f;           // Diameter of the cylinder
        float normal[3],corners[4][3];    // Storage for vertices
                                           calculations
        float step = (3.1415f/50.0f);     // Approximate the cylinder
                                           wall with
                                          // 100 flat segments.

        // Set material color for head of screw
        glColor3f(0.0f, 0.0f, 0.7f);

        // counterclockwise polygons face out (the default for triangles)
        glFrontFace(GL_CCW);


        // First assemble the wall as 100 quadrilaterals formed by
        // placing adjoining triangles together
        glBegin(GL_TRIANGLES);

        // Go around and draw the sides
        for(angle = 0.0f; angle < (2.0f*3.1415f); angle += step)
                {
                // Calculate x and y position of the next vertex
                x = diameter*(float)sin(angle);
                y = diameter*(float)cos(angle);

               // Get the coordinate for this point and extrude the
               // length of the cylinder.
               corners[0][0] = x;
               corners[0][1] = y;
               corners[0][2] = -height;

               corners[1][0] = x;
               corners[1][1] = y;
               corners[1][2] = 0.0f;

               // Get the next point and do the same
               x = diameter*(float)sin(angle+step);
               y = diameter*(float)cos(angle+step);

               // If finished, use known starting point to close the
               surface
               if(angle+step < 3.1415*2.0) // Not Finished
                       {
                       corners[2][0] = x;
                       corners[2][1] = y;
                       corners[2][2] = 0.0f;

                       corners[3][0] = x;
                       corners[3][1] = y;
                       corners[3][2] = -height;
                       }
               else
                       {
                       // Finished, use the starting point
                       corners[2][0] = 0.0f;
                       corners[2][1] = diameter;
                       corners[2][2] = 0.0f;

                       corners[3][0] = 0.0f;
                       corners[3][1] = diameter;
                       corners[3][2] = -height;
                       }

               // Instead of using real normal to actual flat section,
               // use what the normal would be if the surface were really
               // curved. Since the cylinder goes up the z axis, the normal
               // points from the z axis out directly through each vertex.
               // Therefore we can use the vertex as the normal, as long as
               // we reduce it to unit length first.

               // First Triangle ////////////////////////////////////////
               // Fill the normal vector with the coordinate points
               normal[0] = corners[0][0];
               normal[1] = corners[0][1];
               normal[2] = corners[0][2];

               // Reduce to length of one and specify for this point
               ReduceToUnit(normal);
               glNormal3fv(normal);
               glVertex3fv(corners[0]);

               // Get vertex, calculate unit normal and go
               normal[0] = corners[1][0];
               normal[1] = corners[1][1];
               normal[2] = corners[1][2];
               ReduceToUnit(normal);
               glNormal3fv(normal);
               glVertex3fv(corners[1]);

               // Get vertex, calculate unit normal and go
               normal[0] = corners[2][0];
               normal[1] = corners[2][1];
               normal[2] = corners[2][2];
               ReduceToUnit(normal);
               glNormal3fv(normal);
               glVertex3fv(corners[2]);


               // Second Triangle ////////////////////////////////////////

               // Get vertex, calculate unit normal and go
               normal[0] = corners[2][0];
               normal[1] = corners[2][1];
               normal[2] = corners[2][2];
               ReduceToUnit(normal);
               glNormal3fv(normal);
               glVertex3fv(corners[2]);

               // Get vertex, calculate unit normal and go
               normal[0] = corners[3][0];
               normal[1] = corners[3][1];
               normal[2] = corners[3][2];
               ReduceToUnit(normal);
               glNormal3fv(normal);
               glVertex3fv(corners[3]);

               // Get vertex, calculate unit normal and go
               normal[0] = corners[0][0];
               normal[1] = corners[0][1];
               normal[2] = corners[0][2];
               ReduceToUnit(normal);
               glNormal3fv(normal);
               glVertex3fv(corners[0]);
               }

        glEnd();         // Done with cylinder sides

        // Begin a new triangle fan to cover the bottom
        glBegin(GL_TRIANGLE_FAN);

        // Normal points down the z axis
        glNormal3f(0.0f, 0.0f, -1.0f);

        // Center of fan is at the origin
        glVertex3f(0.0f, 0.0f, -height);

        // Spin around, matching step size of cylinder wall
        for(angle = 0.0f; angle < (2.0f*3.1415f); angle += step)
                {
                // Calculate x and y position of the next vertex
                x = diameter*(float)sin(angle);
                y = diameter*(float)cos(angle);

                // Specify the next vertex for the triangle fan
                glVertex3f(x, y, -height);
                }

        // Close the fan
        glVertex3f(0.0f, diameter, -height);
        glEnd();
        }

Fortunately, the cylinder is wrapped symmetrically around the z-axis. Thus, the normal for each vertex can be found by normalizing (reducing to length 1) the vertex itself. Figure 10-5 shows the output from the SHAFT program.


Figure 10-5  Output from the SHAFT program


Previous Table of Contents Next