How to Calculate Fog in Computer Graphics: A Step‑by‑Step Guide
Fog is a common visual effect that adds depth, realism, and atmosphere to 3D scenes. Whether you’re working in a game engine, a rendering pipeline, or a custom graphics application, understanding how to calculate fog correctly is essential for creating convincing environments. This article walks you through the fundamentals of fog calculation, the different fog models, and practical implementation tips that will help you master this classic effect.
Introduction
Fog is more than just a visual trick; it’s a powerful tool that simulates the scattering of light by particles in the air. By blending scene colors toward a chosen fog color based on distance, you can:
- Improve depth perception – Objects farther away appear lighter and less detailed.
- Enhance realism – Mimic real‑world atmospheric conditions.
- Control performance – Reduce the need for high‑detail geometry at long ranges.
The key to great fog is accurate distance measurement and an appropriate attenuation function. Let’s explore the math behind fog and how to implement it efficiently.
1. The Core Equation
At its heart, fog is a form of exponential attenuation applied to the color of each pixel. The general formula is:
finalColor = (1 – fogFactor) * sceneColor + fogFactor * fogColor
- sceneColor – The color produced by lighting and shading.
- fogColor – The color of the fog (often light gray or a sky hue).
- fogFactor – A value between 0 and 1 that represents how much fog influences the pixel.
The challenge is to compute fogFactor from the pixel’s distance to the camera Worth knowing..
2. Distance Calculation
The distance used in fog calculations can come from several sources:
- Linear Depth – Direct Euclidean distance in world space.
- Screen‑Space Depth – Depth value from the depth buffer.
- Per‑Vertex Distance – Interpolated distance values passed to the fragment shader.
2.1 Linear Depth
float distance = length(worldPos - cameraPos);
This gives the true distance but can be expensive if done per pixel. It’s ideal for high‑fidelity rendering or offline pipelines Still holds up..
2.2 Screen‑Space Depth
Modern GPUs provide a depth buffer (gl_FragCoord.z) that is already linearized if you transform it correctly. You can sample this value directly in your fragment shader:
float depth = texture(depthMap, uv).r;
float distance = depth * farPlane; // assuming depth is normalized [0,1]
This method is fast and works well for real‑time applications It's one of those things that adds up. Practical, not theoretical..
2.3 Interpolated Distance
Pass a per‑vertex distance from the vertex shader, then interpolate it across the primitive:
// Vertex shader
vDistance = length(worldPos - cameraPos);
// Fragment shader
float distance = vDistance;
This approach balances accuracy and performance.
3. Fog Models
Different fog models produce distinct visual results. Choose the one that best matches your artistic vision and performance constraints It's one of those things that adds up..
3.1 Linear Fog
float fogFactor = clamp((fogEnd - distance) / (fogEnd - fogStart), 0.0, 1.0);
- fogStart – Distance where fog begins.
- fogEnd – Distance where fog fully covers the scene.
Linear fog is simple and fast but can look unnatural because the transition is abrupt.
3.2 Exponential Fog
float fogFactor = exp(-density * distance);
fogFactor = clamp(fogFactor, 0.0, 1.0);
- density – Controls how quickly fog accumulates.
Exponential fog produces a smooth, realistic fade and is commonly used in games.
3.3 Exponential Squared Fog
float fogFactor = exp(-pow(density * distance, 2.0));
fogFactor = clamp(fogFactor, 0.0, 1.0);
This variant creates an even steeper fall‑off, useful for dense atmospheres like mist or volcanic haze.
4. Implementing Fog in a Shader Pipeline
Below is a concise GLSL example that demonstrates a complete fog calculation in a fragment shader:
uniform vec3 fogColor;
uniform float fogStart;
uniform float fogEnd;
uniform float fogDensity;
uniform bool useExpFog; // true = exponential, false = linear
in vec3 vWorldPos; // interpolated from vertex shader
in vec3 vColor; // result of lighting
out vec4 fragColor;
void main()
{
// 1. Compute distance
float distance = length(vWorldPos - cameraPos);
// 2. 0, 1.Even so, 0);
} else {
fogFactor = clamp((fogEnd - distance) / (fogEnd - fogStart), 0. Calculate fog factor
float fogFactor;
if (useExpFog) {
fogFactor = exp(-fogDensity * distance);
fogFactor = clamp(fogFactor, 0.0, 1.
// 3. Blend colors
vec3 finalColor = mix(fogColor, vColor, fogFactor);
fragColor = vec4(finalColor, 1.0);
}
Tips for optimization:
- Pre‑compute constants on the CPU (e.g.,
1/(fogEnd - fogStart)). - Use
mix()instead of manual blending for cleaner code. - Cache depth if you’re sampling from a depth texture.
5. Real‑World Adjustments
5.1 Height‑Dependent Fog
Fog density often changes with altitude. Add a height factor:
float heightFactor = (vWorldPos.y - groundLevel) / fogHeight;
float adjustedDensity = fogDensity * heightFactor;
5.2 Color Variation
Instead of a single fog color, blend between two colors based on distance:
vec3 fogColorStart = vec3(0.7, 0.8, 1.0); // light blue
vec3 fogColorEnd = vec3(0.4, 0.5, 0.7); // darker blue
vec3 fogColor = mix(fogColorStart, fogColorEnd, distance / fogEnd);
5.3 Multiple Fog Layers
Layering fog can emulate complex atmospheres (e.So naturally, , near‑ground mist + distant haze). In real terms, g. Render each layer with its own parameters and blend the results.
6. Common Pitfalls and How to Avoid Them
| Issue | Description | Fix |
|---|---|---|
| Fog appears too thin or too thick | Incorrect density or start/end values | Adjust parameters or switch models |
| Performance drop | Per‑pixel distance calculation | Use interpolated distance or depth buffer |
| Artifacts at far planes | Depth buffer precision loss | Use a logarithmic depth buffer or increase near/far ratio |
| Fog color mismatch | Fog color not matching lighting | Match fog hue to ambient light or sky color |
7. Frequently Asked Questions
Q1: Can I use fog in 2D games?
Yes. Treat the distance as the vertical or horizontal offset from the camera or a fixed depth value. The same attenuation formulas apply.
Q2: Is fog always linear in real life?
Real fog follows an exponential decay due to light scattering. Linear fog is a stylized approximation often used for performance.
Q3: How do I synchronize fog with a moving camera?
Recompute the distance per frame for each pixel. In modern GPUs, this happens automatically when you use the camera’s view matrix in the vertex shader.
Q4: Can I animate fog density?
Absolutely. Animate the fogDensity uniform over time or tie it to environmental variables like time of day or weather It's one of those things that adds up..
Conclusion
Calculating fog is a blend of mathematics, artistry, and performance tuning. By understanding the core equation, choosing the right fog model, and implementing efficient distance calculations, you can create atmospheric scenes that captivate viewers while keeping your rendering pipeline lean. Experiment with different densities, colors, and height dependencies to discover the fog style that best fits your project. Happy rendering!
The interplay of precision and creativity defines successful fog implementation, balancing technical accuracy with artistic intent. Through iterative refinement and attention to environmental context, creators transcend mere visual effects to evoke emotion and narrative depth, solidifying their medium’s unique identity. Such mastery bridges the gap between simulation and storytelling, leaving lasting impressions that resonate long after the scene concludes Turns out it matters..