Posts
Search
Contact
Cookies
About
RSS

raylib Fog

Added 10 Jul 2019, 2:30 p.m. edited 18 Jun 2023, 5:58 p.m.

When writing the raylib example shaders_basic_lighting, it occurred to me that taking it a little further and adding fog would be fairly straight forward.


fog doesn't have to be gray!

Fog effects have a long tradition in video games, initially as a way to limit view distance without things suddenly popping into existence. However one thing with fog that shouldn't be overlooked is that it is an incredible effect to add... well... atmosphere to a game. Its such a neat effect I don't know why a lot of games don't add just a little fog, even if you can see to the horizon, as this greatly enhances how the scene looks, in effect emulating haze.

Before looking at the fog you should look at my write up of the lighting example, there is actually little difference except for a few additional variables.

int fogC = GetShaderLocation(shader, "fogColor");
SetShaderValue(shader, fogC, (float[4]){0.6, 0.2, 0.2, 1.0}, UNIFORM_VEC4);

int fogD = GetShaderLocation(shader, "FogDensity");
float fogDensity = 0.15f;
SetShaderValue(shader, fogD, &fogDensity, UNIFORM_FLOAT);

We only need to set the fog colour once, but we're allowing the user to change the fog density as the program runs, this has the effect of altering how far we can see, as the fog becomes denser we see less...

When updating we just need to change two important variables

SetShaderValue(shader, fogD, &fogDensity, UNIFORM_FLOAT);

// update the light shader with the camera view position
SetShaderValue(shader, shader.locs[LOC_VECTOR_VIEW], &camera.position.x, UNIFORM_VEC3); 

With these values updated we're ready to render

ClearBackground((Color){0.6*255,0.2*255,0.2*255,255});

Don't forget that raylib uses a range 0 - 255 for colour components, where as the shader uses a range of 0.0 - 1.0. This colour value for clearing, should match the fog colour setting.

The actual shader uses some very simple calculations to modify the fragment colour of the model. Despite its simplicity it seem to work rather well.

finalColor =  (texelColor * ((colDiffuse+vec4(specular,1)) * vec4(lightDot, 1.0)));
finalColor += texelColor * ambient; //(ambient/10.0);
// gamma
finalColor = pow(finalColor, vec4(1.0/2.2));

float dist = length(viewPos - fragPosition) ;
float fogFactor = 1.0 / exp( (dist * FogDensity) * (dist * FogDensity));

fogFactor = clamp( fogFactor, 0.0, 1.0 );
finalColor = mix(fogColor, finalColor, fogFactor);

Unless you have a specific need to add some kind of effect, the fog shader can be left as is, just like the lighting example, its actually quite easy to drop the new shader into your existing project without too much complication, just make sure you "attach" the shader to the models that you want effected by the fog.

model.materials[0].shader = shader;

You can get the full source for this example here

Enjoy!