Fog

You may need to read the articles about 3D and varyings before this one.


Fog can be emulated by mixing the output color with a fog color that matches the background color.

outColor = mix(u_color, u_fogColor, u_fogAmount);

Distance fog is used to obscure the far end of the camera's view frustum so that the scene doesn't appear to end abruptly. The depth of each fragment can be determined by first multiplying its position by a world view matrix.

v_worldViewPos = u_view * u_world * a_position;

Since this position is relative to the camera, the magnitude of the vector is equivalent to the fragment's distance from the camera.

float fogDepth = length(v_worldViewPos);

On a low-powered GPU, gl_FragCoord.z can be used instead to get a cheap approximation of the fragment's distance from the camera.

The depth fog can easily be given a starting and ending distance using the built-in smoothstep function.

float fogAmount = smoothstep(u_fogNear, u_fogFar, fogDepth);

To make the fog look more realistic, it can instead be given an exponential thickness.

float fogDensity2 = u_fogDensity * u_fogDensity;
float fogDepth2 = fogDepth * fogDepth;
float fogAmount = 1.0 - exp2(-fogDensity2 * fogDepth2 * 1.442695);
fogAmount = clamp(fogAmount, 0.0, 1.0);

The constant 1.442695 comes from the formula for converting between the binary logarithm and the natural logarithm.

log2(n)1.442695ln(n)\log_2(n) \approx 1.442695\ln(n)

The next article is about transparency.