3.1 Creating and Rendering Light Maps
There are two main methods of producing lighting effects in 3D graphics: vertex lighting and phong shading.
Vertex lighting is the model provided by OpenGL and is explained in detail in the Red Book. At each vertex the intensity of the light from each light source is calculated and the results summed to determine the overall lighting level. This process results in distinct lighting values at each corner of a polygon. Gouraud shading is therefore normally applied to obtain a smooth transition in lighting level across the surface of the polygon. This works fine for any object that is made up of relatively small polygons but is not so useful in large rooms where the polygons tend to be much bigger and the limitations of gouraud shading become readily apparent.
In phong shading the lighting level is determined for every point on a polygon's surface so the result is much more accurate and lifelike. There is no direct support for phong shading in OpenGL but the API is rich enough to allow various methods to be used to approximate the effect. The lighting map is the usual method that is used to create static (and often dynamic) lighting within games. I will limit this discussion to the methods I use to provide static lighting within Corridors of Power using light maps.
3.1.2 Generation of Lighting Maps
Each panel in a level is assigned a unique texture, its light map. A pre-processor program is used to generate the light maps off-line, these are then loaded and blended onto the scene panels at run-time. As the light maps don't contain as much detail information they can be rendered, with the help of bi-linear filtering, at a significantly lower resolution than scene textures and this helps to keep the texture memory budget within reasonable limits.
Before a lighting map can be calculated, it needs to be orientated in relation to the scene panel. The easiest way to do this is take one of the edges of the scene panel to be the s axis. The vector between the two vertices that describe the edge is then used to determine the unit vector in the s axis. Then another vertex on the panel is used to determine the unit vector in the t axis, which of course must be perpendicular to the s axis. The panel size and/or the light map scaling factor are then used to determine the texel spacing for the light map. All this data allows the position in 3D space of each texel in the light map to be determined. The figure below illustrates these concepts.
For every texel on the light map, the vector from every relevant light source is checked to ensure that there is no collision with a scene panel, (see the section on Collision Detection for the maths to do this). If the texel is not in shadow then the intensity of the light at that point is calculated and summed with any other contributions. Light intensities can be calculated using the same formula applied in vertex lighting within OpenGL.
Note: a problem can occur because the bi-linear filtering process applied when the light map is rendered will include the dark texels beyond the lit region of the map, resulting in dark edges on panels. Therefore, the process needs to add extra rows/columns of lit texels beyond the edge of the lit region in order to avoid this problem. This is illustrated by the two pairs of figures below, the first pair shows what can happen to an un-adjusted lightmap and the second pair shows the correct operation of an adjusted lightmap. (The active region of the lightmaps is indicated by the orange line.)
3.1.3 Rendering Lighting Maps
When rendering each scene panel with its corresponding light map, Corridors of Power uses the following process:
This is certainly not the only way to do a light map, but it should give you an idea of the principles involved. The blend function is one of several that can be used, for example a function of (GL_DST_COLOR, GL_SRC_COLOR) would reduce the overall loss of brightness that can occur.