Open GL Super Bible

Previous Table of Contents Next


Continuity

If two curves placed side by side share an endpoint (called the breakpoint), they together form a piecewise curve. The continuity of these curves at this breakpoint describes how smooth the transition is between them. The four categories of continuity are none (C0), positional (C1), tangential (C2), and curvature (C3).

As you can see in Figure 17-3, no continuity is when the two curves don’t meet at all. Positional continuity is achieved when the curves at least meet and share a common endpoint. Tangential continuity occurs when the two curves have the same tangent at the breakpoint. Finally, curvature continuity means the two curves’ tangents also have the same rate of change at the breakpoint (thus an even smoother transition).


Figure 17-3  Continuity of piecewise curves

When assembling complex surfaces or curves from many pieces, you will usually strive for C2 or C3 continuity. You’ll see later that some parameters for curve and surface generation can be chosen to produce the desired continuity.

Evaluators

OpenGL contains several functions that make it very easy to draw Bazier curves and surfaces by specifying the control points and the range for the parametric u and v parameters. Then, by calling the appropriate evaluation function (the evaluator), the points that make up the curve or surface are generated. We’ll start with a 2D example of a Bazier curve and then extend this to three dimensions to create a Bazier surface.

A 2D Curve

The best way to get started is with an example, explaining it line by line. Listing 17-1 shows some code from the example program BEZIER in this chapter’s subdirectory on the CD. This program specifies four control points for a Bazier curve and then renders the curve using an evaluator. The output from Listing 17-1 is shown in Figure 17-4.


Figure 17-4  Output from the BEZIER example program

Listing 17-1 Code from BEZIER that draws a Bazier curve with four control points

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

GLfloat ctrlPoints[4][3]= {{  -4.0f, 0.0f, 0.0f},      // Endpoint
                               { -6.0f, 4.0f, 0.0f},   // Control Point
                               {  6.0f, -4.0f, 0.0f},  // Control Point
                               {  4.0f, 0.0f, 0.0f }}; // Endpoint
…
…

// This function is used to superimpose the control points over the curve
void DrawPoints(void)
        {
        int i; // Counting variable

        // Set point size larger to make more visible
        glPointSize(5.0f);

        // Loop through all control points for this example
        glBegin(GL_POINTS);
                for(i = 0; i < nNumPoints; i++)
                glVertex2fv(ctrlPoints[i]);
        glEnd();
        }

// Change viewing volume and viewport.  Called when window is resized
void ChangeSize(GLsizei w, GLsizei h)
        {
        // Prevent a divide by zero
        if(h == 0)
                h = 1;

        // Set Viewport to window dimensions
        glViewport(0, 0, w, h);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();

        gluOrtho2D(-10.0f, 10.0f, -10.0f, 10.0f);

        // Modelview matrix reset
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        }

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

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

        // Sets up the Bzier
        // This actually only needs to be called once and could go in
        // the setup function
        glMap1f(GL_MAP1_VERTEX_3,      // Type of data generated
        0.0f,                          // Lower u range
        100.0f,                        // Upper u range
        3,                             // Distance between points in the
                                          data
        nNumPoints,                    // Number of control points
        &ctrlPoints[0][0]);            // Array of control points

        // Enable the evaluator
        glEnable(GL_MAP1_VERTEX_3);

        // 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();

        // Draw the Control Points
        DrawPoints();

        // Flush drawing commands
        glFlush();
        }

The first thing we do in Listing 17-1 is define the control points for our curve:

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

GLfloat ctrlPoints[4][3]= {{  -4.0f, 0.0f, 0.0f},      // Endpoint
                               { -6.0f, 4.0f, 0.0f},   // Control Point
                               {  6.0f, -4.0f, 0.0f},  // Control Point
                               {  4.0f, 0.0f, 0.0f }}; // Endpoint

We defined global variables for the number of control points and the array of control points. To experiment, you can change these by adding more control points, or just modifying the position of these points.

The function DrawPoints() is pretty straightforward. We call this function from our rendering code to display the control points along with the curve. This also is very useful when you are experimenting with control-point placement. Our standard ChangeSize() function establishes a 2D orthographic projection that spans from –10 to +10 in the x and y directions.

Finally, we get to the rendering code. The function RenderScene() first calls glMap1f (after clearing the screen) to create a mapping for our curve:

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

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

        // Sets up the Bzier
        // This actually only needs to be called once and could go in
        // the setup function
        glMap1f(GL_MAP1_VERTEX_3,        // Type of data generated
        0.0f,                            // Lower u range
        100.0f,                          // Upper u range
        3,                               // Distance between points in the
                                            data
        nNumPoints,                      // Number of control points
        &ctrlPoints[0][0]);              // Array of control points
        …
        …


Previous Table of Contents Next