D3DX について、パート2: テクスチャ

Philip Taylor
Microsoft Corporation

August 30, 2002

要約: Philip Taylor が前回に引き続き、Microsoft Direct3D ユーティリティ ライブラリ D3DX が提供している各種のテクスチャ サポートについて解説します。

先月から始まったMicrosoft® Direct3D® ユーティリティ ライブラリ D3DX の解説へようこそ。今月は、D3DX が提供しているテクスチャ サービスに目を向け、D3DX の各種のテクスチャ サポートを紹介したいと思います。これには以下のものが含まれます。

  • テクスチャ要件チェック
  • ミップマップ テクスチャ サポート
  • キューブマップ サポート
  • ボリュームテクスチャ サポート
  • バンプマッピング サポート
  • レンダーターゲット サポート

先月示したリストをちょっと変えて、ID3DXRenderToSurface インターフェイスと ID3DXRenderToEnvmap インターフェイスを「レンダーターゲット サポート」にまとめています。この 2 つのインターフェイスの主な用途はレンダーターゲット サポートであり、「環境マッピング」と「D3DX レンダーターゲット」の 2 つのセクションに分けるよりもわかりやすいと考えたからです。これらをまとめて扱うことで、その意義を理解しやすくなります。

この文章では、D3DX のすべてのテクスチャ関数を扱うわけではありません。読者の方々が自分で確認できるように、主にサンプルが使用している関数に焦点を当てることにします。いくつかのケースでは SDK で使ってていない関数も示しますが、それは例外です。関数が SDK で使用されている場合には、そのコード部分がどのサンプルに含まれているかも記します。

テクスチャ要件チェック

D3DXCheckTextureRequirementsD3DXCheckCubeTextureRequirements、および D3DXCheckVolumeTextureRequirements を使用すると、デバイス インスタンス上にミップマップ テクスチャ、キューブマップ テクスチャ、またはボリュームテクスチャ設定の特定の組み合わせを作成できるかどうかを確認することができます。

次に、D3DXGetImageInfoFrom ファイルを使用して特定のイメージのフォーマットを取得する方法の 1 つを示します。

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

次に、これを使って D3DXCheckTextureRequirement の呼び出しを次のように指定します。

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

呼び出しに失敗した場合には、戻り値が自動的に調整されるのも便利です。D3DXCreateTexture のドキュメントには次のように書かれています。

内部的には、D3DXCreateTextureD3DXCheckTextureRequirements を使用して呼び出しパラメータを調整しています。このため、D3DXCreateTexture の呼び出しは、IDirect3DDevice8::CreateTexture の呼び出しが失敗するようなケースでも成功することがよくあります。

同じように、D3DXCheckCubeTextureRequirements は次のように呼び出します。

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

次に、D3DXCheckVolumeTextureRequirements を次のように呼び出します。

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

これらの関数は、呼び出しが失敗したときには更新済みのパラメータを返すので (「スマート」な確認と呼ぶことができるでしょう)、ユーティリティ ルーチンとして非常に便利です。

ミップマップ テクスチャ サポート

IDirect3DTexture8 は、標準的なミップマップ テクスチャの基本的なサポートを提供します。SDK に含まれているほぼすべての Direct3D サンプルがミップマップ テクスチャを使用しています。例外は、特殊なキューブマップとボリューム テクスチャのサンプルです (これらについては後に詳しく説明します)。D3DX サポートには、空のテクスチャの作成、テクスチャのロード、テクスチャの保存、フィルタリング、およびアルゴリズム的な生成といった基本的操作のためのヘルパが含まれます。以下では、個々の操作のコード部分を示します。

空のテクスチャの作成

ビットをアルゴリズム的に生成する場合、ロード プロセスを手動で管理する場合、またはそれ以外にも何らかの正当な理由から、初期化されていないビットを含んだ「空」のテクスチャを作成したいことがあります。D3D は、これを D3DXCreateTexture 関数によってサポートしています。次にこの関数のプロトタイプを示します。

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

この関数は、テクスチャを作成するデバイス、必要な幅と高さ、要求するミップ レベルの数、用途、テクスチャ フォーマット、およびメモリ プールを引数として取ります。返されるのは LPDIRECT3DTEXTURE8 へのポインタです。

次に、Water サンプルに含まれている呼び出しの例を示します。

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

リソースからのロード

プログラマが次に必要とする操作は、リソースからのテクスチャの作成でしょう。この機能は D3DXCreateTextureFromResourceEx が提供しています。次に関数プロトタイプを示します。

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);

この関数は、テクスチャを作成するデバイスと、目的のリソースを識別する HMODULE ハンドルおよび文字列を引数として取ります。空のテクスチャの作成関数と同様に、必要な幅と高さ、要求するミップ レベルの数、用途、テクスチャ フォーマット、およびメモリ プールも渡します。また、オプションの ColorKey、D3DXIMAGE_INFOポインタ、および PALETTEENTRY の配列へのポインタも渡します。返るのは LPDIRECT3DTEXTURE8 へのポインタです。

DirectPlay Maze サンプルに含まれている呼び出しの例を示します。

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 ) ) )

ファイルからのロード

リソース ファイル内のテクスチャの使用は、単純な例では解決策として手軽ですが、一般には独立したディスク ファイルからロードする方がはるかに便利です。この機能は、基本エディションでは D3DXCreateTextureFromFile が提供しています。次に関数プロトタイプを示します。

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

この関数は、テクスチャを作成するデバイスとソース ファイル名を引数として取ります。返されるのは LPDIRECT3DTEXTURE8 へのポインタです。

SDK チュートリアル #5 に含まれている呼び出しの例を示します。

// D3DX を使用して、ファイル ベースのイメージからテクスチャを作成
if( FAILED( D3DXCreateTextureFromFile( g_pd3dDevice, "banana.bmp",
                                       &g_pTexture ) ) )

これは基本エディションです。The D3DXCreateTextureFromFileEx 関数は「拡張」("Ex") 機能の関数を提供しています。次に関数プロトタイプを示します。

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);

この関数は、テクスチャを作成するデバイスとソース ファイル名を引数として取ります。他の拡張テクスチャ作成関数と同様に、必要な幅と高さ、要求するミップ レベルの数、用途、テクスチャ フォーマット、およびメモリ プールと、オプションの ColorKey、D3DXIMAGE_INFO ポインタ、および PALETTEENTRY の配列へのポインタも渡されます。返されるのは LPDIRECT3DTEXTURE8 へのポインタです。

SDK サンプルの Water に含まれている呼び出しの例を示します。

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); 

基本関数は最低限のパラメータを公開し、"Ex" の拡張関数はテクスチャのロードを制御するためのすべてのパラメータを公開しているというパターンが見て取れます。

メモリからのロード

作成フォーマットからレンダリング フォーマットに変換するときには、メモリ ブロックからテクスチャを作成できると便利なことがあります。メモリ ブロックからのロードの機能は、D3DXCreateTextureFromFileInMemoryD3DXCreateTextureFromFileInMemoryEx が提供します。

次に D3DXCreateTextureFromFileInMemory のプロトタイプを示します。

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

この関数は転送元データ ポインタと転送元データ サイズ、およびデバイス パラメータを引数として取り、LPDIRECT3DTEXTURE8 オブジェクトへのポインタを返します。D3DXCreateTextureFromFileInMemory を使用している SDK サンプルはありませんが、Worldcraft レベル エディタはこの関数を使用しています。次に、この関数の使用例を示します。

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

次に D3DXCreateTextureFromFileInMemoryEx のプロトタイプを示します。

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);

この関数は転送元データ ポインタと転送元データ サイズ、および通常の "Ex" パラメータ、つまり Width、Height、MipLevels、Usage、Format、Pool、Filter と MipFilter、ColorKey、転送元イメージ情報、およびオプションのパレットを作成するための PALETTEENTRY の配列を引数として取ります。関数が返すのは、LPDIRECT3DTEXTURE8 オブジェクトへのポインタです。SDK のサンプル スクリーンセーバーは、この関数を使って、リソースをリソース フォークから取得し、メモリにロードした後に、カスタム リソースからロードを行います。次に、この関数の使用例を示します。

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 ) ) )

保存

テクスチャのファイルへの保存は、.dds 圧縮テクスチャと、Microsoft Windows® ビットマップ フォーマットの .bmp でサポートされています。単一サーフェイスの保存とミップマップテクスチャ保存の両方が用意されています。次にミップマップ テクスチャ保存のための関数プロトタイプを示します。

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

この関数は、ファイル名、フォーマット、転送元テクスチャ、およびオプションのパレットを引数として取ります。SDK サンプルの DXTex は、この関数を使ってテクスチャを保存します。次に、この関数の使用例を示します。

//sdk ツール dxtex
if( FAILED( D3DXSaveTextureToFile( lpszPathName, D3DXIFF_DDS, 
                                   ptex, NULL ) ) )

フィルタリング

また、D3DX はポイント、リニア、トライアングル、またはボックス フィルタを使ってテクスチャのフィルタリングを行い、D3DXFilterTexture を使用したミップ レベルの「リアルタイム」での生成をサポートしています。次に関数プロトタイプを示します。

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

SDK サンプルの BumpSelfShadow は、この関数を使用しています。次に呼び出しの例を示します。

//sdk サンプルbumpselfshadow
if(FAILED(hr = D3DXFilterTexture( m_pHorizonTextures[0], NULL,0, 
    D3DX_FILTER_BOX)))

アルゴリズム的な生成

テクスチャのアルゴリズム的な生成はきわめて便利なテクニックであり、D3DX では D3DXFill* 関数がサポートします。ミップマップ テクスチャでは、D3DXFillTexture 関数がこの機能を提供しており、そのプロトタイプは次のとおりです。

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

この関数は、次の型の関数ポインタを引数として取ります。

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

これがランタイムによって呼び出され、個々のピクセルを生成します。MSDN Shader Workshop サンプルは、この関数を次のように使用しています。

// fresnel の評価
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);

このように、独自のテクスチャを簡単に生成できます。

キューブマップ テクスチャ サポート

IDirect3DCubeTexture8 は、キューブ環境マップ テクスチャのための基本サポートを提供します。キューブ環境マップ テクスチャは、現実感のある環境マップによる反射の作成に非常に便利です。これらはキューブの 6 つの面から構成されているので、周囲の環境を正確に反映しています。SDK サンプルの CubeMap、FishEye、Water と SDK ツールの DXTex は、いずれもキューブマップ テクスチャを使用しています。また、MSDN Shader Workshop サンプルも同様です。D3DX サポートには、空のキューブマップ テクスチャの作成、既存のデータからのキューブマップ テクスチャのロード、キューブマップ テクスチャのフィルタリング、およびキューブマップ テクスチャの個々の面のデータのアルゴリズム的な生成といった基本的な操作のためのヘルパが含まれています。以下では、各操作のコード部分を示します。

空のキューブマップ テクスチャの作成

単なる空のキューブマップ テクスチャが必要な場合のために、D3DX は D3DXCreateCubeTexture 関数を用意しています。D3DXCreateCubeTexture のプロトタイプはミップマップ テクスチャ関数と似ています。

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

デバイス以外のパラメータは、エッジのサイズ、ミップ レベルの数、Usage、Format、および Pool です。返されるのは LPDIRECT3DCUBETEXTURE8 です。SDK サンプルの Water には、空のキューブマップ テクスチャを作成するための使用例があります。

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

空のキューブマップを初期化するには、アルゴリズム的な生成か、レンダーターゲットとして使用するかのどちらかを行います。

ファイルからのロード

ファイルからのキューブマップ テクスチャの基本的なロードは、D3DXCreateCubeTextureFromFile によって実行されます。次にプロトタイプを示します。

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

この関数はデバイスとファイル名だけを引数として取り、LPDIRECT3DCUBETEXTURE8 インターフェイスを返します。MSDN Shader Workshop サンプルに使用例があります。

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

拡張キューブマップ ファイル ロード関数の D3DXCreateCubeTextureFromFileEx は、次のプロトタイプを持ちます。

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);

この関数は、例のごとくデバイスおよびファイル名を取り、さらにエッジ サイズ、MipLevels、Usage、Format、Pool、Filter と MipFilter の設定、そしてオプションの ColorKey、転送元 イメージ データ ポインタ、およびパレット ポインタを引数として取ります。返されるのは LPDIRECT3DCUBETEXTURE8 インターフェイスです。SDK ツールの Dxtex に使用例があります。

//sdk ツール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 ) ) )

これらのキューブマップ ローダーの「メモリから」と「リソースから」のバージョンは省略します。読者はこのパターンをすでに理解しているでしょうから、これらの関数も簡単に使えるはずです。

フィルタリング

SDK ドキュメントは次のように述べています。

D3DXFilterTexture 関数は、D3DXFilterCubeTextureD3DXFilterVolumeTexture の両方の機能を含んでおり、この 2 つの関数は廃止されています。

しかし、実際にヘッダーの中身を見てみると、D3DXFilterCubeTexture は次のような D3DXFilterTexture の #define に過ぎないことがわかります。

#define D3DXFilterCubeTexture D3DXFilterTexture

おそらく SDK ドキュメントは、コードを読んだときにこの関数の使用が適しているかどうかが判断しやすいように、この短い名前を使うことを推奨しているのだと思われます。SDK サンプルの Water は、#define を次のように使用しています。

D3DXFilterCubeTexture(m_pSkyCubeTex, NULL, 0, D3DX_DEFAULT);

では、キューブマップ テクスチャのアルゴリズム的な生成に進みましょう。

アルゴリズム的な生成

D3DX は、キューブマップ内のビットをプログラム的に生成するための D3DXFillCubeTexture 関数を用意しています。この関数は、関数ポインタ パラメータに、D3DXFillTexture と同じ関数ポインタ シグニチャを使用します。次に関数プロトタイプを示します。

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

MSDN Shader Workshop サンプルには、この関数の使用例があります。

//スペキュラ ライト ルックアップ テーブル
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);

次はボリューム テクスチャを取り上げます。

ボリュームテクスチャ サポート

IDirect3DVolumeTexture8 はボリューム テクスチャのための基本サポートを提供しています。ボリューム テクスチャ、あるいは 3-D テクスチャは、現実感のあるフォグ、爆発、または深さを必要とするその他の任意のエフェクトの作成にきわめて便利です。これらはテクスチャの複雑さ (メモリ読み込み) を幾何学的な複雑さに置き換える働きをします。ボリューム テクスチャには多くのメモリが必要になるので、プログラマは注意する必要があります。SDK サンプルの VolumeTexture と SDK ツールの DXTex は、どちらもボリューム テクスチャを使用しています。D3DX サポートには、空のテクスチャの作成、テクスチャのロード、テクスチャの保存、フィルタリング、および手続き的な生成といった基本操作のためのヘルパが含まれています。以下では、各操作のコード部分を示します。

空のテクスチャの作成

D3DX は、空のテクスチャの作成のために D3DXCreateVolumeTexture を用意しています。次に示す関数プロトタイプは、3-D テクスチャに必要な深さのパラメータが追加されている点を除けば、ミップマップ関数と似ています。

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

残念ながら SDK にはサンプルはありませんが、深さの値を指定することで、WxH 2-D ミップマップ テクスチャの代わりに WxHxD 3-D テクスチャが得られるということは簡単に理解できるでしょう。

ファイルからのロード

D3DX の基本的なファイルからのボリュームテクスチャ ロード関数である D3DXCreateVolumeTextureFromFile のサンプルは SDK には含まれていませんが、"Ex" バージョン、つまり拡張バージョンの D3DXCreateVolumeTextureFromFileEx のサンプルは存在します。次にプロトタイプを示します。

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);

SDK ツールの DXTex は、これを次のように呼び出しています。

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 ) ) )

フィルタリング

キューブマップ テクスチャ フィルタ ルーチンの D3DXFilterCubeTexture と同様に、D3DXFilterVolumeTexture も次のような #define として定義されています。

#define D3DXFilterVolumeTexture D3DXFilterTexture 

使い方は明らかでしょうから、ここでは説明を省きます。

アルゴリズム的な生成

ボリューム テクスチャのアルゴリズム的な生成は、ミップマップ テクスチャとキューブマップ テクスチャのアルゴリズム的な生成と同じように、生成関数への関数ポインタを渡して D3DXFill* 関数を呼び出すことによって行います。ボリューム テクスチャの場合の関数は、次のプロトタイプを持つ D3DXFillVolumeTexture です。

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

生成関数にもまったく同じ関数プロトタイプが使用されるので、D3DXFillVolumeTexture の使用方法は他の関数と同じです。ランタイムは各テクスチャ要素の生成関数を自動的に呼び出します。SDK には、これに対応する使用例はありません。

次はバンプマッピングです。

バンプマッピング

バンプマッピングのための 2 つの便利な関数、D3DXComputeNormalMapD3DXComputeTangent を取り上げましょう。D3DXComputeNormalMap は高さマップを法線マップに変換するために使用されます。D3DXComputeTangent はローカル接空間座標系を生成するために使用されます。

次に D3DXComputeNormalMap の関数プロトタイプを示します。

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

この関数は、転送元の高さマップ テクスチャと転送先の法線マップ テクスチャの両方のインターフェイス ポインタ、マップの変換方法を制御するフラグ、転送元の高さマップのどのチャネルを変換に使用するのかを識別するためのチャネル値、およびオプションとしてチャネル値に掛ける振幅値を引数として取ります。このメソッドは、3x3 のカーネル サイズの中心差分を使って法線を計算することに注意してください。転送先の RGB チャネルは、法線のバイアスされた (x,y,z) 要素を含んでいます。MSDN Shader Workshop に使用例があります。

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

D3DXComputeTangent はメッシュに対して作用しますが、バンプマップ ライティングの計算に使用される情報を返すので、バンプマップ ピクセル ライティングのためのヘルパ サービスを実行するメッシュ関数である「仲介役」の関数の 1 つであると言えます。次にプロトタイプを示します。

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

この関数は、入力メッシュと、入力テクスチャ座標値を取り出すステージ、および出力メッシュを必要とします。さらに、出力 u と v の送信先のステージを制御するための値と、ラップ制御と隣接情報のためのパラメータを指定します。MSDN Shader Workshop サンプルと SDK サンプルの BumpSelfShadow の両方がこの関数を使用しています。次に使用例を示します。

//テクスチャ空間内の接線ベクトルを計算し、それらを (3D の) 第 1 テクスチャ 
//ステージにロードし、0 番目のテクスチャ ステージから
//テクスチャ座標を読み込む。
//U x N と仮定されているので、V 方向のベクトルは不要。
hr = D3DXComputeTangent(pMeshSysMem,0,pMeshSysMem2,1, 
                        D3DX_COMP_TANGENT_NONE,TRUE,NULL);

レンダーターゲット サポート

D3DX は、レンダーターゲットとキューブ マップのためのサポートを追加しています。ID3DXRenderToSurface インターフェイスはレンダーターゲットのためのレンダーターゲット作成機能をカプセル化しており、ID3DXRenderToEnvmap インターフェイスはキューブ環境マップのためのサポートをカプセル化しています。いったんこれらのインターフェイスを作成した後の一般的な使用パターンは、Begin 関数を呼び出し、レンダリングを行った後に、End 関数を呼び出すというものになります。キューブ環境マップの場合は、これをキューブ マップの 6 つの面について繰り返す必要があります。また、これらのインターフェイスは、デバイスの喪失とリセットを扱うときの内部リソースの管理もサポートしています。

サーフェイスへのレンダリング

D3DXCreateRenderToSurface のサーフェイスへのレンダリングのサポートにより、テクスチャへのレンダリングのシナリオを、これを直接にサポートしていないカード上でも実行できます。このパフォーマンスの高いエミュレーション サポートにより、リアビュー ミラー、リモート カメラ、および TV などのテクスチャへのレンダリングのエフェクトを、これまでは対応ハードウェアが少ないために実現が不可能だったアプリケーションで使用できるようになります。SDK ドキュメントはこれを「その他」の関数の下に分類していますが、筆者はこれをテクスチャ ライブラリの拡張部分だと考えています。次に関数プロトタイプを示します。

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

いつものデバイス パラメータに加え、Width と Height、サーフェイス フォーマット、および 2 つの深度ステンシル パラメータ (1 つしか存在しない場合には、そのフォーマット) を渡し、ID3DXRenderToSurface インターフェイスが返されます。SDK サンプルの Water に使用例があります。

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

このインターフェイスを取得したら、その BeginScene メソッドを呼び出し、レンダリングを実行した後に、EndScene を呼び出します。これは標準的なテクスチャへのレンダリングの操作に他なりません。やはり SDK サンプルの Water に典型的な例があります。

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();
}

環境マップへのレンダリング

D3DXCreateRenderToEnvMap の環境マップへのレンダリングのサポートにより、キューブマップ シナリオを、これを直接にサポートしていないカード上でも実行することができます。このパフォーマンスの高いエミュレーション サポートにより、きれいなリフレクション マップのようなキューブマップ エフェクトを、これまでは対応ハードウェア (geForce2 世代以降の新しいカード)が少ないために実現が不可能だったアプリケーションで使用できるようになります。SDK ドキュメントはこれを「その他」の関数の下に分類していますが、筆者はこれをテクスチャ ライブラリの拡張部分だと考えています。次に関数プロトタイプを示します。

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

いつものデバイス パラメータに加え、エッジ サイズ、キューブマップ フォーマット、深度ステンシル バッファがアタッチされているかどうか、深度ステンシル バッファが渡されるときのフォーマット (アタッチされている場合) が渡され、ID3DXRenderToEnvmap が返されます。SDK サンプルの Cubemap は、このインターフェイスを使って、多くのハードウェア上で動作するようにしています。次に使用例を示します。

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

この D3DX 環境マップ コンストラクトを次の例のように使用して、個々の面をループで処理し、クリア、リソースの設定、およびレンダリングを行うことができます。

for (uiFaceIndex = 0; uiFaceIndex < 6; ++uiFaceIndex)
{
// Face メソッドを呼び出す。  
// これでレンダーターゲット、深度ステンシル、およびビューポートが設定される。
   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);
   }
}

これは、レンダーターゲットの使用例で、D3DX キューブマップの個々の面を並行して作成するのと同じ原理に基づいています。

これで、D3DX テクスチャ サービスの簡単な紹介を終わります。

D3DX について最後に一言

これまでの説明でわかるように、D3DX はかなり高度なテクスチャ機能をサポートしています。D3DX の残りの領域については今後のコラムで扱いますので、ご期待ください。

このコラムの執筆に際して、Craig PeeperTodd Frost、および Rob Aldinger (Microsoft) の各氏のご協力に感謝します。 ご意見をお寄せください。感想、質問、トピックに関するアイデア、コラムのトピックに関しての皆さんのやり方を示すリンクなどを (日本語で) directxj@microsoft.com まで送ってください。ただし、個別に返答したり、サポートに関する質問に回答したりすることはできませんので、あらかじめご了承ください。

Microsoft では、同じ目的の開発者が情報を共有できるようなフォーラムとして、活発なメーリング リストを運営しています (英語)。

オーディオおよびビデオを扱う DirectXAV に関する話題は、 http://DISCUSS.MICROSOFT.COM/archives/DIRECTXAV.html

グラフィックス、ネットワーク、および入力を扱う DirectXDev に関する話題は、http://DISCUSS.MICROSOFT.COM/archives/DIRECTXDEV.html を参照してください。

 

Driving DirectX

Philip Taylor は DirectX SDK、Managed DirectX、Windows XP 3D スクリーンセーバーなどのプログラム マネージャです。 DirectX 3.0 から DirectX 8.0 までの DirectX エバンジェリズム グループのシニア エンジニアとして活躍し、多数のゲーム開発会社に対して DirectX 関連のサポートを行いました。GameSDK (DirectX 1.0) の最初のパブリック ベータの段階から手を染め、かつては実際に DirectX 2 でゲームを開発したこともありました。 時間に余裕があるときは、さまざまな 3-D グラフィックス プログラミング メーリング リストで彼に出会うことがあるかもしれません。