Create a fog shader

I decided to improve my last OpenGL scene by adding fog to create an odd mystique effect. Now I’m sure that all of you have seen fog in your lives and I don’t have to explain what it is. If you want to read more about the fog phenomenon and its characteristics you can read more on Wikipedia or other sources. In Computer Graphics you can create a fog effect in a few ways. In this tutorial I will focus on the standard way to create fog in shaders. At the end of the article we can improve our fog effect just by adding scattering and create a cool ground fog. I saw lots of tutorials about fog on the Internet and lots of them are deprecated so I hope I can bring a bit of fresh air.

My scene with fog

Because this article is long I will structure it like this:

Clear color

Standard fog equations and differences between them

Getting the distance: Z-Depth vs Length

Fog in vertex shader vs Fog in fragment shader

Beautiful fog with atmospheric effects

Further reading

Clear color

You have to choose wisely the clear color of your OpenGL/DirectX scene because this can have a major impact over visual aspects. Usually for a static scene you can choose the clear color to have the same RGB like your fog color. Yes, fog color can have any RGB and of course it’s not required to be always gray(0.5,0.5,0.5). For example in World of Warcraft uses colored fog, based on the zone you are in (Light Blue Fog, Purple Fog, Orange Fog).

Standard fog equations and differences between them

There are three standard fog equations that we can use in our scene to create a fog effect. They are called “standard” because they were here to help us with fog back when the Fixed Pipeline was used.

Linear fog is the simplest fog equation; it’s a linear interpolation function which blends the fog color with original color based on the distance you view the objects from your scene. We need two parameters to create this function. The first one is the fogStart parameter or minimum distance where we need to provide information where the fog should start to blend, and of course the scond one is the fogEnd or the maximum distance where the fog color will block (cover) the original color from the viewer. So the function should look like this:

linear fog equation

We can call ƒ the fogFactor and this value should give a value between 0.0 and 1.0 to get a correct mix between original color and fog color, so we need to clamp it between 0.0 and 1.0.

Linear fog result

I created another camera with the view from above the scene just to see how the fog behaves:

Linear fog; fog factor function

Exponential fog is a simplified model from real world phenomenon so it has a physical background behind. Light intensity is reduced over the distance due to absorbtion and scattering from air particles. So, for each particle the light ray will reach, its intensity will be absorbed by a small attenuation factor. We can think of these particles as very small steps. For each step the light intensity is absorbed by this attenuation factor. This leads to an exponential behavior, which tell us that light intensity decreases exponentially with the distance from the object. Why is this model simplified? Because of that attenuation factor we choose to be constant. In the real world this factor can vary from particle to particle; check the Beer-Lambert law in atmosphere to see how many terms can influence this attenuation factor. For our model this attenuation factor is called fog density and as I said earlier it is uniform. The result can be seen in the first image from this article.

Exponential Fog Formula

Exponential Fog; fog factor function

We can clearly see that exponential fog has a fast decrease in density than the linear fog. I usually go with very small numbers for fog density, here I used 0.05.

Exponential squared fog is the last of the standard three fog equations. The only difference from the exponential fog is that the distance and the fog desnity are squared. Beside the incident light, this equation takes into consideration the reflected light which will create a clearer visibility around the view camera where the distance is very small followed by a fast density increase as we get further. The fog density you choose should be very small.

Exponential Squared Fog Formula

Exponential Square Fog; fog factor function

You can see in the upper left corner of those images that I included a function used to get the final color. There is a mix function in GLSL which blends the original color with fog color in the same way that function works. Remember that it is very important how you pass those arguments to this function. This mix function is the same for all equation.

Getting the distance: Z-Depth vs Length

There are different ways to get the distance(d) needed for the equations above. There is the plane-based technique where the z-depth is used to get the distance. This can cause visual anomalies when you rotate the camera. Imagine on object that is not affected by the fog in your view space, when you rotate the view camera the z changes thus the object can be affected by the fog. We can use this tehnique in certain situations when the view camera doesn’t move that much or is static. Also this is very cheap to compute so it can be used on mobile.

To avoid this unwanted effect with objects that leaves and enters the fog area we can use the range-based technique where we compute the actual (exact) distance between the vertex and and view camera. It is more expensive because it needs to compute a square root but on modern hardware I would not worry that much.

To see the differences we can use 1.0 – fogFactor value for RGB final color just to see how depth behaves. This is very similar to depth buffer. Black is near and white is far this is the reason why we subtract the fogFactor from 1.0.

Fog in vertex shader vs Fog in fragment shader

Now that you know the standard equations for fog and you also know how to get the distance but you may be wondering where to compute it in vertex shader or in fragment shader? Well the answer depends on how you want your fog to be interpolated. You can compute the distance and fogFactor in vertex shader, and pass it to fragment shader and the color is going to be interpolated over the primitive (in my case triangles). This is cheaper to compute and if you have high poly models, you are not able to see huge differences. However if you have a flat terrain like mine with only four vertices at a considerable distance from one each other you will get bad visual results with range-based fog. To compute your fog in the fragment shader you have to pass the viewSpace vector from the vertex shader and compute the distance and fog equations in your fragment shader. Let’s look at some differences for linear fog with range-based distance:

Range-based linear fog in vertex shader

Range-based linear fog in fragment shader

Now let’s look at the code for vertex and fragment shaders. To show all these images I wrote a complex shader with lots of if statements. Here I will show how to create the fragment fog to simplfy the code. However the full shader is in the source code below.

Beautiful fog with atmospheric effects

We saw that exponential fog is more physical based and we used a simplified model from our real world. Here we can go further and add more complexity to the fog model. The interaction between light and medium is basically described with three main processes:

Emission

Absorption

Scattering

We can consider a volume (cloud) of particles that emit, absorb and scatter the light rays. Emission is contributing with energy from luminous particles. When light is absorbed the energy is converted into another energy, like heat loosing intensity. Scattering redirects the original direction of the light in other directions when the light hits a particle, loosing intensity. This is called out-scattering. If we combine the absorption effects with out-scattering effects we get the extinction (attenuation) effect. But the bounced light will hit another particle which will increase that intensity and maybe re-emit light again. This is called in-scattering. Here is an image with all light interaction effects discussed above:

There are more complex theories that you can read about light and transmittance with lots and lots of math and physics. Here we will again simplify this model to write a simple fog shader with just a cool effect. Remember that in “standard” fog equations we had only a single fog factor used to get our final color. We will use the exponential fog formula but this time lets use two fog factors with different density (b1 and b2) values. One fog factor is extinction and the other one is in-scattering.

We can go further and express b1 and b2 based on height and create that ground looking fog. This way fog density changes with altitude. However because I have only a flat grond with some trees my scene is not the best to show off. There are a couple of ways to add height to your fog, the easiest way is subtract the current vertex height (viewSpace.y) from view camera height and multiply by a small factor .

I have been working as a software engineer in computer graphics for almost 5 years. In the free time I love playing guitar, playing video games, hiking and studying computer graphics techniques.Follow me on : Google + , Twitter, Facebook