3Dモデルを描画する際に,画面に映らない部分の描画処理を省く方法として,背面カリング(Back-face culling)というものがある.
この手法自体はOpenGLにもDirectXにも標準で組み込まれていて,設定するだけで簡単に利用できる.
OpenGLの場合,次のように設定する.
// OpenGLの場合
// 背面カリングを有効にする
glEnable(GL_CULL_FACE);
// 反時計回り(counter clockwise)の頂点を持つ面を表と見なす (デフォルト)
// glFrontFace(GL_CCW);
// 時計回り(clockwise)の頂点を持つ面を表と見なす
// glFrontFace(GL_CW);
// WebGLの場合
// var gl = canvas.getContext('webgl');
gl.enable(gl.CULL_FACE);
// gl.frontFace(gl.CCW);
// gl.frontFace(gl.CW);
DirectX 9の場合,次のように設定する.
// ID3DDevice9 * pD3DDevice;
// 背面カリング無し
// pD3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
// 反時計回り(counter clockwise)の頂点を持つ面を消す (デフォルト)
// pD3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
// 時計回り(clockwise)の頂点を持つ面を消す
// pD3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW);
DirectX 11の場合,次のように設定する.
// ID3D11Device * pDevice;
// ID3D11DeviceContext * pContext;
// ラスタライザーステートの設定に必要なパラメータを設定
D3D11_RASTERIZER_DESC rd;
// 背面カリングをしない場合
// rd.CullMode = D3D11_CULL_NONE;
// 表面を消す場合
// rd.CullMode = D3D11_CULL_FRONT;
// 裏面を消す場合 (デフォルト)
// rd.CullMode = D3D11_CULL_BACK;
// 時計回り(clockwise)の頂点を持つ面を表と見なす (デフォルト)
// rd.FrontCounterClockwise = FALSE;
// 反時計回り(counter clockwise)の頂点を持つ面を表と見なす
// rd.FrontCounterClockwise = TRUE;
// その他のパラメータも設定
// ラスタライザーステートを生成して設定
ID3D11RasterizerState * pState;
pDevice->CreateRasterizerState(&rd, &pState);
pContext->RSSetState(pState);
pState->Release();
デフォルトの設定を整理すると次のようになる.
|
OpenGL |
DirectX |
消す面 | 裏 | 裏 |
表と見なす面 | 反時計回り(CCW) | 時計回り(CW) |
この設定手順の中で,OpenGLとDirectX 9を比較すると混乱してしまうのが,OpenGLは「表示する面」をCCW(counter clockwise)にするか,CW(clockwise)にするかを指定するのに対して,DirectX 9では「消す面」をCCWにするかCWにするかを指定する,ということだろう.同じような名前の定数を利用するので,同時に扱うと非常に混乱する気がする.
実際混乱している人がいるのか,OpenGLが右手座標系でDirectXは左手座標系だからだ,といった説明もあったが,頂点が時計回りか反時計回りかは座標系と関係が無いので,表示面指定と消去面指定で混乱しているのではないかと思われる.
調べて,実際にコードを書いて挙動を確認した限りでは合っていると思うのだけれど,実際のところ正しいのだろうか?