Open GL Super Bible

Previous Table of Contents Next


Listing 15-1 Depth buffer example using glDepthFunc

/*
 * "depth.c" - A test program demonstrating the use of glDepthFunc().
 *
 * Press the 'd' key to toggle between GL_LESS and GL_GREATER depth
 * tests.  Press the 'ESC' key to quit.
 */

#include <GL/glaux.h>

/*
 * These #define constants are provided for compatibility between MS
 * Windows and the rest of the world.
 *
 * CALLBACK and APIENTRY are function modifiers under MS Windows.
 */

#ifndef WIN32
#  define CALLBACK
#  define APIENTRY
#endif /* !WIN32 */

GLenum depth_function = GL_LESS;       /* Current depth function */

/*
 * 'reshape_scene()' - Change the size of the scene...
 */

void CALLBACK
reshape_scene(GLsizei width,   /* I - Width of the window in pixels */
              GLsizei height)  /* I - Height of the window in pixels */
{
 /*
  * Reset the current viewport and perspective transformation...
  */

  glViewport(0, 0, width, height);

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(22.5, (float)width / (float)height, 0.1, 1000.0);

  glMatrixMode(GL_MODELVIEW);
}

/*
 * 'draw_scene()' - Draw a scene containing a cube with a sphere in
 *                  front of it.
 */

void CALLBACK
draw_scene(void)
{
  static float red_light[4] = { 1.0, 0.0, 0.0, 1.0 };
  static float red_pos[4] = { 1.0, 1.0, 1.0, 0.0 };
  static float blue_light[4] = { 0.0, 0.0, 1.0, 1.0 };
  static float blue_pos[4] = { -1.0, -1.0, -1.0, 0.0 };

 /*
  * Enable drawing features that we need...
  */

  glEnable(GL_DEPTH_TEST);
  glEnable(GL_LIGHTING);
  glEnable(GL_LIGHT0);
  glEnable(GL_LIGHT1);

  glShadeModel(GL_SMOOTH);
  glDepthFunc(depth_function); 

 /*
  * Clear the color and depth buffers...
  */

  if (depth_function == GL_LESS)
    glClearDepth(1.0);
  else
    glClearDepth(0.0);

  glClearColor(0.0, 0.0, 0.0, 0.0);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

 /*
  * Draw the cube and sphere in different colors...
  *
  * We have positioned two lights in this scene.  The first is red and
  * located above, to the right, and behind the viewer.  The second
  * is blue and located below, to the left, and in front of the viewer.
  */

  glLightfv(GL_LIGHT0, GL_DIFFUSE, red_light);
  glLightfv(GL_LIGHT0, GL_POSITION, red_pos);

  glLightfv(GL_LIGHT1, GL_DIFFUSE, blue_light);
  glLightfv(GL_LIGHT1, GL_POSITION, blue_pos);

  glPushMatrix();
    glTranslatef(-1.0, 0.0, -20.0);
    auxSolidSphere(1.0);
  glPopMatrix();

  glPushMatrix();
    glTranslatef(1.0, 0.0, -20.0);
    glRotatef(15.0, 0.0, 1.0, 0.0);
    glRotatef(15.0, 0.0, 0.0, 1.0);
    auxSolidCube(2.0);
  glPopMatrix();

  glFlush();
}

/*
 * 'toggle_depth()' - Toggle the depth function between GL_LESS and
 *                    GL_GREATER.
 */

void CALLBACK
toggle_depth(void)
{
  if (depth_function == GL_LESS)
    depth_function = GL_GREATER;
  else
    depth_function = GL_LESS;
}

/*
 * 'main()' - Initialize the window and display the scene until the
 *            user presses the ESCape key.
 */

void
main(void)
{
  auxInitDisplayMode(AUX_RGB | AUX_SINGLE | AUX_DEPTH);
  auxInitWindow(?Depth Function?);

  auxKeyFunc(AUX_d, toggle_depth);
  auxReshapeFunc(reshape_scene);

  auxMainLoop(draw_scene);
}

/*
 * End of "depth.c".
 */

Another Application of the Depth Buffer

The depth buffer can also be used to generate a contour mapping of a scene, which shows different colors for each depth. Contour maps can be generated using the glReadPixels function and by specifying the depth component as the value of interest, as follows:

glReadPixels(x, y, width, height, GL_DEPTH_COMPONENT, type, pixels);

The returned depth values can then be scaled and assigned to color values that can be displayed as a contour image, especially in color index mode, like this:

#define WIDTH 320
#define HEIGHT 200
GLfloat   pixels[WIDTH * HEIGHT];
int i;

// draw the scene...
glEnable(GL_DEPTH_TEST);
...
// Grab the depth buffer
glReadPixels(0, 0, WIDTH, HEIGHT, GL_DEPTH_COMPONENT, GL_FLOAT,
             pixels);
// Convert depth values to color indices
for (i = 0; i < (WIDTH * HEIGHT); i ++)
  pixels[i] = pixels[i] * 255.0; // Assume 256 color palette
// Display the new pixels on the screen
glDisable(GL_DEPTH_TEST);
glDrawPixels(0, 0, WIDTH, HEIGHT, GL_COLOR_INDEX, GL_FLOAT, pixels);

In a real application, you’d probably want to provide some user control over the color palette and range of values. You can also use RGBA color values to enhance a scene, using glBlendFunc to mix the “normal” image with the “depth” image.

Cutting Away Parts of a Scene

Let’s see how to cut away parts of a scene—an engine block, for instance—to show some internal operation that would not normally be visible. Listing 15-2 is an example of using the depth buffer for this purpose.

The heart of this program is the draw_scene function, which draws a picture of a cube and sphere being cut by a moving plane. To cut away parts of the scene, we first draw the cutting plane. Instead of drawing to the color buffer, we begin by disabling drawing to the color buffer with glDrawBuffer.

glDrawBuffer(GL_NONE);

glBegin(GL_POLYGON);
  glVertex3f(-100.0, 100.0, cutting_plane);
  glVertex3f(100.0, 100.0, cutting_plane);
  glVertex3f(100.0, -100.0, cutting_plane);
  glVertex3f(-100.0, -100.0, cutting_plane);
glEnd();

glDrawBuffer(GL_BACK);

Once the cutting plane is drawn, we reenable color buffer drawing and proceed with drawing the cube and sphere. The invisible plane we drew will restrict what is drawn on the screen to polygons that lie behind it, effectively cutting away parts of the scene.


Previous Table of Contents Next