DirectX再入門7
ステンシルテスト
「レンダリング結果」を「ステンシルバッファ」でマスクする機能
レンダリング
|→ステンシルテスト
ステンシルバッファ
何に使えるか?
- モデルのシルエットなどに基づいて、画像を切り抜く
- 鏡や水面の表現などが可能
テストの方法
- 値
- ステンシルバッファ値
- ステンシル参照値
- ステンシルマスク値
- 条件
- 比較関数
※ステンシルマスク値は、
ステンシルバッファ値やステンシル参照値を
&でマスクする。(論理積)
ただし、通常は0xFFFFFFFFを指定しておく(マスクしないようにする)
ということで、ステンシルバッファ値とステンシル参照値を
「比較関数」により、テストする。
(ステンシル参照値には任意の値を設定しておく)
比較関数一覧
比較関数 | 意味(ステンシル参照値が左辺) |
---|---|
D3DCMP_LESS | < |
D3DCMP_LESSEQUAL | ≦ |
D3DCMP_GREATER | > |
D3DCMP_GREATEREQUAL | ≧ |
D3DCMP_EQUAL | = |
D3DCMP_NOTEQUAL | ≠ |
D3DCMP_ALWAYS | 常に合格 |
D3DCMP_NEVER | 常に不合格 |
深度テスト
前景にオブジェクトがある場合に、書き込みをスキップするテスト。
テストの順番は、「ステンシルテスト」→「深度テスト」で行われる。
レンダリングターゲットのステンシルバッファへの書き込み
- テスト結果による書き込み設定
- ステンシルテスト不合格の場合に書き込み(D3DRS_STENCILFAIL)
- ステンシルテスト合格・深度テスト不合格の場合に書き込み(D3DRS_STENCILZFAIL)
- ステンシルテスト合格・深度テスト合格の場合に書き込み(D3DRS_STENCILPASS)
- 値の書き込み設定
- D3DSTENCILOP_REPLACE:ステンシル参照値とステンシルマスク値の論理積を書き込む
- D3DSTENCILOP_INCR:すでに書き込まれている値+1
- D3DSTENCILOP_DECR:すでに書き込まれている値−1
- D3DSTENCILOP_ZERO:0にする
- D3DSTENCILOP_KEEP:何もしない
プログラムではどうするの?
1.ステンシルバッファを作成する
プレゼンテーションパラメータに以下の値を設定。
D3DPRESENT_PARAMETERS.AutoDepthStencilFormat = D3DFMT_D24S8;
深度バッファの1ピクセルが24ビット、ステンシルバッファの1ピクセルが8ビット。
2.ステンシルバッファのクリア
IDirect3DDevice9::Clear( 0, 0, D3DCLEAR_STENCIL | D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0)));
ステンシルバッファをクリアするには、D3DCLEAR_STENCILが必要となる。
3.深度テストの設定
IDirect3DDevice9::SetRenderState(D3DRS_ZFUNC, D3DCMP_XXX);
4.ステンシルテストの設定
// ステンシルテスト有効化 IDirect3DDevice9::SetRenderState(D3DRS_STENCILENABLE, TRUE); // ステンシル参照値 IDirect3DDevice9::SetRenderState(D3DRS_STENCILREF, 0xXX); // 各種マスクの設定 IDirect3DDevice9::SetRenderState(D3DRS_STENCILMASK, 0xffffffff); IDirect3DDevice9::SetRenderState(D3DRS_STENCILWRITEMASK, 0xffffffff); // ステンシル比較関数 IDirect3DDevice9::SetRenderState(D3DRS_STENCILFUNC, D3DCMP_XXX);
5.ステンシルテスト結果の設定
// ステンシルテスト不合格 IDirect3DDevice9::SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_XXX); // ステンシルテスト合格、深度テスト不合格 IDirect3DDevice9::SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_XXX); // ステンシルテストと深度テストの両方合格 IDirect3DDevice9::SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_XXX);
ステンシルシャドウ
ステンシルバッファで影を描画する方法。
Zファイティング
物体を重ねたときに、計算の誤差により、
双方が隠れたり隠れなかったりしてチラチラする現象。
ステンシルテストにより抑制する。
影を描画するには?
影の映し出す「光源」、
影の元となる「物体」、
影が映りこむ「物体」
の3つの関係により発生する。
今回は、影が映りこむ「物体」を「平面」とする。
平面の場合、影の元となる「物体」を、
光源方向から平面に向けて平たく変形するだけでよいので、処理が楽。
DirectXでは、ど〜やるの?
- D3DXVECTOR4で光源の方向、種類を指定
- D3DXPLANEで影が映りこむ平面を定義
- 1と2をD3DXMatrixShadowに渡すと、平面に映った影が取得できる
- D3DXPlaneFromPointNormal(D3DXPLANE *plane, D3DXVECTOR3 *p, D3DXVECTOR3 *v)
- pに「平面状の任意の点」vに「平面の向き」を指定すると、planeに平面が設定される。
Zファイティングの抑制
- バックバッファに影を描画
- ステンシルバッファに影のマスク画像を作成
- 2を使って、影と重なる部分以外を描画