Tutorial *92*
Some people might remember the fog effect you could add to Quake 2 with a few simple additions to the dll. Well, here it is again, in Quake 1 format (only a little cooler). This tutorial is for anyone with a copy of VC6, and who has made sure they can compile their copy of the Quake source. If you are having trouble, there are tutorials available on this site. Once you’ve done that, we’re ready to get our coding hats on!

Right, first up is to set the version we are compiling to GLQuake. I’m working on fog in software, but that involves some funky math (more funky than you’ll see here, anyway), so we’ll stick with GL only, for simplicity. If you’re not sure how to change you’re configuration to build GLQuake, then simply go to the Build menu, select Set Active Configuration, then click "winquake - Win32 GL Release", and hit OK. If you’ve not compiled this before, now is a good time to do so, so we don’t have to wait around for hours in the next section, and is a good place to test you’ve got it right so far. Press F7, and watch the build window go! Once it’s done, head on over to your quake source direction, into the WinQuake folder, where you should find a new folder called "release_gl". In there resides you’re shiny new self compiled glquake.exe, all ready to go! Stick it in you’re Quake folder and run it if you don’t believe me!

Next thing on the agenda is to find the place where we will add in our fog code. Just look for "gl_rmain.c" in your file list, and open it up. Now, scroll down to the function that actually controls most of the rendering (screen updates) of GLQuake, "R_RenderView". To find it quickly, simply search for "void R_RenderView (void)". This function is responsible for updating you’re screen in GLQuake. It does some things itself, but for some other things, it calls other functions for. That’s lucky for us, as it means less code to trawl through to add in the fog.

Now, read this function through. Don’t worry if you don’t understand it, but reading code is an important step whenever you are editing something someone else has written, or are learning in general. The astute of you may have noticed that id had already begun to experiment with fog themselves, but never properly finished it. So, lets pick up where they left off. Find the lines in this function that say…



/***** Experimental silly looking fog ******

****** Use r_fullbright if you enable ******

	glFogi(GL_FOG_MODE, GL_LINEAR);

	glFogfv(GL_FOG_COLOUR, colours);

	glFogf(GL_FOG_END, 512.0);

	glEnable(GL_FOG);

********************************************/

They’re right, the bright blue fog this gives us does look silly. So, lets change this code to something that will give us a better effect. Replace that whole block with this (just trust me for now, I’ll explain in a minute)…



glFogi(GL_FOG_MODE, GL_LINEAR);
glFogfv(GL_FOG_COLOR, colors);
glFogf(GL_FOG_START, 300.0);
glFogf(GL_FOG_END, 1536.0);
glFogf(GL_FOG_DENSITY, 0.2);
glEnable(GL_FOG);

OK, just a couple more things to do before you can compile and play around again! Go down a little more, and find the lines…



//  More fog right here :)
// glDisable(GL_FOG);
// End of all fog code...

Nuke all that, and replace it with



	glDisable(GL_FOG);

OK, we now have a nicer looking blue fog. "Blue!", you cry? I didn’t like it either, so I changed it to a more subtle grey. Find the line (this time at the top of the function)…



GLfloat colors[4] = {(GLfloat) 0.0, (GLfloat) 0.0, (GLfloat) 1, (GLfloat) 0.20};

This sets the colour of the fog, in RGBA format. The first number is the red component, second green, third blue, and 4th is the Alpha, or transparency component. I changed it too…



GLfloat colors[4] = {(GLfloat) 0.3, (GLfloat) 0.3, (GLfloat) 0.3, (GLfloat) 0.1};

You can alter these values to whatever you like, to get the effect you want. Experiment!

OK, that’s pretty much it. Hit F7 again, and copy the resulting exe to you’re Quake directory. You should now notice a grey (or whatever colour you gave it) mist hanging around, fading into to a sold wall of that colour over a long distance. And there we have it, a simple to add and complex looking graphical effect in virtually no code. But wait! Don’t run off yet, unless you reckon you’re done learning (or hate maths)! Time to get into the real mechanics behind what we just did. Have a look at these…

F = (end - z)/(end - start)    (Where z is the distance between the camera and the point of fog in question)

Cr’ = F x Cr + (1 - F)CF     Where Cr is the initial, pre fog colour of the point, CF is the fog colour, and F is defined above.

Also note that after F is calculated, it is clamped between 1 and 0 (i.e, if its more than 1, its made 1, if its less than 0, its made 0). The variables "end" and "start" give the distance from the camera at which fog starts and at which it ends (we set them with some calls when we started our fog, a free prize of nothing for the person to spot where!).

Right, these will look scary to some, but they are really not that bad. They are the equations that OpenGL use to calculate our fog in this instance. F is an easy one, and calculates fog intensity at any given point. Obviously, end - start is the length of the whole fog ‘bank’. End - z gives us the ‘depth’ of the point in the fog bank (starting from the back of it), based on the cameras position. Then, a simple division gives us the fraction of how similar any given point is in intensity to the nearest point. Sorry if that’s all a little muddled, I hate putting maths into words, but I’m sure most people can work it out from the equations alone.

With that knowledge, the next equation is even easier. Cr’ is the new colour value of a given point, after the fogging has been applied. F is the fractional intensity of the fog, and looking at the equation, we can see that a value of F=0 will give us the most fog. Confusing, I know, but that’s the way it is. F*Cr is really easy, its the amount of the original colour of the point that will remain. Min F, max fog, no original colour remains. Simple. The next part, (1 - F)CF is also easy. Min F, max fog, 1-0 = 1, 1*CF = CF, all the colour is replace with the fog colour. Test it yourself with some simple numbers, it works, and the code we just wrote proves it. Add them together, and you get the new colour!

Ahh, scary (and badly explained) maths is now done. Back to code, more specifically, OpenGL. This isn’t a how to code OpenGL tutorial, so I’ll just give you the reasoning behind what we did. http:\\www.opengl.org has real tutorials for the interested. Basically, everything before glEnable(GL_FOG); was setting up our fog. We call a few functions with the values we want our fog to have. This tells OpenGL what sort of effect we want. Then we call glEnable(GL_FOG);. Now, in OpenGL, everything that happens (in the main) that gets drawn to the screen happens between a pair of calls. Browsing the code, you’ve probably seen things like glBegin (GL_TRIANGLE_STRIP);. This says "Every color/vertex etc that I give you between this and glEnd (); is going to be part of a strip of triangles". "OK", you say, "sounds simple, but we didn’t use glBegin!". True enough, sir, true enough, what we did was flip one of OpenGL’s many ‘switches’, with our glEnable call. We said "For everything you render from now on, use our fogging!". And, lo and behold, fog appears!". Now, we only want fog on the world view (that is, what you see), so after the calls that build the world, we flip our switch off with glDisable(GL_FOG); and say "right, that’s enough fog for now!". Hence, no fogging is applied to anything else.

Tada! If you sat through all this, well done to you. I don’t claim to be anything approaching an expert in this field, so if you find any inaccuracies with what I’ve written, please do tell me. Also, if you’ve got any questions/problems, feel free to contact me! Anyway, go off now, and impress you’re friends in Deathmatch by looming out of the fog at them!.

Adam Wright, aka Asriel


 
Sign up
Login:
Passwd:
[Remember Me]