volumetric fog

I want to code volumentric fog. I am not sure if it’s correct name for this effect - what I need is fog only on bottom of my mountains, so : draw fog only if y<maxy. How ?

PS. I have seen examples in net, but never any description.

If you draw fog only if y<maxy, it’s a bad approximation, but it works pretty good if your camera is always higher that ymax.

If you have to dive into fog, that effect looks ugly and you’d rather use some more advanced techniques.

In general, volumetric fog is rendered using EXT_fog_coord extension (which is no longer an extension since OpenGL1.4). There is an example at gameturorials.com which implements your technique. Play a bit with it and you quickly see the advantages if you’re higher than fog and disadvantages if you’re inside the fog.

hello vincoof, you wrote:

“In general, volumetric fog is rendered using EXT_fog_coord extension”

but OpenGL implementation I use (Linux DRI, Voodoo3) doesn’t know this extension

“There is an example at gameturorials.com which implements your technique.”

yes, I have seen it, but it’s only code for Visual C, what I need is text description or portable code to compile on Linux

If the EXT_fog_coord extension is not available, you can do it either with vertex colouring or at worse in two passes.

Can you list the supported extensions for your graphics card/driver combo ?
Call glGetString(GL_EXTENSIONS) in a sample OpenGL application and print that string. Or simply run ‘glinfo’ that may be already installed on your hard disk in /usr/bin or /bin.

hello vincoof, you wrote:

“If the EXT_fog_coord extension is not available, you can do it either with vertex colouring or at worse in two passes.”

But I don’t know how to start. Can you point me to any tutorial which describes that fog effect? I don’t want code, but text description.

“Can you list the supported extensions for your graphics card/driver combo ?”

Yes. I use latest DRI drivers. glGetString(GL_EXTENSIONS) gives me same like glxinfo:

GL_ARB_multitexture GL_ARB_transpose_matrix GL_EXT_abgr GL_EXT_bgra GL_EXT_clip_volume_hint GL_EXT_compiled_vertex_array GL_EXT_packed_pixels GL_EXT_paletted_texture GL_EXT_polygon_offset GL_EXT_rescale_normal GL_EXT_texture3D GL_EXT_texture_env_add GL_EXT_texture_object GL_EXT_texture_lod_bias GL_EXT_vertex_array GL_HP_occlusion_test GL_IBM_rasterpos_clip GL_MESA_window_pos GL_NV_texgen_reflection

I think you have to do it in 2 passes. You can do it in one pass if your fog is black or white (but not grey).

In two passes, for each object :
1- render your object “normally” : lighting enabled (if needed), texturing enabled (if needed), etc.
2- render you object with vertex colouring : disable lighting, disable texturing, and set glColor4f(fog_red, fog_green, fog_blue, fog_density) for each vertex where (fog_red, fog_green, fog_blue) is the constant fog color, and where fog_density is the fog density of the vertex.

Example : draw a textured quad (nota: I assume that the texture is already initialized).

code for quad WITHOUT fog :

glEnable(GL_DEPTH_TEST); // Use Z-buffer
glDepthFunc(GL_LEQUAL);
glDisable(GL_LIGHTING); // No lighting
glEnable(GL_TEXTURE_2D); // Use 2D texture
glBindTexture(GL_TEXTURE_2D, my_texture_id);
glBegin(GL_QUADS);
glColor3f(1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex2f(-1.0f, -1.0f); // lower-left vertex
glTexCoord2f(0.0f, 1.0f); glVertex2f(-1.0f, +1.0f); // upper-left vertex
glTexCoord2f(1.0f, 1.0f); glVertex2f(+1.0f, +1.0f); // upper-right vertex
glTexCoord2f(1.0f, 0.0f); glVertex2f(+1.0f, -1.0f); // lower-righft vertex
glEnd();

if you want to add fog, do this as second pass :

GLfloat fog_color[4] = {0.5f, 0.5f, 0.5f, 0.0f}; // grey fog
glEnable(GL_DEPTH_TEST); // Use Z-buffer
glDepthFunc(GL_EQUAL); // Multipass : draw exactly where precedent pass drew
glDisable(GL_LIGHTING); // Still no lighting
glDisable(GL_TEXTURE_2D); // Don’t use 2D texture anymore
glEnable(GL_BLEND); // Multipass : blend with precedent pass
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Classic blending
glBegin(GL_QUADS);
fog_color[3] = 0.0f; // set no fog for the lower-left vertex
glColor4fv(fog_color);
glVertex2f(-1.0f, -1.0f);
fog_color[3] = 0.5f; // set 50% fog for the upper-left vertex
glColor4fv(fog_color);
glVertex2f(-1.0f, +1.0f);
fog_color[3] = 1.0f; // set 100% fog for the upper-right vertex
glColor4fv(fog_color);
glVertex2f(+1.0f, +1.0f);
fog_color[3] = 1.0f; // set 50% fog for the lower-right vertex
glColor4fv(fog_color);
glVertex2f(+1.0f, -1.0f);
glEnd();
glDisable(GL_BLEND); // End multipass : don’t blend anymore

It is called “vertex colouring” because you call glColor for each vertex.

You can do something better with 1D-textures associated to automatic texture coordinate generation, but it’s more complex so I won’t explain that.
But I recommend you to learn it if your application has a critical performance hit.

“2- render you object with vertex colouring : disable lighting, disable texturing, and set glColor4f(fog_red, fog_green, fog_blue, fog_density) for each vertex where (fog_red, fog_green, fog_blue) is the constant fog color, and where fog_density is the fog density of the vertex.”

Let’s say I make fog at bottom and no fog at tp. What will happen when I move camera down? I should be inside heavy fog, but when I look up - I will see unfogged triangles. How to fix that?

That’s exactly the problem I pointed out a few posts earlier
If you never go through the fog, it’s not a problem.
But if you go through the fog, you may compute something more complex for fog_density.

That is, you have to compute in fog_density the “quantity” of fog that lies between the camera and the vertex. The problem is that this value changes as the camera moves (not when the camera rotates only) and it’s very computer-expensive.

But if you don’t want to waste some precious cpu time, you can mix OpenGL fog (I mean, glFog) with home-made fog (I mean, vertex colouring) : while you’re higher than the fog, use the 2-pass-fog with vertex colouring ; and when you enter the fog, add OpenGL classic fog.
When you add OpenGL fog, don’t add alot when you’re “close to the fog exit” and add alot more when you’re “deep inside the fog”.

And while you’re adding OpenGL fog, keep the 2-pass fog. That is, 2 fogs are active simultaneously : OpenGL fog and vertex colouring.

Thanks vincoof! I think I understand it now, and soon I will add it to my engine.