Simulating fog

A simple fog effect can be achieved by mixing the color of each fragment with a constant fog color. The amount of influence of the fog color is determined by the distance from the camera. We could use either a linear relationship between the distance and the amount of fog color, or we could use a non-linear relationship such as an exponential one.

The following figure shows four teapots rendered with a fog effect produced by mixing the fog color in a linear relationship with distance.

Simulating fog

To define this linear relationship we can use the following equation:

Simulating fog

In the preceding equation, dmin is the distance from the eye where the fog is minimal (no fog contribution), and dmax is the distance where the fog color obscures all other colors in the scene. The variable z represents the distance from the eye. The value f is the fog factor. A fog factor of zero represents 100 percent fog, and a factor of one represents no fog. Since fog typically looks thickest at large distances, the fog factor is minimal when |z| is equal to dmax, and maximal when |z| is equal to dmin.

Note

Since the fog is applied by the fragment shader, the effect will only be visible on the objects that are rendered. It will not appear on any "empty" space in the scene (the background). To help make the fog effect consistent, you should use a background color that matches the maximum fog color.

Getting ready

Start with the same vertex shader from the Using per-fragment shading for improved realism recipe. Your OpenGL program must set the values for all uniform variables defined in that vertex shader as well as the fragment shader shown in the following section.

How to do it...

To create a shader that produces a fog-like effect, use the following code for the fragment shader:

in vec3 Position;
in vec3 Normal;

struc tLightInfo {
  vec4 position;
  vec3 intensity;
};
uniform LightInfo Light;

struct FogInfo {
  float maxDist;
  float minDist;
  vec3 color;
};
uniform FogInfo Fog;

uniform vec3 Kd;            // Diffuse reflectivity
uniform vec3 Ka;            // Ambient reflectivity
uniform vec3 Ks;            // Specular reflectivity
uniform float Shininess;    // Specular shininess factor

layout( location = 0 ) out vec4 FragColor;

vec3 ads( )
{
   // … The ADS shading algorithm 
}

void main() {
  float dist = abs( Position.z );
  float fogFactor = (Fog.maxDist - dist) / 
                      (Fog.maxDist - Fog.minDist);
  fogFactor = clamp( fogFactor, 0.0, 1.0 );
  vec3 shadeColor = ads();
  vec3 color = mix( Fog.color, shadeColor, fogFactor );

  FragColor = vec4(color, 1.0);
}

How it works...

In this shader, the ads function is exactly the same as the one used in the recipe Using the halfway vector for improved performance. The part of this shader that deals with the fog effect lies within the main function.

The uniform variable Fog contains the parameters that define the extent and color of the fog. The minDist field is the distance from the eye to the fog's starting point, and maxDist is the distance to the point where the fog is maximal. The color field is the color of the fog.

The dist variable is used to store the distance from the surface point to the eye position. The z coordinate of the position is used as an estimate of the actual distance. The fogFactor variable is computed using the preceding equation. Since dist may not be between minDist and maxDist, we clamp the value of fogFactor to be between zero and one.

We then call the ads function to evaluate the basic ADS shading model. The result of this is stored in the shadeColor variable.

Finally, we mix shadeColor and Fog.color together based on the value of fogFactor, and the result is used as the fragment color.

There's more...

In this recipe, we used a linear relationship between the amount of fog color and the distance from the eye. Another choice would be to use an exponential relationship. For example, the following equation could be used:

There's more...

In the above equation, d represents the density of the fog. Larger values would create "thicker" fog. We could also square the exponent to create a slightly different relationship (a faster increase in the fog with distance).

There's more...

Computing distance from the eye

In the above code, we used the absolute value of the z coordinate as the distance from the camera. This may cause the fog to look a bit unrealistic in certain situations. To compute a more precise distance, we could replace the line:

float dist = abs( Position.z );

with the following:

float dist = length( Position.xyz );

Of course, the latter version requires a square root, and therefore would be a bit slower in practice.

See also

  • The Using per-fragment shading for improved realism recipe
  • The Implementing per-vertex ambient, diffuse, and specular (ADS) shading recipe in Chapter 2, The Basics of GLSL Shaders
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.149.254.35