・Direct3Dがシェーダ機能を使えるかチェックする
・頂点シェーダで処理する頂点データを定義
・エフェクトオブジェクトの作成( HLSLのエフェクトファイルを読み込む )
・テクニックの選択
・描画
・エフェクト開始宣言
・HLSLのグローバル変数をセット
・パスの開始宣言
・(ポリゴンを描画)
・パスの終了宣言
・エフェクト終了宣言
ピクセルシェーダと頂点シェーダそれぞれの利用可能なバージョンをチェックします。
LPDIRECT3DDEVICE9 device;
D3DCAPS9 caps;
device->GetDeviceCaps(&caps);
if ( ( caps.VertexShaderVersion < D3DVS_VERSION(2,0) ) ||
( caps.PixelShaderVersion < D3DPS_VERSION(2,0) ) ) {
::MessageBox(NULL,_T("プログラマブルシェーダの機能に対応していません。"),_T(""),MB_OK);
}
Direct3Dで使う頂点はプログラマーがある程度自由に定義できます。そのため定義した頂点の内容は頂点シェーダにも知らせなければいけません。
Direct3Dで使う頂点データの例
struct CUSTOMVERTEX
{
D3DVECTOR pos; //頂点の位置
DWORD color; //頂点の色
float tu; //テクスチャ座標
float tv;
};
CUSTOMVERTEXで定義した頂点の内容に従って頂点シェーダにその構造を知らせます。
頂点シェーダが処理する頂点データの構造を定義
LPDIRECT3DDEVICE9 device;
HRESULT hr;
LPDIRECT3DVERTEXDECLARATION9 pVertexDeclaration; //頂点シェーダの頂点定義
//パイプラインに渡す頂点データの構造を定義
D3DVERTEXELEMENT9 decl[] = {
{ 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 }, //位置
{ 0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0}, //色
{ 0, 16, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0}, //テクスチャ座標
D3DDECL_END() //最後に必ずD3DDECL_END()をつける
};
//頂点の定義オブジェクトを作成する
hr = device->CreateVertexDeclaration( decl, &pVertexDeclaration );
if ( FAILED(hr) ) {
throw _T("error");
}
//頂点定義をセット
device->SetVertexDeclaration( pVertexDeclaration );
特にD3DVERTEXELEMENT9の二番目の値に注意して下さい。 0,12,16と入っているこの値は、構造体(CUSTOMVERTEX)の先頭からのオフセット(先頭から何バイトずれているか)を差しています。
HLSLで記述したエフェクトファイルを読み込んでDirect3Dのエフェクトオブジェクトを作成します。
LPCWSTR path = _T("エフェクトファイル");
LPDIRECT3DDEVICE9 device;
LPD3DXEFFECT pEffect;
HRESULT hr;
//ファイルの読み込み
LPD3DXBUFFER pErrMessage = NULL;
hr = D3DXCreateEffectFromFile( GetDevice(), path, NULL, NULL, 0, NULL, &pEffect, &pErrMessage );
if ( FAILED(hr) ) {
//エラーメッセージ表示(文字コードがANSI)
::MessageBoxA(NULL,(LPCSTR)(pErrMessage->GetBufferPointer()),"",MB_OK);
pErrMessage->Release();
throw 0;
}
LPD3DXEFFECT pEffect;
pEffect->SetTechnique("RenderScene"); //引数は任意のテクニックの名称
エフェクトファイルに定義しておいたグローバル変数へデータを渡します。
この例では座標変換行列とテクスチャを渡しています。
LPD3DXEFFECT pEffect;
D3DXMATRIX mat;
LPDIRECT3DTEXTURE9 texture;
//第一引数がグローバル変数名 二つ目がデータ。
pEffect->SetMatrix("g_mWorldViewProjection", mat );
pEffect->SetTexture( "g_Texture", texture );
アセンブルで頂点シェーダを実装した時は座標変換行列を転置行列にしていましたが、HLSLでは不要になりました。
エフェクトを有効にして描画するにはちょっと手間がかかります。
レンダリング処理をBeginとEndで挟まなければいけません。
LPD3DXEFFECT pEffect;
//エフェクト開始
pEffect->Begin( NULL, 0 ); //第一引数ではパスの数を取得できる
//使用するパスを選択
pEffect->BeginPass( 0 );
//ここで描画処理をする(DrawPrimitiveなど)
pEffect->EndPass();//パス終了
pEffect->End();//エフェクト終了