このセクションでは、出力マージャー ステージの深度ステンシル バッファーと深度ステンシル状態を設定する手順について説明します。
深度ステンシル バッファーと対応する深度ステンシル状態の使用方法がわかったら、高度なステンシル手法を参照してください。
Depth-Stencil リソースを作成する
テクスチャ リソースを使用して深度ステンシル バッファーを作成します。
ID3D11Texture2D* pDepthStencil = NULL;
D3D11_TEXTURE2D_DESC descDepth;
descDepth.Width = backBufferSurfaceDesc.Width;
descDepth.Height = backBufferSurfaceDesc.Height;
descDepth.MipLevels = 1;
descDepth.ArraySize = 1;
descDepth.Format = pDeviceSettings->d3d11.AutoDepthStencilFormat;
descDepth.SampleDesc.Count = 1;
descDepth.SampleDesc.Quality = 0;
descDepth.Usage = D3D11_USAGE_DEFAULT;
descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL;
descDepth.CPUAccessFlags = 0;
descDepth.MiscFlags = 0;
hr = pd3dDevice->CreateTexture2D( &descDepth, NULL, &pDepthStencil );
Depth-Stencil 状態の作成
デプス-ステンシル状態は、デプス-ステンシル テストを実行する方法を出力統合ステージに指示します。 深度ステンシル テストでは、特定のピクセルを描画するかどうかを決定します。
D3D11_DEPTH_STENCIL_DESC dsDesc;
// Depth test parameters
dsDesc.DepthEnable = true;
dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
dsDesc.DepthFunc = D3D11_COMPARISON_LESS;
// Stencil test parameters
dsDesc.StencilEnable = true;
dsDesc.StencilReadMask = 0xFF;
dsDesc.StencilWriteMask = 0xFF;
// Stencil operations if pixel is front-facing
dsDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_INCR;
dsDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
// Stencil operations if pixel is back-facing
dsDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
dsDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_DECR;
dsDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
dsDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
// Create depth stencil state
ID3D11DepthStencilState * pDSState;
pd3dDevice->CreateDepthStencilState(&dsDesc, &pDSState);
DepthEnable および StencilEnable では、深度テストとステンシル テストを有効 (および無効) にします。 深度テストを無効にし、深度バッファーへの書き込みを禁止するには、DepthEnable を FALSE に設定します。 ステンシル テストを無効にし、ステンシル バッファーへの書き込みを禁止するには、StencilEnable を FALSE に設定します (DepthEnable が FALSE で StencilEnable が TRUE の場合、深度テストはステンシル操作で常に合格します)。
DepthEnable は出力マージャー ステージにのみ影響します。データがピクセル シェーダーに入力される前のクリッピング、深度バイアス、または値のクランプには影響しません。
Depth-Stencil データを OM ステージにバインドする
深度ステンシルの状態をバインドします。
// Bind depth stencil state
pDevice->OMSetDepthStencilState(pDSState, 1);
ビューを使用して深度ステンシル リソースをバインドします。
D3D11_DEPTH_STENCIL_VIEW_DESC descDSV;
descDSV.Format = DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
descDSV.Texture2D.MipSlice = 0;
// Create the depth stencil view
ID3D11DepthStencilView* pDSV;
hr = pd3dDevice->CreateDepthStencilView( pDepthStencil, // Depth stencil texture
&descDSV, // Depth stencil desc
&pDSV ); // [out] Depth stencil view
// Bind the depth stencil view
pd3dDeviceContext->OMSetRenderTargets( 1, // One rendertarget view
&pRTV, // Render target view, created earlier
pDSV ); // Depth stencil view for the render target
レンダー ターゲット ビューの配列は ID3D11DeviceContext::OMSetRenderTargets に渡すことができますが、これらのレンダー ターゲット ビューはすべて単一の深度ステンシル ビューに対応します。 Direct3D 11 のレンダー ターゲット配列は、アプリケーションがプリミティブ レベルで複数のレンダー ターゲットに同時にレンダリングできるようにする機能です。 レンダー ターゲット配列は、 ID3D11DeviceContext::OMSetRenderTargets (基本的に Direct3D 9 で使用されるメソッド) を複数呼び出してレンダー ターゲットを個別に設定するよりもパフォーマンスが向上します。
レンダー ターゲットはすべて同じ種類のリソースである必要があります。 マルチサンプル アンチエイリアシングを使用する場合は、バインドされているすべてのレンダー ターゲットと深度バッファーのサンプル数が同じである必要があります。
バッファーをレンダー ターゲットとして使用する場合、深度ステンシル テストと複数のレンダー ターゲットはサポートされません。
- 同時にバインドできるレンダー ターゲットは 8 個までです。
- すべてのレンダー ターゲットは、すべての次元で同じサイズ (幅と高さ、3D の場合は深度、*Array 型の場合は配列サイズ) である必要があります。
- 各レンダー ターゲットのデータ形式は異なる場合があります。
- 書き込みマスクは、レンダー ターゲットに書き込まれるデータを制御します。 出力書き込みマスクは、レンダーターゲットごとのコンポーネントレベルで、書き込まれるデータを制御します。
高度なステンシル手法
深度ステンシル バッファーのステンシル部分は、合成、デカール、アウトラインなどのレンダリング効果を作成するために使用できます。
- 合成
- デカール
- アウトラインとシルエット
- Two-Sided ステンシル
- Depth-Stencil バッファーをテクスチャ として読み取る
合成
アプリケーションでは、ステンシル バッファーを使用して、2D または 3D イメージを 3D シーンに合成できます。 ステンシル バッファー内のマスクは、レンダリング ターゲット サーフェスの領域を隠すために使用されます。 保存された 2D 情報 (テキストやビットマップなど) は、隠れた領域に書き込むことができます。 または、アプリケーションで、レンダリング ターゲット サーフェスのステンシル マスク領域に追加の 3D プリミティブをレンダリングすることもできます。 シーン全体をレンダリングすることもできます。
多くの場合、ゲームは複数の 3D シーンを合成します。 たとえば、ゲームを運転すると、通常、リアビュー ミラーが表示されます。 ミラーには、ドライバーの背後にある 3D シーンのビューが含まれています。 これは基本的に、ドライバーの前方ビューと合成された 2 番目の 3D シーンです。
デカール貼り
Direct3D アプリケーションでは、デカル処理を使用して、レンダリング ターゲット サーフェスに描画される特定のプリミティブ イメージのピクセルを制御します。 アプリケーションでは、プリミティブのイメージにデカールを適用して、同一平面ポリゴンを正しくレンダリングできるようにします。
たとえば、道路にタイヤ マークと黄色の線を適用する場合、マーキングは道路の上に直接表示されます。 ただし、マーキングと道路の z 値は同じです。 したがって、深度バッファーでは、2 つの間にクリーンな分離が生成されない場合があります。 背面プリミティブの一部のピクセルは、フロント プリミティブの上にレンダリングされ、その逆も可能です。 結果として得られる画像は、フレーム間で輝いているように見えます。 この効果は、zファイティングまたはフリミングと呼ばれます。
この問題を解決するには、ステンシルを使用して、デカールが表示される背面プリミティブのセクションをマスクします。 z バッファリングをオフにし、フロント プリミティブのイメージをレンダー ターゲット サーフェスのマスクされた領域にレンダリングします。
この問題を解決するには、複数のテクスチャ ブレンドを使用できます。
アウトラインとシルエット
ステンシル バッファーを使用すると、アウトラインや silhouetting などのより抽象的な効果を得ることができます。
アプリケーションで 2 つのレンダー パスを実行する場合 (ステンシル マスクを生成するために 1 つ、2 番目にステンシル マスクをイメージに適用する場合)、2 番目のパスではプリミティブが少し小さい場合、結果のイメージにはプリミティブのアウトラインのみが含まれます。 その後、アプリケーションはイメージのステンシル マスク領域を単色で塗りつぶし、プリミティブに浮き出しの外観を与えることができます。
ステンシル マスクがレンダリングするプリミティブと同じサイズと形状の場合、結果のイメージにはプリミティブがあるべき場所に穴が含まれます。 その後、アプリケーションは穴を黒で埋め、プリミティブのシルエットを生成できます。
Two-Sided ステンシル
シャドウ ボリュームは、ステンシル バッファーを使用してシャドウを描画するために使用されます。 アプリケーションは、遮蔽するジオメトリによって投影されたシャドウボリュームを計算するために、シルエットエッジを計算し、それらを光源から離れて押し出して3Dボリュームのセットにします。 その後、これらのボリュームはステンシル バッファーに 2 回レンダリングされます。
最初のレンダリングでは、前方向きの多角形が描画され、ステンシル バッファーの値がインクリメントされます。 2 番目のレンダーでは、シャドウ ボリュームの裏側のポリゴンを描画し、ステンシル バッファーの値を減少させます。 通常、インクリメントされた値とデクリメントされた値はすべて、互いに取り消されます。ただし、シーンは既に通常のジオメトリでレンダリングされているため、シャドウ ボリュームがレンダリングされるときに、一部のピクセルが z バッファー テストに失敗します。 ステンシル バッファーに残っている値は、シャドウ内のピクセルに対応します。 これらの残りのステンシルバッファーの内容がマスクとして使用され、大きく広がる黒い四角形がシーン全体にアルファブレンドされます。 ステンシル バッファーがマスクとして機能すると、シャドウ内のピクセルが暗くなります。
つまり、シャドウ ジオメトリは光源ごとに 2 回描画されるため、GPU の頂点スループットが低下します。 両面ステンシル機能は、この状況を軽減するように設計されています。 この方法では、ステンシル状態の 2 つのセット (下の名前) があり、1 つは前面の三角形にそれぞれ設定され、もう 1 つは背面の三角形に対して設定されます。 この方法では、シャドウ ボリュームごとに、ライトごとに 1 つのパスのみが描画されます。
両面ステンシル実装の例は 、ShadowVolume10 サンプルで確認できます。
テクスチャとしての Depth-Stencil バッファーの読み取り
非アクティブな深度ステンシル バッファーは、シェーダーによってテクスチャとして読み取ることができます。 テクスチャが 2 つのパスでレンダリングされる際に深度ステンシル バッファーを読み取るアプリケーション。最初のパスは深度ステンシル バッファーに書き込み、2 番目のパスはバッファーから読み取ります。 これにより、シェーダーは、バッファーに以前に書き込まれた深度値またはステンシル値を、現在レンダリングされているピクセルの値と比較できます。 比較の結果を使用して、シャドウ マッピングやソフト パーティクルなどのエフェクトをパーティクル システムに作成できます。
深度ステンシル リソースとシェーダー リソースの両方として使用できる深度ステンシル バッファーを作成するには、「Depth-Stencil リソースの 作成 」セクションのサンプル コードにいくつかの変更を加える必要があります。
深度ステンシル リソースには、DXGI_FORMAT_R32_TYPELESSなどの型指定なしの形式が必要です。
descDepth.Format = DXGI_FORMAT_R32_TYPELESS;
深度ステンシル リソースでは、D3D10_BIND_DEPTH_STENCILバインド フラグとD3D10_BIND_SHADER_RESOURCE バインド フラグの両方を使用する必要があります。
descDepth.BindFlags = D3D10_BIND_DEPTH_STENCIL | D3D10_BIND_SHADER_RESOURCE;
さらに、 D3D11_SHADER_RESOURCE_VIEW_DESC 構造体と ID3D11Device::CreateShaderResourceView を使用して、深度バッファーのシェーダー リソース ビューを作成する必要があります。 シェーダー リソース ビューでは、深度ステンシル リソースの作成時に指定された型指定されていない形式(タイプレスフォーマット)に相当する型付きの形式として、DXGI_FORMAT_R32_FLOATが使用されます。
最初のレンダー パスでは、「 OM ステージへのデータ Depth-Stencil バインド 」セクションの説明に従って深度バッファーがバインドされます。 D3D11_DEPTH_STENCIL_VIEW_DESCに渡される形式に注意してください。書式には、DXGI_FORMAT_D32_FLOATなどの型指定された形式が使用されます。 最初のレンダー パスの後、深度バッファーにはシーンの深度値が含まれます。
2 番目のレンダー パスでは、 ID3D11DeviceContext::OMSetRenderTargets 関数を使用して深度ステンシル ビューを NULL または別の深度ステンシル リソースに設定し、シェーダー リソース ビューは ID3D11EffectShaderResourceVariable::SetResource を使用してシェーダーに渡されます。 これにより、シェーダーは最初のレンダリング パスで計算された深度値を検索できます。 最初のレンダー パスの視点が 2 番目のレンダー パスと異なる場合は、深度値を取得するために変換を適用する必要があることに注意してください。 たとえば、シャドウ マッピング手法が使用されている場合、最初のレンダー パスは光源の観点から、2 番目のレンダー パスはビューアーの視点から取得されます。
関連トピック