Open GL Super Bible

Previous Table of Contents Next


Perspective Projections

A perspective projection performs perspective division to shorten and shrink objects that are farther away from the viewer. The width of the back of the viewing volume does not have the same measurements as the front of the viewing volume. Thus an object of the same logical dimensions will appear larger at the front of the viewing volume than if it were drawn at the back of the viewing volume.

The picture in our next example is of a geometric shape called a frustum. A frustum is a section of a pyramid viewed from the narrow end to the broad end. Figure 7-21 shows the frustum, with the observer in place.


Figure 7-21  A perspective projection defined by a frustum

You can define a frustum with the function glFrustum. Its parameters are the coordinates and distances between the front and back clipping planes. However, glFrustum is not very intuitive about setting up your projection to get the desired effects. The utility function gluPerspective is easier to use and somewhat more intuitive:

void gluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear,
 GLdouble zFar);

Parameters for the gluPerspective function are a field-of-view angle in the vertical direction; the aspect ratio of the height to width; and the distances to the near and far clipping planes. See Figure 7-22. The aspect ratio is then found by dividing the width (w) by the height (h) of the front clipping plane.


Figure 7-22  The frustum as defined by gluPerspective

Listing 7-2 shows how we change our orthographic projection from the previous examples to use a perspective projection. Foreshortening adds realism to our earlier orthographic projections of the square tube, as shown in Figures 7-23, 7-24, and 7-25. The only substantial change we made for our typical projection code in Listing 7-2 is the added call to gluPerspective.


Figure 7-23  The square tube with a perspective projection


Figure 7-24  Side view with foreshortening


Figure 7-25  Looking down the barrel of the tube with perspective added

Listing 7-2 Setting up the perspective projection for the PERSPECT example program

// Change viewing volume and viewport.  Called when window is resized
void ChangeSize(GLsizei w, GLsizei h)
        {
        GLfloat fAspect;

        // Prevent a divide by zero
        if(h == 0)
                h = 1;

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

        fAspect = (GLfloat)w/(GLfloat)h;

        // Reset coordinate system
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();

        // Produce the perspective projection
        gluPerspective(60.0f, fAspect, 1.0, 400.0);

        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        }

A Far-Out Example

For a complete example showing Modelview manipulation and perspective projections, we have modeled the Sun and the Earth/Moon system in revolution. We have enabled some lighting and shading for drama, so you can more easily see the effects of our operations. Youíll be learning about shading and lighting in the next two chapters.

In our model, we have the Earth moving around the Sun, and the Moon revolving around the Earth. A light source is placed behind the observer to illuminate the Sun sphere. The light is then moved to the center of the Sun in order to light the Earth and Moon from the direction of the Sun, thus producing phases. This is a dramatic example of how easy it is to produce realistic effects with OpenGL.

Listing 7-3 shows the code that sets up our projection, and the rendering code that keeps the system in motion. A timer elsewhere in the program invalidates the window four times a second to keep the Render function in action. Notice in Figures 7-26 and 7-27 that when the Earth appears larger, itís on the near side of the Sun; on the far side, it appears smaller.


Figure 7-26  The Sun/Earth/Moon system with the Earth on the near side


Figure 7-27  The Sun/Earth/Moon system with the Earth on the far side

Listing 7-3 Code that produces the Sun/Earth/Moon System

// Change viewing volume and viewport.  Called when window is resized
void ChangeSize(GLsizei w, GLsizei h)
        {
        GLfloat fAspect;

        // Prevent a divide by zero
        if(h == 0)
                h = 1;

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

        // Calculate aspect ratio of the window
        fAspect = (GLfloat)w/(GLfloat)h;

        // Set the perspective coordinate system
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();

        // Field of view of 45 degrees, near and far planes 1.0 and  425
        gluPerspective(45.0f, fAspect, 1.0, 425.0);

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

// Called to draw scene
void RenderScene(void)
        {
        // Earth and Moon angle of revolution
        static float fMoonRot = 0.0f;
        static float fEarthRot = 0.0f;

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

        // Save the matrix state and do the rotations
        glMatrixMode(GL_MODELVIEW);
        glPushMatrix();

        // Set light position before viewing transformation
        glLightfv(GL_LIGHT0,GL_POSITION,lightPos);

        // Translate the whole scene out and into view
        glTranslatef(0.0f, 0.0f, -300.0f);

        // Set material color, Red
        // Sun
        glRGB(255, 255, 0);
        auxSolidSphere(15.0f);

        // Move the light after we draw the sun!
        glLightfv(GL_LIGHT0,GL_POSITION,lightPos);

        // Rotate coordinate system
        glRotatef(fEarthRot, 0.0f, 1.0f, 0.0f);

        // Draw the Earth
        glRGB(0,0,255);
        glTranslatef(105.0f,0.0f,0.0f);
        auxSolidSphere(15.0f);

        // Rotate from Earth-based coordinates and draw Moon
        glRGB(200,200,200);
        glRotatef(fMoonRot,0.0f, 1.0f, 0.0f);
        glTranslatef(30.0f, 0.0f, 0.0f);
        fMoonRot+= 15.0f;
        if(fMoonRot > 360.0f)
                fMoonRot = 0.0f;

        auxSolidSphere(6.0f);

        // Restore the matrix state
        glPopMatrix();// Modelview matrix

        // Step earth orbit 5 degrees
        fEarthRot += 5.0f;
        if(fEarthRot > 360.0f)
                fEarthRot = 0.0f;

        // Flush drawing commands
        glFlush();
        }


Previous Table of Contents Next