next up previous contents
Next: 10.2.2 3D Texture Light Up: 10.2 Light Maps Previous: 10.2 Light Maps   Contents

10.2.1 2D Texture Light Maps

A 2D light map is a texture map applied to the surfaces of a scene, modulating the intensity of the surfaces to simulate the effects of a local light. If the surface is already textured, then applying the light map becomes a multipass operation, modulating the intensity of a surface detail texture.

A 2D light map can be generated analytically, creating a bright spot in luminance or color values that drops off appropriately with increasing distance from the light center. As with other lighting equations, a quadratic drop off, modified with linear and constant terms can be used to simulate a variety of lights, depending on the area of the emitting source.

Since generating new textures takes time and consumes valuable texture memory, it is a good strategy to create a few canonical light maps, based on intensity drop-off characteristics and color, then use them for a number of different lights by transforming the texture coordinates. If the light source is isotropic, then simple translations and scales can be used to position the light appropriately on the surface, while scales can be used to adjust the size of the lighting effect, simulating different sizes of lights and distance from the lighted surface.

In order to apply a light map to a surface properly, the position of the light in the scene must be projected onto each surface of interest. This position shows where the bright spot will be. The perpendicular distance of the light from the surface can be used to adjust the bright spot size and brightness. One approach is to generate texture coordinates, orienting the generating planes with each surface of interest, then translating and scaling the texture matrix to position the light on the surface. This process is repeated for every surface affected by the light.

In order to repeat this process for multiple lights (without resorting to a multilight lightmap) or to light textured surfaces, the lighting must be done as a series of passes. This can be done two ways. The more straightforward way is to blend the entire scene. The other way is to blend together the surface texture and light maps to create a texture for each surface. This texture will represent the contributions of the surface texture and all lightmaps affecting its surface. The merged texture is then applied to the surface. Although more involved, the second method produces a higher quality result.

For each surface:

  1. Transform the surface so that it is perpendicular to the direction of view (maximize its visible surface). Scale the image so that its area in pixels matches the desired size of the final texture.
  2. Render the transformed surface into the frame buffer (this can be done in the back buffer). If it is textured, render it with the surface texture.
  3. Re-render the surface, using the appropriate light map. Adjust the GL_ EYE_PLANE equations and the texture transform to position the light correctly on the surface. Use the appropriate blend function.
  4. Repeat the previous step with each light visible to the surface.
  5. Copy the image into a texture using glCopyTexImage2D().
  6. When you've created textures for all lit surfaces, render the scene using the new textures.

Since switching between textures must be done quickly, and lightmap textures tend to be small, use texture objects to switch between different light maps and surface textures to improve performance.

With either approach, the blending is a modulation of the colors of the existing texture. This can be done by rendering with the blend function (GL_ ZERO, GL_ SRC_COLOR). If the light map is composed of luminance values than the individual destination color components will be scaled equally, if the light map represents a colored light, then the color components of the destination will be scaled by the red, green, and blue components of the light map texel values.

Note that each modulation pass attenuates the surface color. The results will become increasingly dim. If surfaces require a large number of lights, the dynamic range of light maps can be compressed to avoid excessive darkening. Instead of ranging from 1.0 (full light) to 0.0 (no light), They can range from 1.0 (full light) to 0.5 or 0.75 (no light). The no light value can be adjusted as a function of the number of lights in the scene.

Here are the steps for using 2D Light Maps:

  1. Create the 2D light data. ``Canonical lights'' can be defined at the center of the texture, with the intensity dropping off in a realistic fashion towards the edges. In order to avoid artifacts, make sure the intensity of the light field is the same at all the edges of the texture volume.
  2. Define a 2D texture, using GL_ REPEAT for the wrap values in $s$, $t$, and $r$. Minification and magnification should be GL_ LINEAR to make the changes in intensity smoother. For performance reasons, make this texture a texture object.
  3. Render the scene without the lightmap, using surface textures as appropriate.
  4. For each light in the scene:
    1. For each surface in the scene:
      1. Cull surfaces that cannot ``see'' the current light.
      2. Find the plane of the surface.
      3. Align the GL_ EYE_PLANE for GL_ s and GL_ t with the surface plane.
      4. Scale and translate the texture coordinates to position and size the light on the surface.
      5. Render the surface using the appropriate blend function and lightmap texture.

An alternative to simple light maps is to use projective textures to draw light sources. This is a good approach when doing spotlight effects. It's not as useful for isotropic light sources, since you'll have to tile your projections to make the light shine in all directions. See the projective texture description in Section 10.1.2 and in Section 6.16 for more details.

next up previous contents
Next: 10.2.2 3D Texture Light Up: 10.2 Light Maps Previous: 10.2 Light Maps   Contents