Open GL Super Bible

Previous Table of Contents Next


Other Types of Fog

For the other fog types, you’ll probably make the fog color white or some other light color. In addition to the fog color, GL_EXP and GL_EXP2 fog types have an additional density parameter:

glFogf(GL_FOG_DENSITY, density);

The density parameter can be any number greater than 0.0, but typically you’ll keep it less than 0.1. Figure 16-4 shows how the density of fog affects how much of the fog color is used.


Figure 16-4  Fog density over distance

Fog Distance

The fog distance is the transformed Z component of all glVertex calls. This Z coordinate lies in the range 0.0 to 1.0 and is the same number that is stored in the depth buffer. The fog distance and density determine how much fog color is mixed in, as shown here:

By default, fog is applied at all depths from 0.0 to 1.0. The GL_FOG_START and GL_FOG_END parameters restrict the range of depth values used for fog calculations. This is typically used to more accurately model fog density when the immediate area in front of the viewer is not covered (for example, when flying through clouds, the breaks between clouds will not be as dense).

Revisiting the Terrain Viewing Program

Weather haze effects are the perfect addition to the terrain viewing program of Chapter 12. In Figure 16-5 you can see the fantastic improvement in image quality. This was achieved by adding the following three lines of code:

glFogf(GL_FOG_DENSITY, 0.0025);
glFogi(GL_FOG_MODE, GL_EXP);
glFogfv(GL_FOG_COLOR, fogcolor);


Figure 16-5  Weather haze using glFog

The fog color in this case was defined as a solid white RGBA color (1.0, 1.0, 1.0, 1.0). To improve the output even more at the expense of speed, we can also call

glHint(GL_FOG_HINT, GL_NICEST);

This forces fog to be evaluated at every pixel rather than every vertex. Unfortunately, for most scenes this means 100 times as many calculations must be performed!

Now here is Listing 16-4, with the updated RepaintWindow function.

Listing 16-4 FOGSCENE.C: Updated RepaintWindow function using glFog for the terrain viewing program

/*

 * 'RepaintWindow()' - Redraw the client area with our scene.

 */



void

RepaintWindow(RECT *rect)       /* I - Client area rectangle */

{

  int          i;               /* Looping var */

  int          x, y;            /* Terrain (x,y) location */

  int          last_type;       /* Previous terrain type */

  int          *type;           /* Current terrain type */

  GLfloat      *height,         /* Current terrain height */

               (*n)[3];         /* Current terrain normal */

  static GLfloat       sky_top[4][3] =

          
 


              

                              
            { /*            Sky coordinates */ { -TERRAIN_EDGE,
  TERRAIN_SIZE          *       0.8, -TERRAIN_EDGE }, { TERRAIN_EDGE,
  TERRAIN_SIZE          *           0.8, -TERRAIN_EDGE }, { TERRAIN_EDGE,
  TERRAIN_SIZE      *         0.8, TERRAIN_EDGE }, { -TERRAIN_EDGE,
               TERRAIN_SIZE         * 0.8, TERRAIN_EDGE } };
  static GLfloat       sky_bottom[4][3] =
                             
          
           
            
           
  
           
  {
    { -TERRAIN_EDGE, 0.0, -TERRAIN_EDGE },
    {  TERRAIN_EDGE, 0.0, -TERRAIN_EDGE },
    {  TERRAIN_EDGE, 0.0,  TERRAIN_EDGE },
    { -TERRAIN_EDGE, 0.0,  TERRAIN_EDGE }
  };
  static GLfloat       sunpos[4] = { 0.0, 1.0, 0.0, 0.0 };
  static GLfloat       suncolor[4] = { 64.0, 64.0, 64.0, 1.0 };
  static GLfloat       sunambient[4] = { 0.001, 0.001, 0.001, 1.0 };
  static GLfloat       fogcolor[4] = { 1.0, 1.0, 1.0, 1.0 };

 /*
  * Reset the viewport and clear the window to light blue…
  */

  glViewport(0, 0, rect->right, rect->bottom);

  glClearColor(0.5, 0.5, 1.0, 1.0);

  glEnable(GL_DEPTH_TEST);
  glEnable(GL_FOG);
  glFogf(GL_FOG_DENSITY, 0.0025);
  glFogi(GL_FOG_MODE, GL_EXP);
  glFogfv(GL_FOG_COLOR, fogcolor);

  if (Moving || Drawing)
  {
   /*
    * Don't texture while flying or drawing; it's too slow…
    * Also, draw to the back buffer for smooth animation.
    */

    glDisable(GL_TEXTURE_2D);
    glDrawBuffer(GL_BACK);
  }
  else
  {
   /*
    * Enable textures when we've stopped moving or drawing.
    * This generates a nice scene that we can print out or
    * save to a bitmap file…
    *
    * Because it takes longer, we draw to the front buffer
    * so the user can see some progress…
    */

    glEnable(GL_TEXTURE_2D);
    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
    glDrawBuffer(GL_FRONT);
  };

  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

 /*
  * Setup viewing transformations for the current position and
  * orientation…
  */

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(45.0, (float)rect->right / (float)rect->bottom,
                 0.1, 1000.0);

  glMatrixMode(GL_MODELVIEW);
  glPushMatrix();
    glRotatef(Roll, 0.0, 0.0, 1.0);
    glRotatef(Pitch, -1.0, 0.0, 0.0);
    glRotatef(Heading, 0.0, 1.0, 0.0);
    glTranslatef(-Position[0],
                 -Position[1],
                 -Position[2]);
    glScalef(TERRAIN_SCALE, TERRAIN_SCALE, TERRAIN_SCALE);

    if (!(Moving || Drawing))
    {
     /*
      * Draw the sky…
      */

      glDisable(GL_LIGHTING);
      glCallList(SkyTexture);
      glBegin(GL_QUAD_STRIP);
        for (i = 0; i < 4; i ++)
        {
          glTexCoord2f((float)i, 0.0);
          glVertex3fv(sky_bottom[i]);

          glTexCoord2f((float)i, 0.8);
          glVertex3fv(sky_top[i]);
        };

        glTexCoord2f(4.0, 0.0);
        glVertex3fv(sky_bottom[0]);

        glTexCoord2f(4.0, 0.8);
        glVertex3fv(sky_top[0]);
      glEnd();

      glBegin(GL_TRIANGLE_FAN);
        glTexCoord2f(0.5, 1.0);
        glVertex3f(0.0, TERRAIN_SIZE, 0.0);

        for (i = 0; i < 4; i ++)
        {
          glTexCoord2f((float)i, 0.8);
          glVertex3fv(sky_top[i]);
        };

        glTexCoord2f(4.0, 0.8);
        glVertex3fv(sky_top[0]);
      glEnd();
    };

   /*
    * Setup lighting…
    */

    glEnable(GL_LIGHTING);
    glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);

    glEnable(GL_LIGHT0);
    glLightfv(GL_LIGHT0, GL_POSITION, sunpos);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, suncolor);
    glLightfv(GL_LIGHT0, GL_AMBIENT, sunambient);

    if (Moving || Drawing)
      glEnable(GL_COLOR_MATERIAL);
    else
      glDisable(GL_COLOR_MATERIAL);

   /*
    * Then the terrain…
    */

    type   = TerrainType[0];
    height = TerrainHeight[0];
    n      = TerrainNormal[0];
    for (y = 0; y < (TERRAIN_SIZE - 1); y ++)
    {
      last_type = -1;

      for (x = 0; x < TERRAIN_SIZE; x ++, type ++, height ++, n ++)
      {
        if (last_type != *type)
        {
         /*
          * If the type of terrain changes, end any existing
          * strip of quads and reset color/texture parameters…
          */

          if (last_type != -1)
            glEnd();

          switch (*type)
          {
            case IDC_WATER :
                if (Moving || Drawing)
                  glColor3f(0.0, 0.0, 0.5);
                else
                  glCallList(WaterTexture);
                break;
            case IDC_GRASS :
                if (Moving || Drawing)
                  glColor3f(0.0, 0.5, 0.0);
                else
                  glCallList(GrassTexture);
                break;
            case IDC_ROCKS :
                if (Moving || Drawing)
                  glColor3f(0.25, 0.25, 0.25);
                else
                  glCallList(RocksTexture);
                break;
            case IDC_TREES :
                if (Moving || Drawing)
                  glColor3f(0.0, 0.25, 0.0);
                else
                  glCallList(TreesTexture);
                break;
            case IDC_MOUNTAINS :
                if (Moving || Drawing)
                  glColor3f(0.2, 0.1, 0.05);
                else
                  glCallList(MountainsTexture);
                break;
       };

       glBegin(GL_QUAD_STRIP);
       if (last_type != -1)
       {
        /*
         * Start from the previous location to prevent
         * holes…
         */

         glTexCoord2i(x * 2 - 2, y * 2);
         glNormal3fv(n[-1]);
         glVertex3f((GLfloat)(x - TERRAIN_EDGE - 1),
                    height[-1],
                    (GLfloat)(y - TERRAIN_EDGE));
         glTexCoord2i(x * 2 - 2, y * 2 + 2);
         glNormal3fv(n[TERRAIN_SIZE - 1]);
         glVertex3f((GLfloat)(x - TERRAIN_EDGE - 1),
                    height[TERRAIN_SIZE - 1],
                    (GLfloat)(y - TERRAIN_EDGE + 1));
       };

       last_type = *type;
     };

     glTexCoord2i(x * 2, y * 2);
     glNormal3fv(n[0]);
     glVertex3f((GLfloat)(x - TERRAIN_EDGE),
                height[0],
                (GLfloat)(y - TERRAIN_EDGE));
     glTexCoord2i(x * 2, y * 2 + 2);
     glNormal3fv(n[TERRAIN_SIZE]);
     glVertex3f((GLfloat)(x - TERRAIN_EDGE),
                height[TERRAIN_SIZE],
                (GLfloat)(y - TERRAIN_EDGE + 1));
    };

    glEnd();
   };
 glPopMatrix();

/*
 * While we fly or draw we're double-buffering.  Swap buffers
 * as necessary…
 */

 glFinish();
 if (Moving || Drawing)
   SwapBuffers(SceneDC);
}


Previous Table of Contents Next