スクリーン全体を描画するシェーダを記述
ポストエフェクト本体の処理は、スクリーンに一致するサイズの長方形のポリゴンを描画するシェーダを作成して、その中で行います。これには、まずテクニック内のパス定義で以下のようにスクリプトを記述します。
pass DrawBuffer < string Script= "Draw=Buffer;"; > {
AlphaBlendEnable = FALSE;
VertexShader = compile vs_2_0 VS_DrawBuffer();
PixelShader = compile ps_2_0 PS_DrawBuffer();
}
この"Draw=Buffer;"というコマンドにより、シェーダが描画するオブジェクトが、スクリーンに一致するサイズの長方形のポリゴンになります。
頂点シェーダは以下のように実装します。カメラ等の座標変換が必要ないため、基本的に入力されたポリゴンの頂点情報をそのまま出力する形になります(TexにViewportOffsetを加えている点については補足1を参照)。
VS_OUTPUT VS_DrawBuffer( float4 Pos : POSITION, float4 Tex : TEXCOORD0 ){
VS_OUTPUT Out;
Out.Pos = Pos;
Out.Tex = Tex + ViewportOffset;
return Out;
}
そして、ピクセルシェーダでポストエフェクト本体の処理を実装します。以下の例では、入力したピクセル色をそのままスクリーンに出力しているので、無編集のポストエフェクトになります。
float4 PS_DrawBuffer(float2 Tex: TEXCOORD0) : COLOR
{
float4 Color = tex2D( ScnSamp, Tex );
// 何か処理
return Color;
}
典型的なポストエフェクトの頂点シェーダは以下のようなものになります。
// スクリーンサイズ
float2 ViewportSize : VIEWPORTPIXELSIZE;
// スクリーンサイズを1としたときの、0.5ピクセル分
static float2 ViewportOffset = (float2(0.5,0.5)/ViewportSize);
VS_OUTPUT VS_DrawBuffer( float4 Pos : POSITION, float4 Tex : TEXCOORD0 ){
VS_OUTPUT Out;
Out.Pos = Pos;
Out.Tex = Tex + ViewportOffset;
return Out;
}
ここで、テクスチャ座標Texは、(0,0)でスクリーン左上の点を指し、(1,1)でスクリーン右下の点を指します。この頂点シェーダではTexにViewportOffsetを加えていますが、もしも、入力されたTexの値を変更せずにそのままピクセルシェーダに渡して、入力テクスチャの座標として使用した場合、次のような問題が発生します。
ラスタライザによって頂点情報がピクセル単位へと展開されるとき、あるピクセルの頂点情報は、そのピクセルの左上の点における情報になります。例えばスクリーン上の最も左上のピクセルについて考えると、ViewportOffsetを加えていなければTexの値は(0,0)になります。これはこのピクセルを表す1x1の四角形の左上の点を指し、ピクセルの中心は指しません。テクスチャの各ピクセルの色を正確に取得するためには、tex2D()関数には、ピクセルの四角形の中心を指す座標を与える必要があります。サンプラの設定にもよりますが、テクスチャ座標が1つのピクセルの中心を指しておらず、ピクセル同士の境界の座標を指している場合、得られるピクセル色は双方のピクセルの色の平均になります。
これを避けるために、頂点シェーダでTexにViewportOffsetを加えるという操作を行っています。これにより、テクスチャ座標が縦横ともに0.5ピクセル分ずれ、ピクセルシェーダにおけるTexの値がピクセルの中心座標を指すようになります。
