Open GL Super Bible

Previous Table of Contents Next


The first parameter to glMap1f, GL_MAP1_VERTEX_3, sets up the evaluator to generate vertex coordinate triplets (x, y, and z), as opposed to GL_MAP1_VERTEX_4 which would generate the coordinates and an alpha component. You can also have the evaluator generate other values, such as texture coordinates and color information. See the Reference Section for details.

The next two parameters specify the lower and upper bounds of the parametric u value for this curve. The lower value specifies the first point on the curve, and the upper value specifies the last point on the curve. All the values in between correspond to the other points along the curve. Here we set the range to 0–100.

The fourth parameter to glMap1f specifies the number of floating point values between the vertices in the array of control points. Each vertex consists of three floating point values (for x, y, and z), so we set this value to 3. This flexibility allows the control points to be placed in an arbitrary data structure, as long as they occur at regular intervals.

The last parameter is a pointer to a buffer containing the control points used to define the curve. Here, we pass a pointer to the first element of the array. Once the mapping for the curve is created, we enable the evaluator to make use of this mapping. This is maintained through a state variable, and the following function call is all that is needed to enable the evaluator to produce points along the curve:

// Enable the evaluator
glEnable(GL_MAP1_VERTEX_3);

The function glEvalCoord1f takes a single argument: a parametric value along the curve. This function then evaluates the curve at this value and calls glVertex internally for that point. By looping through the domain of the curve and calling glEvalCoord to produce vertices, we can draw the curve with a simple line strip:

// Use a line strip to "connect the dots"
glBegin(GL_LINE_STRIP);
        for(i = 0; i <= 100; i++)
                {
                // Evaluate the curve at this point
                glEvalCoord1f((GLfloat) i);
                }
glEnd();

Finally, we wish to display the control points themselves:

// Draw the Control Points
DrawPoints();

// Flush drawing commands
glFlush();
}

Evaluating a Curve

OpenGL can make things even easier than this. We set up a grid with the function glMapGrid, which tells OpenGL to create an evenly spaced grid of points over the u domain (the parametric argument of the curve). Then we call glEvalMesh to “connect the dots” using the primitive specified (GL_LINE or GL_POINTS). The following two function calls:

// Use higher level functions to map to a grid, then evaluate the
// entire thing.

// Map a grid of 100 points from 0 to 100
glMapGrid1d(100,0.0,100.0);

// Evaluate the grid, using lines
glEvalMesh1(GL_LINE,0,100);

completely replace this code:

// Use a line strip to "connect-the-dots"
glBegin(GL_LINE_STRIP);
        for(i = 0; i <= 100; i++)
                {
                // Evaluate the curve at this point
                glEvalCoord1f((GLfloat) i);
                }
glEnd();

As you can see, this is more compact and efficient, but its real benefit comes when evaluating surfaces rather than curves.

A 3D Surface

Creating a 3D Bazier surface is much like the 2D version. In addition to defining points along the u domain, we must define them along the v domain as well.

Listing 17-2 is from our next example program, BEZ3D, and displays a wire mesh of a 3D Bazier surface. The first change from the preceding example is that we have defined three more sets of control points for the surface along the v domain. To keep this surface simple, the control points are the same except for the Z value. This will create a uniform surface, as if we simply extruded a 2D Bazier along the Z axis.

Listing 17-2 BEZ3D code to create a Bazier surface

// The number of control points for this curve
GLint nNumPoints = 3;

GLfloat ctrlPoints[3][3][3]= {{{  -4.0f, 0.0f, 4.0f},         // V = 0
                                    { -2.0f, 4.0f, 4.0f},
                                    {  4.0f, 0.0f, 4.0f }},

                                    {{  -4.0f, 0.0f, 0.0f},   // V = 1
                                    { -2.0f, 4.0f, 0.0f},
                                    {  4.0f, 0.0f, 0.0f }},

                                    {{ -4.0f, 0.0f, -4.0f},   // V = 2
                                    { -2.0f, 4.0f, -4.0f},
                                    {  4.0f, 0.0f, -4.0f }}};
…
…

// Called to draw scene
void RenderScene(void)
        {
        //int i;

        // Clear the window with current clearing color
        glClear(GL_COLOR_BUFFER_BIT);

        // Save the modelview matrix stack
        glMatrixMode(GL_MODELVIEW);
        glPushMatrix();

        // Rotate the mesh around to make it easier to see
        glRotatef(45.0f, 0.0f, 1.0f, 0.0f);
        glRotatef(60.0f, 1.0f, 0.0f, 0.0f);

        // Sets up the Bzier
        // This actually only needs to be called once and could go in
        // the setup function
        glMap2f(GL_MAP2_VERTEX_3,      // Type of data generated
        0.0f,                          // Lower u range
        10.0f,                         // Upper u range
        3,                             // Distance between points in the
                                          data
        3,                             // Dimension in u direction (order)
        0.0f,                          // Lower v range
        10.0f,                         // Upper v range
        9,                             // Distance between points in the
                                          data
        3,                             // Dimension in v direction (order)
        &ctrlPoints[0][0][0]);         // array of control points

        // Enable the evaluator
        glEnable(GL_MAP2_VERTEX_3);

        // Use higher level functions to map to a grid, then evaluate the
        // entire thing.

        // Map a grid of 100 points from 0 to 100
        glMapGrid2f(10,0.0f,10.0f,10,0.0f,10.0f);

        // Evaluate the grid, using lines
        glEvalMesh2(GL_LINE,0,10,0,10);

        // Draw the Control Points
        DrawPoints();

        // Restore the modelview matrix
        glPopMatrix();

        // Flush drawing commands
        glFlush();
        }


Previous Table of Contents Next