Atmospheric perspective: how to make distant objects desaturate and lose contrast

I am trying to create an atmospheric effect where objects farther away from the camera become more desaturated with distance. Can this be done with shaders?

So basically it would be like fog, except instead of fading into a specific color like black or white the objects would always be visible but things far away would lose saturation and contrast. (perhaps to a limit, not going completely grey) The objects may have pbr materials so this wouldn’t mean just changing the saturation of color on the meshes but having some sort of post-processing effect as I understand it.

I want to do all this because this desaturation occurs in the real world and having it in game it would sell the feeling of depth and distance.

Writing shaders from scratch is beyond me. I tried using ai to produce some code with limited results. It made all textures grey, without any lighting.

Here is a playground. Right now the boxes far on the horizon are colored the same as the ones close up. I want a way to differentiate them.

As far as I can see, this cannot be done with fog. Fog in babylon causes objects to fade into a specific color. If the color matches the background color, they effectively fade into invisibility, but there’s no way to set a limit where the object doesn’t become invisible or become just a silhouette. (is there?) I always want all objects visible and have definition, but have a feeling of being distant.

This kind of works, but I don’t want the distant cubes to lose all detail completely:

If anyone has any other ideas how to create atmospheric perspective please let me know.

This would be an extra but I had hopes to makes something where specific meshes could be set to desaturate faster than others. Eg a mountain is not that far away and a player can walk to it relatively quickly but it desaturates quickly with distance to give the illusion it is much farther than it really is.

Thanks

1 Like

I had in mind to work on this exact task soon (Custom Post-Processing, based on depth) so here it is : PLAYGROUND

Basically I set 3 processing :

  • 1 : PassProcessing just to save the original render
  • 2 : Your Whatever Processing (Here, Saturation & Contrast)
  • 3 : A combine processing which takes 1 & 2, and combine based on Depth.

Also, just in case you wonder about this depth = pow(depth, powFactor); line 73 :
It’s because I’m using the depth which goes from 0 to 1 (along camera min to camera max).
A nice trick to “tweek” how you influence the depth is to elevate it to the power of something.
( pow(depth, 2) == depth²)
Since it goes from 0 to 1, limits won’t change, but curvature will

Here is going from pow == 1 to pow == 10 for example :

2 Likes

another idea would be to reuse the fog calculation in a material plugin and instead change the saturation

Material Plugins | Babylon.js Documentation (babylonjs.com)

2 Likes

@Heaust-ops I was able to modify and use yours. Thanks everyone! Some of it is still over my head but I will slowly digest it.

Here’s what I came up with. Maybe others may find this useful.

Atmospheric perspective:

Same thing attempted with fog:

Without nothing:

3 Likes