15. OpenGL Fog Types (Version 2.0)

Exploring Different Types of OpenGL Fog

In the last tutorial, we introduced the basics of fog in OpenGL, focusing on how to set up fog with a specific mode and density. Now it’s time to expand on that by exploring the different types of fog OpenGL supports.

Fog is a powerful tool for adding atmosphere to your scenes, but the way it looks depends heavily on the type of fog you choose. OpenGL provides three options:

GL_EXP: Exponential fog, where the density increases exponentially as the distance increases.
GL_EXP2: Exponential squared fog, which increases more rapidly than GL_EXP and often produces a softer, more realistic effect.
GL_LINEAR: Linear fog, where the density increases linearly between specified start and end distances.

Choosing the right type of fog for your scene often comes down to trial and error, but as you get familiar with these modes, you’ll start to anticipate how each will look in your application.

Review: GL_EXP2

In the last tutorial, we used GL_EXP2. It’s my personal favorite because it creates smooth, natural-looking fog that blends beautifully with most scenes. Here’s the code we used to set it up:

glFogi(GL_FOG_MODE, GL_EXP2); // Exponential squared fog

If you liked how GL_EXP2 looked, great! But let’s dive into the other options to see what they bring to the table.

Other Fog Modes

GL_EXP:
This mode uses a basic exponential formula for fog density, which results in a lighter effect compared to GL_EXP2. It’s great for scenes where you want fog to increase gradually without overwhelming the visuals.

glFogi(GL_FOG_MODE, GL_EXP); // Exponential fog

GL_LINEAR:
Unlike the exponential modes, GL_LINEAR fog is predictable and straightforward. You define a start distance and an end distance, and the fog density increases linearly between these two points. This mode is especially useful for creating a clear boundary where objects fade into fog.

glFogi(GL_FOG_MODE, GL_LINEAR); // Linear fog
glFogf(GL_FOG_START, 1.0); // Fog starts 1 unit into the screen
glFogf(GL_FOG_END, 10.0);  // Fog ends 10 units into the screen

The start and end distances give you precise control over how the fog behaves, making this mode a good choice for scenes with specific depth requirements.

Fog Rendering Quality

Another important aspect of fog in OpenGL is rendering quality, controlled by the `glHint` function. OpenGL provides three quality settings:

GL_NICEST: Maximizes visual quality but may reduce performance.
GL_FASTEST: Prioritizes performance, sacrificing visual fidelity.
GL_DONT_CARE: Leaves the decision to the graphics driver, which may choose either quality or performance based on hardware capabilities.

Here’s how you set it:

glHint(GL_FOG_HINT, GL_NICEST); // Best quality

For this tutorial, we’ll stick with `GL_NICEST` to make the fog look as smooth and polished as possible. If performance is a concern, you can experiment with `GL_FASTEST`.

Switching Fog Modes Dynamically

To help you experiment with these fog modes, I’ve added keyboard controls to switch between them:

– Press A to enable GL_EXP.
– Press S to enable GL_EXP2.
– Press D to enable GL_LINEAR.

Here’s the relevant keyboard handling code:

void keyboard(unsigned char key, int x, int y) {
    if (key == 'a') {
        glFogi(GL_FOG_MODE, GL_EXP); // Switch to GL_EXP
    }
    if (key == 's') {
        glFogi(GL_FOG_MODE, GL_EXP2); // Switch to GL_EXP2
    }
    if (key == 'd') {
        glFogi(GL_FOG_MODE, GL_LINEAR); // Switch to GL_LINEAR
    }
}

This makes it easy to test how each fog type looks in your scene.

The Full Code

Below is the complete code for this tutorial. It includes the fog setup, rendering quality settings, and keyboard controls for switching modes.

#include <GL/gl.h>
#include <GL/glut.h>

GLfloat angle = 0.0;

GLfloat density = 0.3; // Fog density
GLfloat fogColor[4] = {0.5, 0.5, 0.5, 1.0}; // Fog color: grey

// Draw a rotating cube
void cube(void) {
    glRotatef(angle, 1.0, 0.0, 0.0); // Rotate on X-axis
    glRotatef(angle, 0.0, 1.0, 0.0); // Rotate on Y-axis
    glRotatef(angle, 0.0, 0.0, 1.0); // Rotate on Z-axis
    glColor3f(1.0, 0.0, 0.0); // Cube color: red
    glutSolidCube(2);
}

// Initialize fog and OpenGL settings
void init(void) {
    glEnable(GL_DEPTH_TEST); // Enable depth testing
    glEnable(GL_FOG); // Enable fog
    glFogi(GL_FOG_MODE, GL_LINEAR); // Default fog mode: Linear
    glFogfv(GL_FOG_COLOR, fogColor); // Set fog color
    glFogf(GL_FOG_DENSITY, density); // Set fog density
    glFogf(GL_FOG_START, 1.0); // Fog starts 1 unit in
    glFogf(GL_FOG_END, 10.0); // Fog ends 10 units in
    glHint(GL_FOG_HINT, GL_NICEST); // Optimize fog appearance
}

// Render the scene
void display(void) {
    glClearColor(0.0, 0.0, 0.0, 1.0); // Clear screen to black
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();
    gluLookAt(0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); // Camera setup
    cube();
    glutSwapBuffers();
    angle++; // Increment rotation angle
}

// Handle window resizing
void reshape(int w, int h) {
    glViewport(0, 0, (GLsizei)w, (GLsizei)h); // Set viewport
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(60, (GLfloat)w / (GLfloat)h, 1.0, 100.0); // Perspective projection
    glMatrixMode(GL_MODELVIEW);
}

// Keyboard controls for fog modes
void keyboard(unsigned char key, int x, int y) {
    if (key == 'a') {
        glFogi(GL_FOG_MODE, GL_EXP); // Switch to GL_EXP
    }
    if (key == 's') {
        glFogi(GL_FOG_MODE, GL_EXP2); // Switch to GL_EXP2
    }
    if (key == 'd') {
        glFogi(GL_FOG_MODE, GL_LINEAR); // Switch to GL_LINEAR
    }
}

// Main function
int main(int argc, char **argv) {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
    glutInitWindowSize(500, 500); // Window size
    glutInitWindowPosition(100, 100); // Window position
    glutCreateWindow("OpenGL Fog Modes Example"); // Window title
    init(); // Initialize fog and settings
    glutDisplayFunc(display); // Render function
    glutIdleFunc(display); // Animation
    glutReshapeFunc(reshape); // Handle window resizing
    glutKeyboardFunc(keyboard); // Keyboard controls
    glutMainLoop(); // Enter the event loop
    return 0;
}

If you have any questions, feel free to email me at swiftless@gmail.com. Happy coding!

  • March 25, 2010
  • 4