7
votes

I'm trying to implement a ground fog shader for my terrain rendering engine. The technique is described in this article: http://www.iquilezles.org/www/articles/fog/fog.htm

The idea is to consider the ray going from the camera to the fragment and integrate the fog density function along this ray.

Here's my shader code:

#version 330 core
in vec2 UV;
in vec3 posw;

out vec3 color;

uniform sampler2D tex;

uniform vec3 ambientLightColor;
uniform vec3 camPos;

const vec3 FogBaseColor = vec3(1., 1., 1.);

void main()
{
    vec3 light = ambientLightColor;
    vec TexBaseColor = texture(tex,UV).rgb;

    //***************************FOG********************************************
    vec3 camFrag = posw - camPos;
    float distance = length(camFrag);
    float a = 0.02;
    float b = 0.01;

    float fogAmount = a * exp(-camPos.z*b) * ( 1.0-exp( -distance*camFrag.z*b ) ) / (b*camFrag.z);
    color = mix( light*TexBaseColor, light*FogBaseColor, fogAmount );
}

The first thing is that I don't understand how to choose a and b and what are their physical role in the fog density function.

Then, the result is not what I expect… I have a ground fog but the transition of fogAmount from 0 to 1 is always centered at the camera altitude. I've tried a lot of different a and b but when I don't have a transition at camera altitude, I either have a full fogged or not fogged at all terrain.

I checked the data I use and everything's correct:

  • camPos.z is the altitude of my camera
  • camFrag.z is the vertical component of the vector going from the camera to the fragment

I can't get to understand what part of the equation cause this.

Any idea about this ?

EDIT : Here's the effect I'm looking for : image1 image2

2

2 Answers

6
votes

This is a pretty standard application of atmospheric scattering.

It is discussed under the umbrella of volumetric lighting usually, which involves transmittance of light through different media (e.g. smoke, air, water). In cutting-edge shader-based graphics, this can be achieved in real-time using ray-marching or if there is only one uniform participating medium (as it is in this case -- the fog only applies to air), simplified to integration over some distance.

Ordinarily you would ray-march through participating media in order to determine the properties of light transfer, but this application is simplified to assume a medium that has well-defined distribution characteristics and that is where the coefficients you are confused about come from. The density of fog varies exponentially with distance, and this is what b is controlling, likewise it also varies with altitude (not shown in the equation directly below).

   
(source: iquilezles.org)

What this article introduces to the discussion, however, are poorly named coefficients a and b. These control in-scattering and extinction. The author repeatedly refers to the extinction coefficient as extintion, which really makes no sense to me - hopefully this is just because English was not the author's native language. Extinction can be thought of as how quickly light is absorbed, and it describes the opacity of a medium. If you want a more theoretical basis for all of this, have a look at the following paper.

With this in mind, take another look at the code from your article:

vec3 applyFog( in vec3  rgb,      // original color of the pixel
               in float distance, // camera to point distance
               in vec3  rayOri,   // camera position
               in vec3  rayDir )  // camera to point vector
{
    float fogAmount = c*exp(-rayOri.y*b)*(1.0-exp(-distance*rayDir.y*b))/rayDir.y;
    vec3  fogColor  = vec3(0.5,0.6,0.7);
    return mix( rgb, fogColor, fogAmount );
}

You can see that c in this code actually a from the original equation.

More importantly, there is an additional expression here:

   LaTeX Equation

This additional expression controls the density with respect to altitude. Judging by your implementation of the shader, you have not correctly implemented the second expression. camFrag.z is very likely not altitude, but rather depth. Furthermore, I do not understand why you are multiplying it by the b coefficient.

5
votes

I found a method that gives the result I was looking for.

The method is described in this article of Eric Lengyel : [link]http://www.terathon.com/lengyel/Lengyel-UnifiedFog.pdf

It explains how to create a fog layer with density and altitude parameters. You can fly through it, it progressively blends all the geometry above the fog.