Many, many people... even experienced modders and mapmakers continually support the urban legend that the Doom3 engine cannot handle ambient lighting at all. I read daily from people that an area that's not lit in the D3 engine is by definition pitchblack. I hear claims that well-lit area's will create considerable loss of FPS and that the only way to make ambient light is by either using the flawed ambient lights or cheap tricks such as hud-shaders.
I've been taking some time to come up with a fix for these limitations in the Doom3 engine and I think I have found one. Before I continue with this tutorial --which is far more simple than you might expect-- I have to establish some things first though.
Some people say that
any ambient light setup is a 'just a trick' to make the D3 engine show ambient lights and that this is not 'true ambient lighting', regardless of how it looks! In my opinion such arguments are inherantly flawed because all game-engines out there today are basically a big bunch of tricks pulled together to create a virtual world for a player to behold.
Anything from lighting to water to particles are just basic approximations and systems of simple hacks put together to create illusions. We, modders, are in the art of making illusions, we are in effect illusionists. Using hacks and tricks we try to create a virtual world which is believable within it's setting.
A good example of this is particle systems. A well set up particle can create the illusion of smoke, fire or water. A particle system doesn't even come close to real world water, fire or smoke. Technically, a particle system is just a bunch of sprites that move from point a to point b using mathematical predetermined paths. The technique of transparent sprites goes back to the commodore 64 and the first gaming consoles and has in essence not changed since.
Lightmapping as we know it from the older type of engines such as the quake3 engine is basically a method of adjusting the brightness of textures at places which have been predefined by the author of a map. Using the several available shader stages in D3 materials, it's relatively easy to use that same method in making ambient light work in the D3 engine.
Taking that into account, anything you see in any game engine is basically a trick to create the illusion of something. What does this mean? This means that as long as you get a desired effect, the means you used to get that effect aren't important at all. It just
doesn't matter as long as you get the desired effect.
On to the tutorial
As a mapper, at this point you will propably be familiour with the material and shader system which is utilized in the D3 engine. Brian from ID software has taken the time to write a complete shader and material reference on the
iddevnet website. At this point I would like you to go over there and take a look at his material and shader documentation if you have not done so in the past to get aquinted on how to make shaders and materials.
Let's take a look at a basic material setup for a common texture in Doom3, called
textures/hell/cbrick2. You can find this material shader in the hell.mtr file in pak0001.pk4 in your base directory.
(Find this file now and unzip it into your mod directory or base directory, because we will be making changes to this file.)
This is what the code for this shader looks like:
Code:
textures/hell/cbrick2
{
qer_editorimage textures/hell/cbrick2.tga
stone
diffusemap textures/hell/cbrick2.tga
bumpmap addnormals( textures/hell/cbrick2_local.tga, heightmap( textures/hell/breakage1_h.tga, 3 ) )
specularmap textures/hell/cbrick2_s.tga
}
As you can see there are several stages in this material. A diffusemap, specularmap and a bumpmap stage. For this technique we will be adding a new stage later in this tutorial.
First, let's take a look at how this texture looks in game. I will make 2 screenshots, one with the lights on, and one with all lights removed from the map using the 'clearLights' console command.
This first shot has 3 lights which are active. The most important one is a huge light intended to light up the general area. Allthough this gives some effect if I were to turn the shadows on for this light (shadows are off for it at the moment) this would certainly impact the FPS a lot. As you can see there are several pitch black places in this screen (the wall to the left). This is the way that most mappers try to set up ambient lighting and this is where their frustration comes from in lighting scenes. Not only that, the scene is still pretty dark.

In this next shot I have used the 'clearLights' console command, which deletes all the lights from a scene. As you can see, everything is now pitch black. This shows that any unlighted surface in the engine is pitch black.
Ok. Now that we know what the problems are, on to the fix!For my fix, I tend to keep the over all sky light on. This means that I have one huge light set up that will create some light for me. I've done this so that playermodels and enemies and other models will light up accordingly.
Let's take a look now at another command called the 'reloadSurface' console command. It's best to bind some key to this command at this point of the tutorial because you will be using this command a lot.
Let's go back to the material files and the several stages that we can use in these files. We will be adding a new stage to every shader, in every part of your map that you will want to have ambient lighting for. This stage will be a special stage that uses the additive mode to add some ambient light to all of the shaders that I will use in my map.
I use the textures/hell/cbrick2 texture a lot in my map so I will take this material as an example but the principle remains the same for any other shader that you will use for your maps. The first thing I did was to start up the game, open my map and walk in to a wall that uses this shader. Then I used the reloadSurface console command to see which texture it was. Guess which one it was? You guessed right,
textures/hell/cbrick2 
Then, after knowing which shader would need modification I open up hell.mtr in notepad and find the shader. I then add this new special stage to the code. This stage uses the diffusemap of the current shader that I'm working on. In this case
textures/hell/cbrick2.tga.
Code:
textures/hell/cbrick2
{
qer_editorimage textures/hell/cbrick2.tga
stone
diffusemap textures/hell/cbrick2.tga
bumpmap addnormals( textures/hell/cbrick2_local.tga, heightmap( textures/hell/breakage1_h.tga, 3 ) )
specularmap textures/hell/cbrick2_s.tga
{
blend add //gl_one, gl_dst_alpha
map textures/hell/cbrick2.tga
rgb 0.3
}
}
Notice that the 'blend add' and the 'rgb' are the most important things here. These are the means by which you can control your ambient light. The RGB value goes from 0 to 1. 0. Zero (0) meaning that no extra lighting is used at all and one (1) meaning that this texture is 'full bright'.
For this particular map I have decided that an rgb value of 0.3 looks best. But for say, urban settings or the Doom 3 can do it too project, you could easilly use values up to 0.5 or even 1... depending on how light you want your map to be. For the broad daylight setup at the end of this tutorial I use a value of 0.9!
Now at this point I imagine that I am a monk and I go through all the textures of my map and add this stage to each of them that I want to have ambient lighting. In my case there were only 10 textures so this was a total of not even 3 minutes work. I would say that's still quicker than waiting 1 to 2 hours for lightmaps to be calculated... but hey that's just me.
After doing so, I came with this result. I will again make two screenshots, one with lights and one without so that you can see that this ambient light is truly ambient and does not rely upon any lights whatsover. This is the huge advantage of this method. It will not kill your FPS.
Notice that there is not one completely dark area left now in these screenshots, eventhough the second one has
no lights whatsoever.
All that's left in this shot is the ambient, after using the clearLights command. I've not implemented the fix on the mapobjects in this map so you can see the difference between the ambient lighted textures and the ones that weren't.
Now, since the map I've used for this is set during the night, you may think I'm cheating.. so. I set up an daylight scene (broad daylight) with the same technique for you. The first screenshot utilizes ONE light that casts full shadows. I've used the clearLights console command again to show just the ambient in the second screenshot. You can see the ambient effect particularly well on the ground. The first two shots are WITH the effect, the second two shots are WITHOUT this effect. In these last shots of this effect I have used a really high ambient setting of 0.9, I did this just to show you how far you can go in making the dark spots of your map look brighter. With just a little bit of tweaking you can get some amazing ambient light effects in game.
I can assure you that the next shot only uses ONE light. If you don't see a world of difference between these shots then you need glasses!
With the ambient effect:
Without the ambient effect:
clearLights With ambient effect. Remember, there are NO lights in this map at all:
clearLights without ambient effect:
Conclusion:
It's no hard leap to go on to claim this is not a cost effective method of setting up ambient lights for mapping in terms of time but to be honest, once you have a basic setup done and once you've made the textures you want to use in other maps you are done. You only have to give your textures this special stage once.
When I get time I will continue on this method and show you how you can change the ambient light setup realtime by the use of shaderparms in scripts. This is the method that we will be using for the Hexen:Edge Of Chaos mod. Each level will have a simple setting during scriptload that will tell all shaders which ambient lightlevel to use.
If you
still feel that this method is too timeconsuming then I suggest you try the following: Load up any lightmapped engine such as the Source engine, make your map, place your lights, compile it, wait for two hours for it to finish. Find out there are glitches, replace the lights, adjust some settings, wait another 2 hours for the compiling to finish and repeat that process for 4-8 times before you can call your map 'finished', then come back here and we'll have a discussion about timeconsuming mapping methods.
