Lightmap Render States
Question submitted by (12 June 2001)

Return to The Archives
  Using DirectX 8 I want to add lightmaps to my scene, so that I can have effects like the lights on a wall behind a lamp. (see this for example). I want to use single-pass multitexturing, as my hardware supports 2 textures, and 8 texture blend stages.

I can't seem to have the right combo of RenderState and/or TextureStageState... The result is almost always blackness.

What is the correct way to do this?

  Let's start with an excerpt from the DX8 documentation. For those readers that want to locate this in the DX8 documentation, they'll find it in the Contents, using this path:

   DirectX 8.0
      + DirectX Graphics
         + Using DirectX Graphics
            + Textures
               + Texture Blending
                  + Light Mapping With Textures
                     + Diffuse Light Maps.

    // This example assumes that d3dDevice is a valid pointer to an
    // IDirect3DDevice8 interface.
    // lptexBaseTexture is a valid pointer to a texture.
    // lptexDiffuseLightMap is a valid pointer to a texture that contains
    // RGB diffuse light map data.

    // Set the base texture.
    d3dDevice->SetTexture(0,lptexBaseTexture );

// Set the base texture operation and args. d3dDevice->SetTextureStageState(0,D3DTSS_COLOROP, D3DTOP_MODULATE ); d3dDevice->SetTextureStageState(0,D3DTSS_COLORARG1, D3DTA_TEXTURE ); d3dDevice->SetTextureStageState(0,D3DTSS_COLORARG2, D3DTA_DIFFUSE );

// Set the diffuse light map. d3dDevice->SetTexture(1,lptexDiffuseLightMap );

// Set the blend stage. d3dDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE ); d3dDevice->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE ); d3dDevice->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT );

I'm going to assume you are already using code similar to this, yet your textures are still black. Let's first understand what these texture stage states are doing for us.

After setting the base texture, we set three texture stage states which control the color operations. There are color operations and alpha operations. As their names imply, they control the how color and alpha are calculated through the pixel pipeline.

The color operation for our base texture is set to modulation (multiplication). The two color arguments (D3DTSS_COLORARG1 and D3DTSS_COLORARG2) define what gets modulated (multiplied). The two arguments that get multiplied are D3DTA_TEXTURE (the texture for this stage) and D3DTA_DIFFUSE (the diffuse color from the vertices as it is interpolated across the polygon using Gouraud shading.) In other words, the result from the first stage is to perform a pixel-by-pixel multiplication of the diffuse color of the polygon (i.e. how it would look with no texturing) with the texture from this stage.

You'll notice that the next texture stage is setup almost the exact same way. However, rather than multiply the texture (in this case, the light map) against the diffuse component of the vertices, we'll be multiplying it against D3DTA_CURRENT (the result from the previous texture stage.)

Okay, I'll stop telling you what you probably already know and get down to the heart of the matter, your black textures.

It's important to note all of the details behind these color arguments. In the case of the first texture stage state, we're using D3DTA_DIFFUSE as the second color argument. If your vertices don't contain a diffuse component, then the default color (0xffffffff) is used. The result of this would be the texture from the first stage, unmodified. However, if you are including diffuse color information in your vertices, yet the diffuse color of those vertices is black, the result from the first stage will be a black surface. Since the second stage is also using modulation, it won't matter what is in your lightmap, the result from the second stage (and as a result, what you see) will, again, be black.

While we're on the topic of the diffuse color component... If you're multiplying a pure red texture (in the first stage) against a pure blue vertex color, your result will be black.

The next obvious problem would be if either, the texture itself or the lightmap were black. I'll assume you've already considered this possibility (if not, you should be shot, quartered and hung at dawn.) By the way, do you actually know what it means to be quartered? It's pretty gross. :)

I would recommend rendering the scene in single texture mode. Just render the texture map first to make sure it appears correctly. Then do the same for your light map. This is a sure-fire way to validate that you're passing it valid textures with valid UV values, proper texture addressing/wrapping, etc. Most importantly, this validates your render states are correct.

So, you've already been down all these paths and you still can't get your lightmaps to look right? I have another suggestion, then. Do you have lighting enabled (SetRenderState(D3DRS_LIGHTING, TRUE))? If so, this could casuse your black textures if the lighting results in black for that surface. This is especially true with lighting enabled, but no lights defined. With lighting enabled, the diffuse color of your vertices is ignored and the result from the lighting calculations is used instead.

If you're intentionally not using lighting and don't want the diffuse color of the vertices to impact the texture mapping, you can change the color operation for the first stage to D3DTOP_SELECTARG1 (make sure your D3DTSS_COLORARG1 is set to D3DTA_TEXTURE.) This will insure that your result of the first stage is not affected by the diffuse color of the vertices. On some older hardware (and especially with software renderers) this will speed things up since you're not performing any needless multiplications in the first texture stage.

From my experience, it's a good idea to test your code in the reference rasterizer - even when things are working. So make sure you get the same problem in the ref rast.

There are a lot of possibilities here, but these suggestions should help you narrow in on the problem, if not correct it. If these suggestions don't help, then we should carry this into the comments for this column entry.

Personally, I'm willing to bet it's the lighting. Am I right? :)

Response provided by Paul Nettle

This article was originally an entry in flipCode's Ask Midnight, a Question and Answer column with Paul Nettle that's no longer active.


Copyright 1999-2008 (C) FLIPCODE.COM and/or the original content author(s). All rights reserved.
Please read our Terms, Conditions, and Privacy information.