ホーム < ゲームつくろー! < プログラマブルシェーダ編 < ピクセルシェーダの流れを知ろう
その4 ピクセルシェーダの流れを知ろう
ピクセルシェーダは頂点シェーダによって射影空間に変換された頂点がカリングやラスタライズされた後に実行されます。ラスタ化の段階で、1つのポリゴンがどのピクセル領域を占めるかが決められます。次はそこに付ける色を決定する段階にあるわけです。つまり、ピクセルシェーダは「あるピクセルを何色に塗るか」についてとことんまでこだわるエフェクトであるわけです。この章では、そんなピクセルシェーダの流れについて見ていくことにしましょう。
@ ピクセルシェーダの流れ(大局編)
ピクセルシェーダのプログラムの流れは頂点シェーダのそれと殆ど一緒ですが、ピクセルシェーダ用に頂点を教えたり変換行列を作成する事が無い分単純で簡単になります。大雑把な流れは以下の通りです。
A 頂点の宣言
頂点構造体の宣言と頂点フォーマットマクロを定義します。もちろん、頂点シェーダで使用した物を流用してかまいません。
頂点フォーマットの定義 struct CUSTOMVTX
{
float x, y, z; // 頂点位置
DWORD color; // 頂点カラー
};
#define CUSTOMFVF D3DFVF_XYZ | D3DFVF_DIFFUSE
B ピクセルシェーダプログラムの生成とコンパイル
頂点シェーダと同様に、ピクセルシェーダプログラムも直接ソース上に書いておくか、ファイルから読み込むかの2通りの定義方法があります。ソース上から読み込む場合はD3DXAssembleShader関数を、ファイルから読み込む場合はD3DXAssembleShaderFromFile関数を用います。
ピクセルシェーダ命令を定義しコンパイル // ピクセルシェーダ命令配列定義
const char PxShader[] =
"ps_1_1 \n"
"def c0, 0.2989f, 0.5866f, 0.1145f, 1.0f \n" // 彩度算出係数
"dp3 r0, v0 , c0 \n" // 彩度Y算出(r.aに格納される)
"mov r1, r0.a \n" // r0の各成分をYで埋める
"lrp r0, c1 , v0 , r1 \n"; // 線形補間( v0 + c1*(Y-v0) )
// シェーダ命令のコンパイル
ID3DXBuffer *pShader; // シェーダ命令格納バッファ
ID3DXBuffer *pError; // コンパイルエラー情報格納バッファ
D3DXAssembleShader(PxShader, sizeof(PxShader)-1, 0, NULL, 0, &pShader, &pError );
今はピクセルシェーダの命令の中身については触れません。
C ピクセルシェーダハンドラの生成
ピクセルシェーダプログラムのコンパイルが成功したら、シェーダ命令がバッファに格納されます。それを扱ってGPUとやり取りするためのピクセルシェーダハンドラ(IDirect3DPixelShader9)を次に生成します。生成する関数はIDirect3DDevice9::CreatePixelShader関数です。
ピクセルシェーダハンドラの生成 // シェーダハンドラ
IDirect3DPixelShader9 *pShaderHandler;
pD3DDev9->CreatePixelShader( (DWORD*)pShader->GetBufferPointer(), &pShaderHandler );
D ピクセルのレンダリング
後はピクセルをレンダリングするだけです。この時、ストリームにピクセルシェーダハンドラを教えてあげる作業が唯一追加されます。これは、IDirect3DDevice9::SetPixelShader関数を用います。
ピクセルのレンダリング // 描画
pD3DDev9->SetStreamSource( 0, m_pVertex, sizeof(CUSTOMVTX) );
pD3DDev9->SetFVF( CUSTOMFVF );
pD3DDev9->SetPixelShader( pShaderHandler );
pD3DDev9->DrawPrimitive( D3DPT_TRIANGLEFAN, 0, 2 );
これでもうピクセルシェーダの使用方法は終わりです。頂点の宣言はピクセルシェーダに関わらずプログラム上にあるでしょうから、それを省けば「命令のコンパイル」「シェーダハンドラの生成」「ストリームに登録」というわかりやすい手順だけで済みます。頂点シェーダに比べるととても簡単ですよね。