Click to Rate and Give Feedback
MSDN
MSDN Library

  Switch on low bandwidth view
Driving DirectX
Exploring D3DX, Part 2: Textures
 

Philip Taylor
Microsoft Corporation

August 30, 2002

Summary: Philip Taylor continues to illustrate the usefulness of D3DX, turning to the various forms of texture support provided by the Microsoft Direct3D utility library, including mipmapped texture support, cube-map support, volume-texture support, bump-mapping support, and more. (17 printed pages)


Welcome back to our discussion of D3DX, the Microsoft® Direct3D® utility library, continuing from last month. Now it's time to look at the texture services provided by D3DX, drilling down into the range of texture support in D3DX. This includes:

  • Texture-requirements checking
  • Mipmapped texture support
  • Cube-map support
  • Volume-texture support
  • Bump-mapping support
  • Render-target support

I have slightly revised this ordering from last month's, in that I now group the ID3DXRenderToSurface interface and the ID3DXRenderToEnvmap interface support under "Render-Target Support." That's the primary usage of both interfaces, and makes more sense than having separate "Environment mapping" and "D3DX Render Target" sections. Treating them together further illuminates their value.

I won't cover every texturing function in D3DX; instead I will limit myself mainly to functions that the samples use, so I can show a sample invocation everyone can examine. In a few select cases, I will deviate from that plan and show functions that aren't used in the SDK, but that will be the exception. When the function is used in the SDK, I will call out what sample the code snippet is from.

Texture-Requirements Checking

D3DXCheckTextureRequirements, D3DXCheckCubeTextureRequirements, and D3DXCheckVolumeTextureRequirements enable probing on whether a particular combination of mipmap texture, cube-map texture, or volume-texture settings can be created on a device instance.

One way to use this is to get the format for a particular image by using D3DXGetImageInfoFrom file as follows:

D3DIMAGE_INFO info
hr = D3DXGetImageInfoFromFile(tcsFileName, &info);
D3DFORMAT d3dfmt = info.Format

And then use that to direct the invocation of D3DXCheckTextureRequirements as follows:

hr = D3DXCheckTextureRequirements(device, &width, &height,& miplevels,
D3DUSAGE_RENDERTARGET,&d3dfmt,D3DPOOL_DEFAULT);

Also very useful is the fact that the return parameters are adjusted in the case of failure. Indeed the documentation for D3DXCreateTexture states:

Internally, D3DXCreateTexture uses D3DXCheckTextureRequirements to adjust the calling parameters. Therefore, calls to D3DXCreateTexture will often succeed where calls to IDirect3DDevice8::CreateTexture would fail.

Similarly, one would call D3DXCheckCubeTextureRequirements as follows:

hr = D3DXCheckCubeTextureRequirements(&edgeSize, 
&miplevels, 
usage, &d3dfmt, pool);

And one would call D3DXCheckVolumeTextureRequirements as:

hr = D3DXCheckVolumeTextureRequirements(&width, &height,
    &depth, &miplevels, 
usage, &d3dfmt, pool);

Especially since these functions return updated parameters if the call fails—a "smart" probing if you will—they are highly useful utility routines.

Mipmapped Texture Support

IDirect3DTexture8 provides the fundamental support for standard mipmapped textures. Just about every Direct3D sample in the SDK uses mipmapped textures, except for the specialized CubeMap and volume-texture samples (more about those in a bit). D3DX support includes helpers for basic operations, like creating empty textures, loading textures, saving textures, filtering, and procedural generation. Let's examine code snippets for each of these operations.

Empty Creation

Sometimes you just want an "empty" texture, one with un-initialized bits, whether you are going to procedurally generate the bits, manage the loading process manually, or for some other perfectly valid reason. D3D supports this with the D3DXCreateTexture function. The prototype for this function is:

HRESULT D3DXCreateTexture(LPDIRECT3DDEVICE8 pDevice,
  UINT Width, Height, MipLevels,
  DWORD Usage, D3DFORMAT Format, D3DPOOL Pool,
  LPDIRECT3DTEXTURE8* ppTexture);

The function takes the device to create the texture on, the required width and height, the number of mip levels requested, and the behavioral usage, texture format, and memory pool. A pointer to a LPDIRECT3DTEXTURE8 is returned.

A sample invocation, from the Water sample, looks like:

if(FAILED(hr = D3DXCreateTexture(m_pd3dDevice, 
WATER_CAUSTICS_SIZE, WATER_CAUSTICS_SIZE, 1, 
D3DUSAGE_RENDERTARGET, mode.Format, D3DPOOL_DEFAULT,
&m_pCausticTex)) 

Loading from Resources

Creating a texture from a resource is perhaps the very next operation a programmer requires, D3DXCreateTextureFromResourceEx provides this functionality, and the function prototype for it is:

HRESULT D3DXCreateTextureFromResourceEx(LPDIRECT3DDEVICE8 pDevice,
  HMODULE hSrcModule,  LPCTSTR pSrcResource,
  UINT Width, Height, UINT MipLevels,
  DWORD Usage, D3DFORMAT Format,D3DPOOL Pool,
  DWORD Filter,DWORD MipFilter,
  D3DCOLOR ColorKey,D3DXIMAGE_INFO* pSrcInfo,PALETTEENTRY* pPalette,
  LPDIRECT3DTEXTURE8* ppTexture);

The function takes the device to create the texture on, as well as the HMODULE handle and a string identifying the desired resource. As with the empty texture creation function, the required width and height, the number of mip levels requested, and the behavioral usage, texture format, and memory pool are passed in. So is an optional ColorKey, D3DXIMAGE_INFO pointer, and a pointer to an array of PALETTEENTRY's. A pointer to a LPDIRECT3DTEXTURE8 is returned.

A sample invocation, from the DirectPlay Maze sample, looks like:

if( FAILED( D3DXCreateTextureFromResourceEx( m_pd3dDevice, NULL, 
                     MAKEINTRESOURCE( nResource ), 
                     D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 
                     0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, 
                     D3DX_FILTER_TRIANGLE|D3DX_FILTER_MIRROR, 
                     D3DX_FILTER_TRIANGLE|D3DX_FILTER_MIRROR, 
                     0xFF000000, NULL, NULL, 
                     ppTexture ) ) )

Loading from Files

Storing textures in the resource file is an easy and acceptable solution for simple examples, but in general, loading from a separate disk file is much more useful. D3DXCreateTextureFromFile provides this functionality in the basic edition, and the function prototype for it is:

HRESULT D3DXCreateTextureFromFile(LPDIRECT3DDEVICE8 pDevice,
  LPCTSTR pSrcFile,
  LPDIRECT3DTEXTURE8* ppTexture);

The function takes the device to create the texture on and the source file name. A pointer to a LPDIRECT3DTEXTURE8 is returned.

A sample invocation, from the SDK tutorial #5, looks like this:

// Use D3DX to create a texture from a file based image
if( FAILED( D3DXCreateTextureFromFile( g_pd3dDevice, "banana.bmp",
                                       &g_pTexture ) ) )

That's the basic edition. The D3DXCreateTextureFromFileEx function provides the "extended" functionality function (hence the "Ex"), and the function prototype for it is:

HRESULT D3DXCreateTextureFromFileEx(LPDIRECT3DDEVICE8 pDevice, 
  LPCTSTR pSrcFile,
  UINT Width, UINT Height, MipLevels,
  DWORD Usage, D3DFORMAT Format, D3DPOOL Pool,
  DWORD Filter, DWORD MipFilter,
  D3DCOLOR ColorKey,  D3DXIMAGE_INFO* pSrcInfo, PALETTEENTRY* pPalette,
  LPDIRECT3DTEXTURE8* ppTexture);

The function takes the device to create the texture on and the source file name. As with the other extended texture creation functions, the required width and height, the number of mip levels requested, and the behavioral usage, texture format, and memory pool are passed in—so is an optional ColorKey, D3DXIMAGE_INFO pointer, and a pointer to an array of PALETTEENTRY's. A pointer to a LPDIRECT3DTEXTURE8 is returned.

A sample invocation, from the SDK sample, Water, looks like this:

DXUtil_FindMediaFile(sz, _T("Water.bmp"));
D3DXCreateTextureFromFileEx(m_pd3dDevice, sz, 
        D3DX_DEFAULT, D3DX_DEFAULT, 
        D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, 
        D3DX_DEFAULT, 0, NULL, NULL, &m_pFloorTex); 

A pattern should be emerging, with the basic function exposing the bare minimum of parameters and the "Ex" extended function exposing full parameter control over the texture loading.

Loading from Memory

When converting from authoring formats to rendering formats, it's often useful to create textures from memory blocks. This is precisely the functionality provided by D3DXCreateTextureFromFileInMemory and D3DXCreateTextureFromFileInMemoryEx—to enable the feature of loading from memory blocks.

The prototype for D3DXCreateTextureFromFileInMemory is as follows:

HRESULT D3DXCreateTextureFromFileInMemory(LPDIRECT3DDEVICE8 pDevice,
  LPCVOID pSrcData,
  UINT SrcData,
  LPDIRECT3DTEXTURE8* ppTexture);

This function takes a source data pointer and a source data size, as well as the device parameter, and returns a pointer to the a LPDIRECT3DTEXTURE8 object. While none of the SDK samples use D3DXCreateTextureFromFileInMemory, it turns out that the Worldcraft level editor does make use of this function. Below I show one sample usage of this function.

struct Models; 
struct filesinfo;
byte *data; 
filesinfo* fi;
D3DXCreateTextureFromFileInMemory(lpD3D_Dev, 
data+fi[f].fileofs, fi[f].filelen, 
&Models.Model[x].mesh.Textures[y]);

The prototype for D3DXCreateTextureFromFileInMemoryEx is as follows:

HRESULT D3DXCreateTextureFromFileInMemoryEx(LPDIRECT3DDEVICE8 pDevice,
  LPCVOID pSrcData, SrcData,
  UINT Width, UINT Height, UINT MipLevels,
  DWORD Usage, D3DFORMAT Format, D3DPOOL Pool,
  DWORD Filter, DWORD MipFilter,
  D3DCOLOR ColorKey, D3DXIMAGE_INFO* pSrcInfo,PALETTEENTRY* pPalette,
  LPDIRECT3DTEXTURE8* ppTexture);

This function takes a source data pointer and a source data size, as well as the usual "Ex" parameters of Width, Height, MipLevels, Usage, Format, Pool, Filter and MipFilter, ColorKey, source image info, and an array of PALETTEENTRY's making an optional palette. The function returns a pointer to the LPDIRECT3DTEXTURE8 object. The SDK sample screensaver uses this function to load from a custom resource once the resource is retrieved from the resource fork and loaded into memory. Below I show one sample usage of this function.

HRESULT hr;
HMODULE hModule = NULL;
HRSRC rsrc;
HGLOBAL hgData;
LPVOID pvData;
DWORD cbData;

rsrc = FindResource( hModule, strRes, "DDS" );
if( rsrc != NULL )
{
    cbData = SizeofResource( hModule, rsrc );
    if( cbData > 0 )
    {
        hgData = LoadResource( hModule, rsrc );
        if( hgData != NULL )
        {
            pvData = LockResource( hgData );
            if( pvData != NULL )
            {
                if(FAILED(hr = D3DXCreateTextureFromFileInMemoryEx( 
                    m_pd3dDevice, pvData, cbData, 
                    D3DX_DEFAULT, D3DX_DEFAULT, 
                    1, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, 
                    D3DX_FILTER_NONE, D3DX_FILTER_NONE, 
                    0, NULL, NULL, 
                    ppTex ) ) )

Saving

Saving a texture to a file is supported for .dds compressed textures and .bmp, Microsoft Windows® bitmap formats. Both a single-surface save and a mipmap-texture save are provided. The function prototype for the mipmap texture save is as follows:

HRESULT D3DXSaveTextureToFile(LPCTSTR                  pDestFile,
  D3DXIMAGE_FILEFORMAT     DestFormat,
  LPDIRECT3DBASETEXTURE8   pSrcTexture,
  CONST PALETTEENTRY*      pSrcPalette);

This function takes a file name, the format, the source texture, and an optional palette. The SDK sample, DXTex, uses this function to save textures. Below I show one sample usage of this function.

//sdk tool dxtex
if( FAILED( D3DXSaveTextureToFile( lpszPathName, D3DXIFF_DDS, 
                                   ptex, NULL ) ) )

Filtering

D3DX also provides the ability to filter a texture, using point, linear, triangle, or box filters, to generate mip levels "on-the-fly" using D3DXFilterTexture. The function prototype is as follows:

HRESULT D3DXFilterTexture(LPDIRECT3DTEXTURE8 pTexture,
  CONST PALETTEENTRY* pPalette,
  UINT SrcLevel,DWORD MipFilter);

The SDK sample, BumpSelfShadow, uses this function. Here is a sample invocation:

//sdk sample bumpselfshadow
if(FAILED(hr = D3DXFilterTexture( m_pHorizonTextures[0], NULL,0, 
    D3DX_FILTER_BOX)))

Procedural Generation

Procedural texture generation is an extremely useful technique, and is supported in D3DX by the D3DXFill* functions. For mipmapped textures, the D3DXFillTexture function provides this functionality, and its prototype is:

HRESULT D3DXFillTexture( LPDIRECT3DTEXTURE8 pTexture,
  LPD3DXFILL2D       pFunction,
  LPVOID             pData);

This function takes a function pointer, of type:

VOID (*LPD3DXFILL2D)(
  D3DXVECTOR4* pOut,
  D3DXVECTOR2* pTexCoord,
  D3DXVECTOR2* pTexelSize,
  LPVOID       pData); 

This is called by the runtime to generate each pixel. The MSDN Shader Workshop sample uses this function as follows:

//fresnel evaluation
void FresnelEval(D3DXVECTOR4 *col,D3DXVECTOR2 *input,
                  D3DXVECTOR2 *sampSize, void *pRefIndex)
{
    col->x = .5; 
    col->y = 1;
    col->z = .5;
    float vec = input->x*2-1;
    vec = (float) fabs(vec);
    col->w =   D3DXFresnelTerm(vec,*((float*)pRefIndex));
}
hr = D3DXFillTexture(m_pFresnelShaderTexture,FresnelEval,&fRefIndex);

So generating your own textures is that easy.

Cube-Map Texture Support

IDirect3DCubeTexture8 provides the fundamental support for cubic environment map textures. Cubic environment map textures are extremely useful in creating realistic environment mapped reflections. Because they are comprised of the 6 faces of a cube, they contain an accurate rendition of the surrounding environment. The SDK samples, CubeMap, FishEye, Water, and the SDK tool, DXTex, all use cube-map textures. So does the MSDN Shader Workshop sample. D3DX support includes helpers for basic operations like creating empty cube-map textures, loading cube-map textures from existing data, filtering cube-map textures, and procedural generation of the data in each face of a cube-map texture. Let's examine code snippets for each of these operations.

Empty Creation

For the case where you need just an empty cube-map texture, D3DX provides the D3DXCreateCubeTexture function. Similar to the mipmap texture function, D3DXCreateCubeTexture's prototype is:

HRESULT D3DXCreateCubeTexture( LPDIRECT3DDEVICE8 pDevice,
  UINT Size,UINT MipLevels,
  DWORD Usage, D3DFORMAT Format, Pool,
  LPDIRECT3DCUBETEXTURE8* ppCubeTexture );

Here the parameters besides the device are the size of an edge, the number of mip levels, the Usage, Format, and Pool—and an LPDIRECT3DCUBETEXTURE8 is returned. The SDK sample, Water, provides a usage example to create an empty cube-map texture:

if (SUCCEEDED(D3DXCreateCubeTexture(m_pd3dDevice, 128, 
D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, 
&m_pSkyCubeTex)))

Procedural generation and usage as a rendertarget are two ways an empty cube map can be initialized.

Loading from Files

Basic loading of a cube-map texture from a file is performed by D3DXCreateCubeTextureFromFile. Its prototype is:

HRESULT D3DXCreateCubeTextureFromFile(LPDIRECT3DDEVICE8 pDevice,
  LPCTSTR pSrcFile,
  LPDIRECT3DCUBETEXTURE8* ppCubeTexture);

This function takes just the device and a file name, and returns the LPDIRECT3DCUBETEXTURE8 interface. The MSDN Shader Workshop sample provides an example usage:

hr = D3DXCreateCubeTextureFromFile(m_pd3dDevice,FilePath,&m_pEnvMap);

The extended cube-map file loading function, D3DXCreateCubeTextureFromFileEx has the following prototype:

HRESULT D3DXCreateCubeTextureFromFileEx(LPDIRECT3DDEVICE8 pDevice,
  LPCTSTR pSrcFile,UINT Size,UINT MipLevels,
  DWORD Usage,D3DFORMAT Format,D3DPOOL Pool,
  DWORD Filter,DWORD MipFilter,
  D3DCOLOR ColorKey,D3DXIMAGE_INFO* pSrcInfo,PALETTEENTRY* pPalette,
  LPDIRECT3DCUBETEXTURE8* ppCubeTexture);

This function takes the ubiquitous device and file name, and the edge size, the MipLevels, the Usage, Format, and Pool, the Filter and MipFilter settings, and an optional ColorKey, source image data pointer, and palette pointer, and returns the LPDIRECT3DCUBETEXTURE8 interface. The SDK tool, Dxtex, provides an example usage:

//sdk tool dxtex
if( FAILED( D3DXCreateCubeTextureFromFileEx( pd3ddev, lpszPathName, 
imageinfo.Width, imageinfo.MipLevels, 0, 
imageinfo.Format, D3DPOOL_MANAGED, 
D3DX_FILTER_NONE, D3DX_FILTER_NONE, 
0, &imageinfo2, NULL,     
(LPDIRECT3DCUBETEXTURE8*)&m_ptexOrig ) ) )

I am skipping the "from memory" and "from resource" versions of these cube-map loaders. The pattern should be familiar by now, and with this information, you should easily be able to extend your reach to use those functions as well.

Filtering

The SDK documentation states:

The D3DXFilterTexture function combines the functionality of D3DXFilterCubeTexture and D3DXFilterVolumeTexture, making these functions obsolete.

Nevertheless, if you actually take the time to read the headers, then you find that D3DXFilterCubeTexture is simply a #define to D3DXFilterTexture, as follows:

#define D3DXFilterCubeTexture D3DXFilterTexture

The SDK doc is perhaps a little terse, preferring to use this name to make it a bit easier to read the intent of the code as far as determining when the use of this function is acceptable. The SDK sample, Water, does use the #define, as follows:

D3DXFilterCubeTexture(m_pSkyCubeTex, NULL, 0, D3DX_DEFAULT);

On to procedurally generating our cube-map textures...

Procedural Generation

D3DX provides function D3DXFillCubeTexture to generate the bits in the cube map programmatically. This function uses the same function pointer signature for its function pointer parameter as D3DXFillTexture did. The function prototype is:

HRESULT D3DXFillCubeTexture( LPDIRECT3DCUBETEXTURE8 pTexture,
  LPD3DXFILL3D           pFunction,
  LPVOID                 pData);

The MSDN Shader Workshop sample also provides an example usage of this function:

//specular light lookup table
void LightEval(D3DXVECTOR4 *col,D3DXVECTOR2 *input,
               D3DXVECTOR2 *sampSize,void *pfPower)
{
    float fPower = (float) pow(input->y,*((float*)pfPower));
    col->x = fPower;
    col->y = fPower;
    col->z = fPower;
    col->w = input->x;
}
hr = D3DXFillCubeTexture(m_pSatinMap2,LineLightEval,&fPower);

On to volume textures...

Volume-Texture Support

IDirect3DVolumeTexture8 provides the fundamental support for volume textures. Volume textures, or 3-D textures, are extremely useful in creating realistic fog, explosions, or any other effect that requires depth. They substitute texture complexity (read memory) for geometric complexity. Programmers should take care because volume-texture memory requirements add up quickly. The SDK sample, VolumeTexture, and the SDK tool, DXTex, both use volume textures. D3DX support includes helpers for basic operations like creating empty textures, loading textures, saving textures, filtering, and procedural generation. Let's examine code snippets for each of these operations.

Empty Creation

D3DX provides the D3DXCreateVolumeTexture to enable creating empty textures. The function prototype, shown below, adds the depth parameter required for a 3-D texture, but is otherwise similar to the mipmap function.

HRESULT D3DXCreateVolumeTexture(LPDIRECT3DDEVICE8 pDevice,
  UINT Width, UINT Height, UINT Depth, UINT MipLevels,
  DWORD Usage, D3DFORMAT Format, D3DPOOL Pool,
  LPDIRECT3DVOLUMETEXTURE8* ppVolumeTexture);

Unfortunately, no example exists in the SDK, but it should be pretty easy to imagine calling it with a depth value to give a WxHxD 3-D texture, instead of a WxH 2-D mipmapped texture.

Loading from Files

While the basic volume-texture loading from file D3DX function, D3DXCreateVolumeTextureFromFile, does not have an example in the SDK, the "Ex" or extended version D3DXCreateVolumeTextureFromFileEx does. Its prototype is:

HRESULT D3DXCreateVolumeTextureFromFileEx(LPDIRECT3DDEVICE8 pDevice, 
  LPCTSTR pSrcFile,UINT Width, UINT  Height, UINT MipLevels,
  DWORD Usage,D3DFORMAT Format,D3DPOOL Pool,
  DWORD Filter, DWORD MipFilter,
  D3DCOLOR ColorKey,D3DXIMAGE_INFO* pSrcInfo,PALETTEENTRY* pPalette,
  LPDIRECT3DVOLUMETEXTURE8* ppVolumeTexture);

And the SDK tool, DXTex, calls it as follows:

if( FAILED( D3DXCreateVolumeTextureFromFileEx( pd3ddev, lpszPathName, 
                  imageinfo.Width, imageinfo.Height, imageinfo.Depth, 
                  imageinfo.MipLevels,0, imageinfo.Format, 
                  D3DPOOL_MANAGED, D3DX_FILTER_NONE, D3DX_FILTER_NONE,
                  0, &imageinfo2, NULL, 
                  (LPDIRECT3DVOLUMETEXTURE8*)&m_ptexOrig ) ) )

Filtering

As with the cube-map texture filter routine, D3DXFilterCubeTexture, D3DXFilterVolumeTexture is also a #define, as follows:

#define D3DXFilterVolumeTexture D3DXFilterTexture 

It should be obvious how to use it, so I won't spend any time on it here.

Procedural Generation

Procedurally generating volume textures is handled in a manner parallel to the mipmap texture and cube-map texture procedural generation, by invoking a D3DXFill* function with a function pointer to the generation function. For volume textures, D3DXFillVolumeTexture is the function, and its prototype is as follows:

HRESULT D3DXFillVolumeTexture(LPDIRECT3DVOLUMETEXTURE8 pVolumeTexture,
  LPD3DXFILL3D             pFunction,
  LPVOID                   pData);

Exactly the same function prototype is used for the generator function, so using D3DXFillVolumeTexture is identical to using the other functions. The runtime does all the work of invoking the generator function for each texel. There is no corresponding SDK example usage.

On to bumpmapping...

Bumpmapping

Let's examine two useful functions for bumpmapping, D3DXComputeNormalMap and D3DXComputeTangent. D3DXComputeNormalMap is used to convert a height map into a normal map. D3DXComputeTangent is used to generate a local tangent-space coordinate system.

The function prototype for D3DXComputeNormalMap is:

HRESULT D3DXComputeNormalMap(LPDIRECT3DTEXTURE8   pTexture,
  LPDIRECT3DTEXTURE8   pSrcTexture,CONST PALETTEENTRY*  pSrcPalette,
  DWORD  Flags, DWORD Channel,FLOAT Amplitude);

The function takes interface pointers for both the source height map texture and the destination normal map texture, flags that control how the map is converted, a channel value to identify what channel in the source height map to use in the conversion, and an amplitude value to optionally multiply the channel value. Note that this method computes the normal by using the central difference with a kernel size of 3×3. RGB channels in the destination contain biased (x,y,z) components of the normal. The MSDN Shader Workshop sample provides an example usage:

hr = D3DXComputeNormalMap(m_pNormalMap,m_pEmbossTexture,NULL,0,
                          D3DX_CHANNEL_RED,10.0f);//1.0f);

Since D3DXComputeTangent works on meshes, but returns information used for bumpmap lighting calculations, it is one of those "in-between" functions that is a mesh function that performs helper services for bumpmap pixel lighting. Its prototype is:

HRESULT D3DXComputeTangent(LPD3DXMESH InMesh,DWORD TexStage,
  LPD3DXMESH OutMesh,
  DWORD      TexStageUVec, TexStageVVec,
  DWORD      Wrap, DWORD*  pAdjacency); 

The function requires the input mesh and a stage from which to fetch input texture coordinate values, as well as an output mesh. In addition, separate control over which stage the output u and v are sent to is provided as well as parameters for wrap control and adjacency information Both the MSDN Shader Workshop sample and the SDK sample, BumpSelfShadow, use this function. An example usage is shown below:

//compute the tangent vectors in the texture space and load them into
//the 1'rd texture stage (which is 3d), read the texture coords from
//the 0th texture stage. Don't need the V direction vector since it 
//is assumed to be U x N.
hr = D3DXComputeTangent(pMeshSysMem,0,pMeshSysMem2,1, 
                        D3DX_COMP_TANGENT_NONE,TRUE,NULL);

Render-Target Support

D3DX provides additional support for render targets and cube maps. The ID3DXRenderToSurface interface encapsulates render-target creation for rendertargets, as the ID3DXRenderToEnvmap interface does for cubic environment maps. Once these interfaces have been created, the general usage pattern in every case is to invoke a Begin function, render, and invoke the End function. In the case of the cubic environment maps, that needs to be repeated for each of the 6 faces of the cube map. These interfaces also provide support for managing internal resources when dealing with losing and resetting the device.

Render to Surface

Render-to-surface support with D3DXCreateRenderToSurface enables the render-to-a-texture scenario, even on cards that don't directly support it. With this emulation support, which is provided at a good performance level, it's possible to consider using render-to-a-texture effects like rear-view mirrors, remote cameras, and TVs in applications that couldn't previously utilize this feature due to the lack of hardware coverage. Even though the SDK documentation lists this under "miscellaneous" functions, I consider this an extended part of the texture library. The function prototype is:

HRESULT D3DXCreateRenderToSurface(LPDIRECT3DDEVICE8 pDevice,
  UINT Width, Height,
  D3DFORMAT Format, BOOL DepthStencil, DepthStencilFormat,
  LPD3DXRENDERTOSURFACE* ppRenderToSurface);

Besides the ubiquitous device parameter, the Width and Height, surface format, and two-depth stencil parameters (if one exists, then its format) are passed in, and the ID3DXRenderToSurface interface is returned. The SDK sample, Water, provides an example usage:

if(FAILED(hr = D3DXCreateRenderToSurface(m_pd3dDevice, 
                             desc.Width, desc.Height, desc.Format, 
                             FALSE, D3DFMT_UNKNOWN, 
                             &m_pRenderToSurface)))

Once you have this interface, you invoke its BeginScene method, perform your rendering, and then invoke EndScene—all standard render-to-a-texture operations. Again, the SDK sample, Water, provides an illustrative example:

if(SUCCEEDED(m_pRenderToSurface->BeginScene(m_pCausticSurf, NULL)))
{
    D3DXMATRIX matProj;
    D3DXMATRIX matView;

    D3DXMatrixOrthoRH(&matProj, 63.0f, 63.0f, 1.0f, 100.0f);
    D3DXMatrixRotationX(&matView, 0.5f * D3DX_PI);
    matView._43 = -50.0f;

    m_pd3dDevice->SetTransform(D3DTS_PROJECTION, &matProj);
    m_pd3dDevice->SetTransform(D3DTS_VIEW, &matView);
    m_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, 0xff000000, 0.0f, 0);
    m_pd3dDevice->SetRenderState(D3DRS_ZENABLE, FALSE);
    m_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
    m_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
    m_Water.DrawCaustics();
    m_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
    m_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW);
    m_pd3dDevice->SetRenderState(D3DRS_ZENABLE, TRUE);
    m_pRenderToSurface->EndScene();
}

Render to Envmap

Render-to-environment-map support with D3DXCreateRenderToEnvMap enables the cube-map scenario, even on cards that don't directly support it. With this emulation support, which is provided at a good performance level, it's possible to consider using cube-map effects like the excellent reflection maps provided in applications that couldn't previously use this feature due to the lack of hardware coverage (except for more modern cards—the geForce2 generation and beyond). Even though the SDK documentation lists this under "miscellaneous" functions, I consider this an extended part of the texture library. The function prototype is:

HRESULT D3DXCreateRenderToEnvMap(LPDIRECT3DDEVICE8 pDevice,
  UINT Size, D3DFORMAT Format,
  BOOL DepthStencil,D3DFORMAT DepthStencilFormat,
  LPD3DXRenderToEnvMap* ppRenderToEnvMap );

Besides the ubiquitous device parameter, the edge size, the cube-map format, whether a depth-stencil buffer is attached, and what format the depth-stencil buffer is (if one is attached) are passed in, and an ID3DXRenderToEnvmap interface is returned. The SDK sample, Cubemap, uses this interface so that it will work on more hardware. Its usage looks like this:

if (SUCCEEDED((hr = D3DXCreateRenderToEnvMap(m_pSrcDevice,
                       cuiCubeEdgeLength, fmtEnvMapFormat, 
                       bCRTDSArgument, fmtCRTDSFArgument,
                       &pcd3dxrtem))))

One would then use this D3DX environment map construct as below, looping through each face, clearing, setting resources, and rendering:

for (uiFaceIndex = 0; uiFaceIndex < 6; ++uiFaceIndex)
{
// Call the Face method.  
//This should set the render target, depth stencil and viewport.
   if (SUCCEEDED((hr=pcd3dxrtem->Face((D3DCUBEMAP_FACES)uiFaceIndex))))
   { 
   m_pSrcDevice ->SetStreamSource(0, pd3dvb8Triangle,
                                     sizeof(MY_VB_ENTRY));
   m_pSrcDevice ->SetFVF(dwFVF);
   m_pSrcDevice ->Clear(0, NULL, D3DCLEAR_TARGET,
                  (D3DCOLOR(BackgroundColor[uiFaceIndex]),1.0,0);
   m_pSrcDevice -> DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);
   }
}

That follows from the render-target usage with a parallel construction for each face of the D3DX cube map, as expected.

With that, this all-too-brief coverage of the D3DX texture services concludes.

D3DX Last Word

As you can see, D3DX provides quite a bit of texture functionality. The remaining areas of D3DX will be covered in subsequent columns, so stay tuned.

I'd like to acknowledge the help of Craig Peeper, Todd Frost, and Rob Aldinger (Microsoft) in producing this column. Your feedback is welcome. Feel free to drop me a line at the address below with your comments, questions, topic ideas, or links to your own variations on topics the column covers. Please, though, don't expect an individual reply or send me support questions.

Remember, Microsoft maintains active mailing lists as forums for like-minded developers to share information:

DirectXAV for audio and video issues at http://DISCUSS.MICROSOFT.COM/archives/DIRECTXAV.html.

DirectXDev for graphics, networking, and input at http://DISCUSS.MICROSOFT.COM/archives/DIRECTXDEV.html.

 

Driving DirectX

Philip Taylor is the PM for the DirectX SDK, Managed DirectX, the Windows® XP 3D screensavers, and a few more bits and bobs. Previously at Microsoft, he was senior engineer in the DirectX evangelism group for DirectX 3.0 to DirectX 8.0, and helped many game ISVs with DirectX. He has been working with DirectX since the first public beta of the GameSDK (DirectX 1.0), and, once upon a time, actually shipped DirectX 2.0 games. In his spare time, he can be found lurking on many 3-D graphics programming mailing lists and Usenet newsgroups. You can reach him at msdn@microsoft.com.

© 2009 Microsoft Corporation. All rights reserved. Terms of Use  |  Trademarks  |  Privacy Statement
Page view tracker