Separable lighting June 11th, 2009So I want to talk briefly about lighting.
The classic method of illumination in games involved adding up all the lighting affecting a point, which gives you an RGB value. For static lighting, you either add this up per-vertex, or maybe per-pixel in a lightmap, and store it out somewhere. The trouble with this kind of approach is that the lighting value is a fixed color, which prevents you from doing things like realtime time-of-day stuff, or flickering lights, or dynamic shadowing, or whatever.
A trend I've noticed in recent times is to split into the lighting equation into it's individual components, and store those instead of the source RGB value. I figured perhaps if I wrote about it here and gave it a catchy name ("separable lighting!"), it might get more attention.
So for instance, rather than store your lighting in a RGB lightmap as ( final.rgb = sun_visibility * sun_attenuation * sun_color + ambient.rgb ), you'd instead store off in the lightmap just the terms that matter – in this case maybe sun_visibility and ambient.rgb, and work out the rest at runtime. You could store these two in a single DXT5 texture, and with only a small bit of math in the pixel shader you could combine them to get the final RGB value.Another example- imagine your room is lit by four lights. You could store the percent of light0 in R, percent of light1 in G, percent of light2 in B, etc. These values might all end up being store in a lightmap or perhaps per-vertex.
The key advantage to this approach is that although you're basically doing baked lighting, it means you can still do some dynamic stuff. For example, if you wanted to merge lightmap shadows with dynamic shadows, you can do that; you have the percent of sunlight, you have the percent shadowed by the dynamic objects. You can just min() them in the pixel shader to get the final amount. And then add the ambient or whatever.
Or perhaps you want to change the lighting of your level to fade from nighttime through to daytime. Normally this would be hard, but if you have your lightmaps stored in a separable format, then it's easy to change the color of the sun light at runtime. You basically assume the direction of the sun is fixed, and the visibility of the sun is fixed, and the ambient values will be similar enough for no-one to notice. You just change the color of the sunlight, while still reading the "sun visibility term" from the lightmap.
I guess the key idea I'm trying to get across here is that you don't need to store the end results of the lighting equation, just the parts that you need to. Some parts can be computed dynamically for little cost, and some parts (the parts that are hard to compute, like radiosity), can be baked into textures. It's up to you which parts you need to replace or modify at runtime.
Written by Richard Mitton,
software engineer and travelling wizard.
Follow me on twitter: http://twitter.com/grumpygiant