Texture Blending

[Previous] [Next]

You can produce many interesting effects by blending a texture with the underlying primitive's color or another texture on the same primitive. To determine which texture-blending capabilities the target hardware supports, you can check the dwTextureOpCaps member of the D3DDEVICEDESC7 structure using the IDirect3DDevice7::GetCaps method.

Texture blending allows you to create incredibly realistic scenes by combining multiple textures and adding finishes and light maps to primitives. The three main texture-blending techniques are multipass texture blending, multiple-texture blending, and bump mapping.

Multipass Texture Blending

Multipass texture blending is the process of applying numerous textures to a primitive in several passes. This older process of texture blending is often used for the light and shadow mapping of primitives. All Direct3D device interfaces support this type of blending. Multiple-texture blending, which the next section covers, performs this same process on newer 3D hardware but uses only a single pass. However, if the target system isn't capable of multiple-texture blending, you can use multipass texture blending to produce the same result but at a slower rate.

To enable multipass texture blending, set a texture in texture stage 0 by calling the IDirect3DDevice7::SetTexture method. Next select the desired color and alpha blending arguments and operations by using the method IDirect3DDevice7::SetTextureStageState. Next render the objects composing your scene, and set the next texture in texture stage 0. Finally, set the desired color and alpha blending arguments and operations for the second texture, and render the objects again.

Just repeat these steps for all the textures in your scene. For each pass, you must set the current texture. Direct3D blends the texel colors of the current texture with the pixel colors defined in the frame buffer. The following sample code shows how to apply multipass texture blending to a primitive:

 // Draw the first textures normally. Use the first set of texture // coordinates. m_pd3dDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0 ); m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1,                                     D3DTA_TEXTURE ); m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP,                                     D3DTOP_MODULATE ); m_WallData.textureCoords[0].lpvData = &m_avWallVertices[0].tuBase; m_pd3dDevice->SetTexture( 0, D3DTextr_GetSurface("wall.bmp") ); m_pd3dDevice->DrawPrimitiveStrided( D3DPT_TRIANGLELIST,                                     D3DFVF_XYZ | D3DFVF_DIFFUSE |                                     D3DFVF_TEX2,                                     &m_WallData, 24, NULL ); m_pd3dDevice->SetTexture( 0, D3DTextr_GetSurface("floor.bmp") ); m_pd3dDevice->DrawPrimitiveStrided( D3DPT_TRIANGLELIST,                                     D3DFVF_XYZ | D3DFVF_DIFFUSE |                                     D3DFVF_TEX2,                                     &m_FloorCielData, 12, NULL ); // Draw the light map by using blending, with the second set of // texture coordinates. m_pd3dDevice->SetRenderState( D3DRENDERSTATE_ALPHABLENDENABLE,                               TRUE ); m_pd3dDevice->SetRenderState( D3DRENDERSTATE_SRCBLEND,                               D3DBLEND_ZERO ); m_pd3dDevice->SetRenderState( D3DRENDERSTATE_DESTBLEND,                               D3DBLEND_SRCCOLOR ); m_WallData.textureCoords[0].lpvData = &m_avWallVertices[0].tuLightMap; m_pd3dDevice->SetTexture( 0, D3DTextr_GetSurface("lightmap.bmp") ); m_pd3dDevice->DrawPrimitiveStrided( D3DPT_TRIANGLELIST,                                     D3DFVF_XYZ | D3DFVF_DIFFUSE |                                     D3DFVF_TEX2,                                     &m_WallData, 36, NULL ); // Restore state. m_pd3dDevice->SetRenderState( D3DRENDERSTATE_ALPHABLENDENABLE,                               FALSE ); 

Single-Pass Multiple-Texture Blending

DirectX 6 introduced the ability to apply multiple textures to primitives in a single pass (as opposed to the multipass approach you just learned about). To determine which texture-blending capabilities the target hardware supports, use the IDirect3DDevice7::GetCaps method to check the dwTextureOpCaps member of the D3DDEVICEDESC7 structure.

The IDirect3D7 and IDirect3DDevice7 interfaces allow you to blend up to eight textures on your primitives in a single pass. This texture-blending approach is much faster than the older multipass approach. With single-pass multiple-texture blending, you can combine special effects such as textures, shadows, and diffuse and specular lighting in a single pass. To blend multiple textures, you assign textures to a set of current textures and create the blending stages.

Direct3D provides single-pass multiple-texture blending through the use of texture stages. A texture stage takes two arguments and performs a blending operation on them. You can perform more than 25 operations on the arguments. The arguments for a texture stage can be an associated texture, a color or alpha value iterated during Gouraud shading, an arbitrary color or alpha value, or the result from the previous texture stage.

The results of each stage are carried over to the next one, and the result of the final stage is rasterized on the polygon. This process is called the texture-blending cascade. Direct3D provides eight stages (numbered 0 to 7), but some hardware devices provide fewer (or none at all). The stages are blended in increasing order of index. You need to set only the number of stages you want to use. DirectX ignores the remaining (disabled) stages. If an application uses different numbers of stages over time, you can simply disable the first unused stage to prevent Direct3D from applying stages with a higher index.

A blending stage is associated with each texture in the current texture set. The IDirect3DDevice7::SetTextureStageState method controls what information from a particular texture stage gets used. You can set color channel operations by using the D3DTSS_COLOROP stage state. The texture-blending arguments use the D3DTSS_COLORARG1, D3DTSS_COLORARG2, D3DTSS_ALPHARG1, and D3DTSS_ALPHARG2 members of the D3DTEXTURESTAGESTATETYPE enumerated type.

An example of single-pass multitexturing follows.

 D3DTextr_RestoreAllTextures( m_pd3dDevice );     m_pd3dDevice->SetTexture( 0, D3DTextr_GetSurface("tex1.bmp") );     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1,                                         D3DTA_TEXTURE );     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2,                                         D3DTA_DIFFUSE );     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP,                                         D3DTOP_MODULATE );     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MINFILTER,                                         D3DTFN_LINEAR );     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER,                                         D3DTFG_LINEAR ); 

You can also set alpha channel operations (Chapter 10 covers alpha blending) using the D3DTSS_ALPHAOP stage state. The following code segment sets up the base texture in a set of textures to be blended.

 // Stage 0: The base texture     m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP,                                        D3DTOP_MODULATE);     m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1,                                        D3DTA_TEXTURE);     m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2,                                        D3DTA_DIFFUSE);     m_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP,                                        D3DTOP_SELECTARG1);     m_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1,                                        D3DTA_TEXTURE);      m_pd3dDevice->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 1); 

To assign textures to the set of current textures, use the IDirect3DDevice7::SetTexture method. This method takes a value from 0 to 7 as the first argument, indicating the texture stage number, and takes the texture interface pointer as the second parameter. You should be aware that software devices don't support assigning the same texture to more than one stage at a time. This code assigns a texture to texture stage 0:

 m_pd3dDevice->SetTexture( 0,     D3DTextr_GetSurface("..\\Textures\\Cloud3.bmp") ); m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, D3DFVF_TLVERTEX,                              m_pBackground, 4, 0 ); 

Setting Up Texture Stages

The following code shows how to set up a texture stage. The code calls the IDirect3DDevice7::SetTextureStageState method three times. The first call defines the operation that will be performed. The second and third calls set the arguments for the operation the first call specifies.

 // // Set texture render states.     // Set texture stage 0 to modulate the texture with the diffuse  // color, and to use point sampling and no mipmapping. m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP,                                     D3DTOP_MODULATE ); m_pd3dDevice->SetTextureStageState( 0,     // The first texture                          D3DTSS_COLORARG1, // Set the color arg1.                          D3DTA_TEXTURE );  // Color arg1 value m_pd3dDevice->SetTextureStageState( 0,     // The first texture                          D3DTSS_COLORARG2, // Set the color arg2.                          D3DTA_DIFFUSE);   // Color arg2 value m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MINFILTER,                                     D3DTFN_POINT);  m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER,                                     D3DTFG_POINT); m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MIPFILTER,                                     D3DTFP_NONE ); 

The following code example shows how to apply multiple-texture blending to an application:

 // Set up the texture stages. (You don't need to do this // every frame.) m_pd3dDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0 ); m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1,                                     D3DTA_TEXTURE ); m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP,                                     D3DTOP_MODULATE ); m_pd3dDevice->SetTextureStageState( 1, D3DTSS_TEXCOORDINDEX, 1 ); m_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLORARG1,                                     D3DTA_TEXTURE ); m_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLORARG2,                                     D3DTA_CURRENT );  m_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLOROP,                                     D3DTOP_MODULATE ); m_WallData.textureCoords[0].lpvData  =                     &m_avWallVertices[0].tuBase; m_WallData.textureCoords[1].lpvData  =                     &m_avWallVertices[0].tuLightMap; // Draw the walls in multitexture mode. m_pd3dDevice->SetTexture( 0, D3DTextr_GetSurface("wall.bmp") ); m_pd3dDevice->SetTexture( 1, D3DTextr_GetSurface("lightmap.bmp") ); m_pd3dDevice->DrawPrimitiveStrided( D3DPT_TRIANGLELIST,                                     D3DFVF_XYZ | D3DFVF_DIFFUSE |                                     D3DFVF_TEX2,                                     &m_WallData, 24, NULL ); // Draw the floor in single-texture mode. m_pd3dDevice->SetTexture( 0, D3DTextr_GetSurface("floor.bmp") ); m_pd3dDevice->SetTexture( 1, NULL ); m_pd3dDevice->DrawPrimitiveStrided( D3DPT_TRIANGLELIST,                                     D3DFVF_XYZ | D3DFVF_DIFFUSE |                                     D3DFVF_TEX2,                                     &m_FloorCielData, 12, NULL ); // Restore state. m_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLOROP,                                     D3DTOP_DISABLE ); 

Bump Mapping

Bump mapping is a texture-blending method that creates the appearance of a complex texture on primitives. Although standard texture blending works well for smooth surfaces such as a wood floor, it can't model realistic rough surfaces. Bump mapping provides a texture that contains depth information (tessellation) in the form of values indicating high and low spots on the surface. Bump mapping creates a per-pixel texture coordinate perturbation of specular or diffuse environment maps by taking your specification of the bump map contour using delta values. These are applied to the u and v texture coordinates of an environment map in the next texture stage. These delta values are encoded in the pixel format of the bump map surface.

You can store the contour information in any format you desire (or use approaches such as a procedural bump map). You can apply a bump map to a texture using texture stages. To use bump mapping, set the texture-blending operation of the texture stage that contains the bump map to D3DTOP_BUMP. Using at least three texture-blending stages, you apply the base texture, the bump map, and the environment map in the texture-blending cascade.

A bump map is a DirectDraw surface that uses a pixel format in which each pixel stores the delta values for u and v (Du and Dv) and sometimes a luminance value (rather than RGB values). You can enumerate the bump map pixel formats by using the IDirect3DDevice7::EnumTextureFormats method. The following code is a routine from the Direct3D documentation that determines which devices support bump mapping:

 BOOL SupportsBumpMapping()  {     DDPIXELFORMAT ddpfBumpMap;     D3DDEVICEDESC7 d3dDevDesc;     ZeroMemory( &d3dDevDesc, sizeof(d3dDevDesc) );     // Get the device capabilities.     m_pd3dDevice->GetCaps( &d3dDevDesc );     // Does this device support the two bump mapping blend operations?     DWORD dwBumpOps = d3dDevDesc.dwTextureOpCaps &                        (D3DTEXOPCAPS_BUMPENVMAP |                         D3DTEXOPCAPS_BUMPENVMAPLUMINANCE);     if ( 0 == dwBumpOps)         return FALSE;     // Does this device support up to three blending stages?     if( d3dDevDesc.wMaxTextureBlendStages < 3)         return FALSE;     //     // Check for valid bump map pixel formats.     //     // The g_bFoundBumpFormat global variable will be set to TRUE      // by the callback function if a valid format is found.     g_bFoundBumpFormat = FALSE;       m_pd3dDevice->EnumTextureFormats(TextureCallback,                                      (LPVOID) &ddpfBumpMap);     if( FALSE == g_bFoundBumpFormat )         return FALSE;     // The pixel format now in ddpfBumpMap can be used to create      // a surface format that's guaranteed to be valid.     return TRUE; } 

The following routine is an example callback function defined to be passed to the IDirect3DDevice7::EnumTextureFormats method:

 HRESULT CALLBACK TextureCallback( DDPIXELFORMAT* pddpf,                                   VOID* pddpfOut) {     // Take the first enumerated DuDv format.     if( DDPF_BUMPDUDV == pddpf->dwFlags ){         // Copy the format into the variable at pddpfOut          // for use when creating the surface later.         memcpy( pddpfOut, (LPVOID)pddpf, sizeof(DDPIXELFORMAT) );         // Set the global flag to signal success.         g_bFoundBumpFormat = TRUE;         return D3DENUMRET_CANCEL;     }     return D3DENUMRET_OK; } 

This code verifies that the device supports either the D3DTOP_BUMPENVMAP or D3DTOP_BUMPENVMAPLUMINANCE texture-blending operation. It also makes sure that the device supports at least three texture-blending stages and exposes at least one bump mapping pixel format.

Direct3D uses the following formulas and applies them to the Du and Dv components in each bump map pixel:

You can specify the bump map pixel format by using a DDPIXELFORMAT structure. The DDPF_BUMPDUDV flag in the dwFlags member specifies a pixel format for a bump map texture. If this flag is set, the dwBumpBitCount, dwBumpDuBitMask, dwBumpDvBitMask, and dwBumpLuminanceBitMask members are used to specify a bit depth for the bump map and the mask values for each pixel component.

The Du and Dv components of the pixel may range from -1.0 through 1.0, and the luminance component can be from 0 through 255 (if you use it). The Du and Dv values are taken from the bump map pixel and transformed by a 2 × 2 matrix to create the output delta values Du' and Dv'. Direct3D uses these values to modify the texture coordinates that address the environment map in the next texture stage. You set the coefficients of the transformation matrix using the D3DTSS_BUMPENVMAT01 through D3DTSS_BUMPENVMAT11 texture stage states. Direct3D also computes the luminance value, which is used to modulate the color of the environment map in the next blending stage, as follows:

where

 L' = Computed output luminance L  = Luminance value from the bump map pixel S  = The scaling factor the luminance value is multiplied by O  = The offset value 

The D3DTSS_BUMPENVLSCALE and D3DTSS_BUMPENVLOFFSET texture stage states control the values of the S and O values. This formula will be applied when the texture-blending operation for the stage containing the bump map is set to D3DTOP_BUMPENVMAPLUMINANCE. If you instead use D3DTOP_BUMPENVMAP, Direct3D will use a value of 1.0 for L'.

Once the output delta values Du' and Dv' are computed, they are added to the texture coordinates in the next texture stage and Direct3D modulates the selected color by the luminance to compute the color to apply to the polygon.

This code shows how to set up a texture stage for bump mapping. The code first sets the color-blending operations and arguments for each stage as well as the base texture map. It then determines whether you have textures turned on, and if you do, it loads the main texture (labeled STEP 1). In STEP 2, it determines whether you've requested bump mapping. If you have, it sets the bump map texture as the second texture. Finally, in STEP 3, if environment mapping is on, you set the specular environment map texture.

 HRESULT CMyD3DApplication::Render() {     m_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET,                          0x00000000, 1.0f, 0L );     if( FAILED( m_pd3dDevice->BeginScene() ) )         return S_OK; // Don't return a "fatal" error.     m_pd3dDevice->SetRenderState(D3DRENDERSTATE_WRAP0,                                  D3DWRAP_U | D3DWRAP_V );     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP,                                         D3DTOP_MODULATE );     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1,                                         D3DTA_TEXTURE );     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2,                                         D3DTA_DIFFUSE );     m_pd3dDevice->SetTextureStageState( 0,D3DTSS_ALPHAOP,                                         D3DTOP_SELECTARG1 );     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1,                                         D3DTA_TEXTURE );     m_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLOROP,                                         D3DTOP_DISABLE );     // STEP 1     if( m_bTextureOn )         m_pd3dDevice->SetTexture( 0,                           D3DTextr_GetSurface( "earth.bmp" ) );     else         m_pd3dDevice->SetTexture( 0,                           D3DTextr_GetSurface( "block.bmp" ) );          m_pd3dDevice->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 1 );     m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP,                                        D3DTOP_SELECTARG1);     m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1,                                        D3DTA_TEXTURE );     m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2,                                        D3DTA_DIFFUSE );     // STEP 2     if( m_bBumpMapOn )     {         m_pd3dDevice->SetTexture( 1, m_pddsBumpMap );         m_pd3dDevice->SetTextureStageState( 1,                                         D3DTSS_TEXCOORDINDEX, 1 );         m_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLOROP,                                          D3DTOP_BUMPENVMAPLUMINANCE );         m_pd3dDevice->SetTextureStageState(1,D3DTSS_COLORARG1,                                         D3DTA_TEXTURE );         m_pd3dDevice->SetTextureStageState(1,D3DTSS_COLORARG2,                                         D3DTA_CURRENT );         m_pd3dDevice->SetTextureStageState(1,D3DTSS_BUMPENVMAT00,                                         F2DW(0.5f) );         m_pd3dDevice->SetTextureStageState(1,D3DTSS_BUMPENVMAT01,                                         F2DW(0.0f) );         m_pd3dDevice->SetTextureStageState(1,D3DTSS_BUMPENVMAT10,                                         F2DW(0.0f) );         m_pd3dDevice->SetTextureStageState(1,D3DTSS_BUMPENVMAT11,                                         F2DW(0.5f) );         m_pd3dDevice->SetTextureStageState(1,D3DTSS_BUMPENVLSCALE,                                         F2DW(1.0f));         m_pd3dDevice->SetTextureStageState(1,D3DTSS_BUMPENVLOFFSET,                                         F2DW(0.0f) );         // STEP 3         if( m_bEnvMapOn )         {             m_pd3dDevice->SetTexture( 2,                      D3DTextr_GetSurface( "EarthEnvMap.bmp" ) );             m_pd3dDevice->SetTextureStageState( 2,                     D3DTSS_TEXCOORDINDEX, 0 );             m_pd3dDevice->SetTextureStageState(2,                     D3DTSS_COLOROP, D3DTOP_ADD );             m_pd3dDevice->SetTextureStageState(2,                     D3DTSS_COLORARG1, D3DTA_TEXTURE);             m_pd3dDevice->SetTextureStageState( 2,                     D3DTSS_COLORARG2, D3DTA_CURRENT );         }         else             m_pd3dDevice->SetTextureStageState( 2,                     D3DTSS_COLOROP, D3DTOP_DISABLE );     }     else     {         if( m_bEnvMapOn )         {             m_pd3dDevice->SetTexture( 1,                      D3DTextr_GetSurface( "EarthEnvMap.bmp" ) );             m_pd3dDevice->SetTextureStageState(1,                     D3DTSS_TEXCOORDINDEX, 0 );             m_pd3dDevice->SetTextureStageState(1,                     D3DTSS_COLOROP, D3DTOP_ADD );             m_pd3dDevice->SetTextureStageState(1,                     D3DTSS_COLORARG1, D3DTA_TEXTURE );             m_pd3dDevice->SetTextureStageState(1,                     D3DTSS_COLORARG2, D3DTA_CURRENT );         }         else             m_pd3dDevice->SetTextureStageState( 1,                     D3DTSS_COLOROP, D3DTOP_DISABLE );                  m_pd3dDevice->SetTextureStageState(2,                 D3DTSS_COLOROP, D3DTOP_DISABLE );     }     m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP,                             D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX2,                             m_pSphereVertices, m_dwNumSphereVertices,                             0x0 );     m_pd3dDevice->EndScene();     return S_OK; } 

With the bump mapping parameters configured, you can render your objects and the bump mapping effects will be applied.



Inside Direct3D
Inside Direct3D (Dv-Mps Inside)
ISBN: 0735606137
EAN: 2147483647
Year: 1999
Pages: 131

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net