Dynamic Lighting In 3D Scenes by (13 January 1999) Return to The Archives
 Introduction
 This document is a short description of the illumination model used in Focus, my small 3D engine that I use for trying out techniques related to real-time 3D computer graphics. The model is based on light volumes, and it offers an alternative for the commonly used models.

 Common Methods

 The Alternative
 So this is where 'my' model kicks in. I'm sure that it is used before, and maybe it is even documented, but what the heck.Basically, I project a texture on a polygon. That's nothing new: It looks like phong shading. But a fake phong lightmap is used as an environment map, and thus every pixel of every polygon is covered by a pixel from the phong lightmap. This is obviously not always what you want: If you have a spotlight in a room with a narrow beam, you don't want every polygon in the room to catch pixels from the lightmap. And you CERTAINLY don't want that if you have multiple narrow beams.So, I construct a nice volume for the beam. Four planes do the job just fine. Then, every polygon in the scene is clipped against this volume. (Obviously, some optimizations are needed here, but that's not needed to get the idea at the moment) The resulting polygons and polygon parts are precisely the lit polygons: If you would draw these parts in white, you would have a nice beam in your scene. It does shine THROUGH your objects though, I'll address that in a minute. But of course we want to get a bit further than a large square white beam. So, the clipped parts are processed a bit further: First, they get the texture of the light source. This can be anything: A nice single spot, or lots of spots, or even a full color photograph. Then, each vertex of the (clipped) polygon needs new U/V coordinates. Use the following formulas for this:U = lightmap_width  * dist1 / (dist1 + dist3) V = lightmap_height * dist3 / (dist2 + dist4)Where: U is the horizontal index in the lightmap texture; V is the vertical index in the lightmap texture; dist1 is the distance of the vertex to the first boundary plane of the light volume; dist3 is the opposite plane; dist2 is the distance of the vertex to the second boundary plane of the light volume; dist4 is the opposite plane.Thus; dist1/(dist1+dist3) is always a value between zero and one, regardless of the distance of the vertex to the light source. The same goes for dist3/(dist2+dist4).Now the texture can simply be drawn transparent over the existing polygons.

 Finishing Touches
 I promised to address the problem of the 'penetrating volume'. That's simple: Only polygons that face the light source are potentially lit. One obvious optimization: Only polygons that face the camera need to be lit. Otherwise they won't be visible anyway. :) More optimizations: If the light source doesn't move, the clipped polygons can simply be drawn again in the next frame, so the lighting is not so expensive anymore. It is rather easy to implement a system that recalculates the clipped parts ONLY when the light source or the scenery changes. This way you can have fully dynamic lights that are as fast as regular methods, except when the lights move. If you keep the number of simultaneous moving lights in your scenes low, this is some awesome lighting!