Silly exponential fog trick
- Mar 29, 2026
For my last project I worked on implementing fog post effect. As one does, I started with exponential fog, since it is simple and pretty. I have added height component to it as well. To learn how it works I recommend reading article by Inigo Quilez.
My problem was lack of control over the effect, since typical exponential fog only has a single uniform density parameter. So, I came up with a silly trick to add a “minimum distance” to it.
Let's first consider how one might compute exponential fog (for an opaque material):
float optical_depth = density * distance(camera_position, pixel_world_position);
float fog_amount = exp(-optical_depth); // transmittance
// basically alpha blending fog on top of the material
float3 final_color = g_FogColor * (1 - fog_amount) + pixel_color.rgb * fog_amount;
The code is derived from Beer-Lambert’s Law:
This formula computes amount of light that is transmitted through a medium (fog). 𝛽𝑒(𝑥) is a function that defines density of the medium for any given point. For a constant density fog, it simplifies to a simple “distance times density”.
For height fog this is more complicated. But the point is that we need to compute some integral. I will call its value optical depth. It is, in a way, length of the view ray weighted by medium’s density at each point of the ray.
The silly trick
To add minimum distance to the exponential fog, we’ll use smoothstep function to decrease fog’s density around the camera.
Translating this into HLSL we get following:
float smoothstep_antiderivative(float x, float M)
{
x = min(M, x);
// 1/x is the same as (x^-1) so we can write pow(M, N-1) instead of 1/pow(M,N)
return pow(M, 2) * pow(x,3) - 0.5 * pow(M, 3)*pow(x,4);
}
// ....
float d = distance(camera_position, pixel_world_position);
float optical_depth = smoothstep_antiderivative(d, g_FogMinDistance);
optical_depth += max(0, d-g_FogMinDistance);
In reality you can precompute a lot of this, since M is uniform. You can also precompute antiderivative for cases where d > M.
Combining with height fog
Height fog computes its own optical depth and while we could derive formulas that take our little hack into account, here’s a simple way to combine them:
float smooth_optical_depth = ComputeSmoothstep(distance);
float height_optical_depth = ComputeHeightFog(distance);
// We just want less fog near use so use smaller distance
float optical_depth = density * min(smooth_optical_depth, height_optical_depth);
float fog_amount = exp(-optical_depth); // transmittance
A (maybe) simpler way
Alternatively, you can just use smoothstep for your fog. In fact, you can replace exponent in the transmittance equation with anything you like.
For example:
float optical_depth = ComputeHeightFog(distance);
float fog_amount = smoothstep(g_FogMinDistance, g_FogMaxDistance, optical_depth);
This will work just fine but the problem is, height fog component is now affected by min and max distance. While keeping exponential fog allows you to control “force field” around the camera separately from everything else. To demonstrate. First image is exponential fog with M = 22, second uses smoothstep with the same parameter.


Thanks for reading
This algorithm is implemented in my Height Fog plugin for Unity. You can just use that if you want.