[Solved] Height/Distance based fog (again)

Ok I didn’t like to necropost my own post but I was revisiting this again so It seemed better to start a new topic maybe? Not sure… Anyway…

I don’t really want to do volumetric fog/lighting in my landscape because it’s rather large and I’m not sure I can get a decent frame rate unless I can do a very simple and/or crude version of it.

Really the aim is not to just use exponential fog because it looks nice enough but I’d like more fog to accumulate in the lower areas like this guy’s screenshots

I’m doing this as a post process. So I already know the color of the pixel i’m referring to and I also can reconstruct it’s world position from the depth buffer.

So… the pixel shader calls this function to output the end color for the scene

float3 applyFog(float3 rgb,  // original color of the pixel
	float distance, // camera to point distance
	float3 rayOri, // camera position
	float3 rayDir // camera direction to the pixel (normalized from worldpos - camera pos) 
	) 
{
	float fogAmount = fogScattering * exp(-rayOri.y * fogDensity) * (1.0 - exp(-distance * rayDir.y * fogDensity)) / rayDir.y;
	
	return lerp(rgb, fogColor, fogAmount);
}

It does something at least. Makes the lower parts of the terrain bright white and the distant mountains kind of foggy. I’ve played with the scattering and density (I might have those the wrong way round actually but they were b and c in the article) and I just can’t make it look sensible.

Back to exponential fog for now I guess. It seems like it would be simple enough to combine exponential height fog with exponential distance fog.

So hard to find much on this stuff since google is all Unity/Unreal.

Anyway thanks in advance.

That equation looks suspect to me.

Was it from opengl?

The first thing that jumps out at me is in the first term you are using ray origin, the camera position

Shouldn’t that be the height of the target pixel

(rayOri + (rayDir * distance)).y

I don’t like the rayDir.y term in the second term either. Say the target point is level with the camera, then rayDir.y is zero and you have a division by zero

I have found this before with stuff from Inigo Quilez , the idea is perfect but the published code doesn’t work

Yes it was originally an OpenGL shader (the last one in the article) so it could be me screwing up converting it:

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 );
}

I’m just trying to make the lower areas get more fog really like his example picture:

lowyfog

I mean ideally this kind of thing but I don’t understand how to do ray marching.

Well the coordinate system is different in OpenGL, z up in opengl which makes the shader you just posted suspect

Also it would make more sense if rayOri was the pixels world coordinate rather than the camera position

Yes I realised that but in the article he’s using Y as up.

I got it to work in the end, I wasn’t actually doing much wrong, I had to fiddle with density and scattering constants.

1 Like