Upcoming Events
Unite 2010
11/10 - 11/12 @ Montréal, Canada

GDC China
12/5 - 12/7 @ Shanghai, China

Asia Game Show 2010
12/24 - 12/27  

GDC 2011
2/28 - 3/4 @ San Francisco, CA

More events...
Quick Stats
89 people currently visiting GDNet.
2406 articles in the reference section.

Help us fight cancer!
Join SETI Team GDNet!
Link to us Events 4 Gamers
Intel sponsors gamedev.net search:

  Contents

 Preface
 Texture Replaces
 Light

 Tecture Operation
 Unit

 Dark Mapping
 Alpha Operations

 Source code
 Printable version

 


  The Series

 The Basics
 First Steps to
 Animation

 Multitexturing
 Building Worlds
 With X Files


 

Dark Mapping

The D3DTSS_COLORx render states control the flow of an RGB vector, while the D3DTSS_ALPHAx render states govern the flow of the scalar alpha through parallel segments of the pixel pipeline. In Render() we use:


...
// Set texture for the cube
m_pd3dDevice->SetTexture(0,
  D3DTextr_GetSurface("wall.bmp"));
m_pd3dDevice->SetTextureStageState(0,
  D3DTSS_COLORARG1, D3DTA_TEXTURE); 
m_pd3dDevice->SetTextureStageState(0,
  D3DTSS_COLOROP, D3DTOP_SELECTARG1); 

// Set darkmap
m_pd3dDevice->SetTexture(1,
  D3DTextr_GetSurface("env0.bmp"));
m_pd3dDevice->SetTextureStageState(1,
  D3DTSS_COLORARG1, D3DTA_TEXTURE);
m_pd3dDevice->SetTextureStageState(1,
  D3DTSS_COLORARG2, D3DTA_CURRENT);
...

In Detail:


...
// first texture operation unit
// Associate texture with the first texture stage
m_pd3dDevice->SetTexture(0, D3DTextr_GetSurface("wall.bmp"));

// Set the first color argument to the texture associated with this stage
m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);

// Use this texture stage's first color unmodified, as the output. 
m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);

// second texture operation unit
// Associate texture with the second texture stage
m_pd3dDevice->SetTexture(1, D3DTextr_GetSurface("env0.bmp"));

// Set the first color argument to the texture associated with this stage
m_pd3dDevice->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE );

// Set the second color argument to the output of the last texture stage
m_pd3dDevice->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT);

// Set the color operation to the multiplication operation
m_pd3dDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE);
...

This code combines the following textures:

x=

This kind of multitexturing is called dark mapping, because the resulting texel is a darker version of the unlit texel of the primary map. This technique is used a lot in 3D shooters. You can see it in GLQuake1.

Nothing interesting is being done with the alpha channel of the pipeline in this case. There are no D3DTSS_ALPHAx render state calls. For RGB color, the render states D3DTSS_COLORARG1 and D3DTSS_COLORARG2 control arguments, while D3DTSS_COLORUP controls the operation on the arguments.

The first texture operation unit passes the data from texture 0 to the next stage. The control argument D3DTA_TEXTURE means: The texture argument is the texture color for this texture stage. The second texture operation unit receives these texels via Arg2. It modulates (D3DTOP_MODULATE) the texels from texture 0 with the texels from texture 1, which were received via Arg1. There are two other modulation operations:

D3DTOP_MODULATE Multiply the components of the arguments together.
D3DTOP_MODULATE2X Multiply the components of the arguments, and shift the products to the left 1 bit (effectively multiplying them by 2) for brightening.
D3DTOP_MODULATE4X Multiply the components of the arguments, and shift the products to the left 2 bits (effectively multiplying them by 4) for brightening.

The D3DTEXTUREOP structure shows the possible per-stage texture-blending operations. Just take a look at your DirectX 7 documentation. The default value for the first texture stage (stage 0) is D3DTOP_MODULATE, and for all other stages the default is D3DTOP_DISABLE.

The IDirect3DDevice7::SetTexture method assigns a texture to a given stage for a device. The first parameter must be a number in the range of 0-7 inclusive. Pass the texture interface pointer as the second parameter. This method increments the reference count of the texture surface being assigned. When the texture is no longer needed, you should set the texture at the appropriate stage to NULL. If you fail to do this, the surface will not be released, resulting in a memory leak. Since version 6, Direct3D maintains a list of up to eight current textures. So Direct3D supports the blending of up to eight textures onto a primitive at once. It blends these textures onto all of the primitives it renders. Only textures created as texture interface pointers can be used in the set of current textures.

Note: Textures under the IDirect3D2 interface were manipulated using texture handles. With the IDirect3D7 interface (and the legacy IDirect3D3 interface), you create and use textures through interface pointers to the texture surfaces. You obtain a texture surface interface pointer when you create the texture surface by calling IDirectDraw7::CreateSurface which is called in the framework by D3Dtextr_CreateTextureFromFile() method.

When your application selects a texture as the current texture, it instructs the Direct3D device to apply the texture to all primitives that are rendered from that time until the current texture is changed again. If each primitive in a 3-D scene has its own texture, the texture must be set before each primitive is rendered.

Software devices do not support assigning a texture to more than one texture stage at a time.

I've made an animated sample with the three modulation types:


...
// animate darkmap
if (i < 40)
{
  m_pd3dDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE);
}
else if (i < 80)
{
  m_pd3dDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE2X);
}
else if (i < 120)
{
  m_pd3dDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE4X);
}
else if (i = 120)
{
  i = 0;
}
i++;
...

Blending a texture with diffuse color lighting

Sometimes the sun shines so bright that the colors on things get brighter. You can immitate that effect by blending the texture with diffuse color lighting:


...
// Set texture for the cube
m_pd3dDevice->SetTexture(0, D3DTextr_GetSurface("wall.bmp"));
m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_ADD);
...

In Detail:


...
// Associate texture with the first texture stage
m_pd3dDevice->SetTexture(0, D3DTextr_GetSurface("wall.bmp"));

// Set the first color argument to the texture associated with this stage
m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);

// Set the second color argument to diffuse lighting information
m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);

// Set the color operation to the addition mode
m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_ADD);
...

Darkmap blended with diffuse color lighting

Now we're combining the two effects:


...
m_pd3dDevice->SetTexture(0, D3DTextr_GetSurface("wall.bmp"));
m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_ADDSIGNED); 

// Set darkmap
m_pd3dDevice->SetTexture(1, D3DTextr_GetSurface("env0.bmp"));
m_pd3dDevice->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE);
m_pd3dDevice->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT);
m_pd3dDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE);
...

I think this is self-explaining for an old multitexturing freak like you. You should play around with D3DTOP_ADDSIGNED, D3DTOP_SUBTRACT and D3DTOP_ADDSIGNED2X as the color operation of the first texture stage. My favorites are D3DTOP_ADDSIGNED and D3DTOP_SUBTRACT. The latter is really cool.


Next : Alpha Operations