The thought of fog problems with multipass lighting has prevented me from using multipass in my renderers for too long. Today I decided to stop and think about it for a minute, and the solution is very simple!
Fog is implemented as a linear interpolation between the shaded color of the pixel and the fog color, using a fog factor. In my case the fog factor is calculated like this:
float fog_factor = exp2(-abs(view_dist * fog density));
and here is the cg code for calculating the final color:
final_color = lerp(fog_color, final_color, fog_factor);
which is equivalent to:
final_color = fog_color * (1.0 – fog_factor) + final_color * fog_factor;
when multipass lighting is used, fog should be applied to the final color (the sum of all passes):
final_color = fog_color * (1.0 – fog_factor) + (pass1_color + … + passn_color) * fog_factor;
final_color = fog_color * (1.0 – fog_factor) + pass1_color * fog_factor + … + passn_color * fog_factor;
final_color = lerp(fog_color, pass1_color, fog_factor) + pass2_color * fog_factor + … + passn_color * fog_factor;
So the first pass is rendered normally, as in single pass rendering, but the next passes are drawn without adding “fog_color * (1.0 – fog_factor)” each time. We have two options to implement this:
- Write separate shaders for the first and for the subsequent passes, or
- Make the term “fog_color * (1.0 – fog_factor)” be equal to zero in all passes except the first.
The first option might seem a little more oprimized at first, because it eliminates one or two instructions, but in fact it isn’t. The cg manual states that it’s better to use standard library functions, like “lerp”, than coding them on your own, because they are more optimized.
On top of being more optimized, the second option is also more convenient, because you don’t need to maintain separate shaders with no fog term. You just zero the fog term 🙂
So how can we zero the fog term? If you are reading this I think I don’t need to tell you (in fact I shouldn’t have even argued about why the second approach is better …).
Ok, ok ….
Short answer: Do the first pass normally, and the rest of the passes with fog enabled and set the fog color to black.