Share via


チュートリアル 14:ステートの管理

Ee416550.d3d10_Tutorial14(ja-jp,VS.85).jpg

まとめ

このチュートリアルでは、Direct3D 10 プログラミングにおいて非常に重要だがしばしば見落とされていた側面である、ステートについて説明します。シェーダーほど魅力的でも派手でもありませんが、ステートの変更は、グラフィック プログラミングにおいては必要不可欠です。事実、同じシェーダーでも、レンダリング時のデバイスのステートが異なるだけで、大幅に異なる視覚的結果を得ることができます。

このチュートリアルでは、ブレンディング ステート、深度ステンシル ステート、およびラスタライザー ステートという 3 つの主要な種類のステート オブジェクトを説明します。チュートリアルの最後には、同じシーンで異なる表現を生み出すためにステートを操作する方法について、さらによく理解しているでしょう。

ソース

(SDK ルート)\Samples\C++\Direct3D10\Tutorials\Tutorial14

ブレンディング ステート

まず、アルファ ブレンディングという用語について説明します。アルファ ブレンディングとは、画面の特定の位置に既に存在するピクセルの色を使用して、その位置に描画されるピクセルの色を変更することを指します。ブレンディング ステート (API から直接使用される場合は ID3D10BlendState、および FX で使用される場合は BlendState) を使用すると、開発者は、新しいピクセルと古いピクセルとの間でのこのような操作を指定できるようになります。ブレンディング ステートを既定値に設定すると、ラスター化処理時に、指定した画面座標に既に存在するピクセルが単にピクセルによって上書きされます。その位置に描画されていた古いピクセルについての情報は失われます。

例を示すために、アプリケーションでタクシーの中からの都市の景色を描画していることにします。何千ものビル、歩道、電柱、ごみ箱、および都市を構成するその他のオブジェクトを描画しました。タクシーの内部も描画しました。ここで、最後の手順として、実際にガラス越しにのぞいているように見えるよう、タクシーの窓を描画する必要があります。残念なことに、ガラス メッシュのラスター化処理時に描画されるピクセルにより、画面のそれらの位置に既に存在するピクセルがすべて上書きされます。これには、歩道、電柱、およびその他すべての都市のオブジェクトと共に、美しい都市のシーンが含まれています。タクシーのガラス窓を描画するときに、既に画面上にある情報を含めることが可能なら、それはすばらしいことです。現在のピクセル シェーダーのコードを最小限に変更することでこれを実現できるなら、さらにすばらしいでしょう。

これがまさに、ブレンディング ステートによってもたらされる効果です。これを示すために、モデルとクワッドでシーンを構成します。

    // Load the mesh    V_RETURN( g_Mesh.Create( pd3dDevice, L"Tiny\\tiny.x", (D3D10_INPUT_ELEMENT_DESC*)layout, 3 ) );

このクワッドには異なる頂点フォーマットがあるため、異なる入力レイアウトの記述が必要なことに注意してください。

    // Create a screen quad    const D3D10_INPUT_ELEMENT_DESC quadlayout[] =    {        { L"POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },        { L"TEXCOORD0", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 16, D3D10_INPUT_PER_VERTEX_DATA, 0 },    };    g_pTechniqueQuad[0]->GetPassByIndex( 0 )->GetDesc( &PassDesc );    V_RETURN( pd3dDevice->CreateInputLayout( quadlayout, 2, PassDesc.pIAInputSignature, &g_pQuadLayout ) );    ...    D3D10_SUBRESOURCE_DATA InitData;    InitData.pSysMem = svQuad;    InitData.SysMemPitch = 0;    InitData.SysMemSlicePitch = 0;    V_RETURN( pd3dDevice->CreateBuffer( &vbdesc, &InitData, &g_pScreenQuadVB ) );

シーンをレンダリングすると、クワッドが上に描画された、人物のモデルが表示されます。

Ee416550.d3d10_tutorial14_Figure1(ja-jp,VS.85).jpg

この人物が都市を表し、クワッドが実際のガラスの窓枠であると想像してください。アプリケーションを起動すると、状況は上で示したとおりになり、ガラス越しに見ることはできません。しかし、ドロップダウン ボックスから別のクワッド レンダリング モードを選択すると、すぐにクワッド越しに見えるようになります。それは、まるでガラスの面のようです。

Ee416550.d3d10_tutorial14_Figure2(ja-jp,VS.85).jpg

事実、別のクワッド レンダリング モードを選択したときにアプリケーションによって実行されることは、クワッドのレンダリングに使用している FX ファイル内のテクニックの変更のみです。たとえば、コンボ ボックス内の [RenderQuadSolid] は、FX ファイル内の次のテクニックのことを示しています。

    technique10 RenderQuadSolid    {        pass P0        {            SetVertexShader( CompileShader( vs_4_0, QuadVS() ) );            SetGeometryShader( NULL );            SetPixelShader( CompileShader( ps_4_0, QuadPS() ) );                            SetBlendState( NoBlending, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF );        }    }

SetVertexShader、SetGeometryShader、および SetPixelShader 関数については、この時点ではよく理解している必要があります。それらをよく知らない場合は、チュートリアル 10 ~ 12 を参照してください。最後の行は、ここで焦点を当てている部分です。これは、FX ファイル内のブレンディング ステートの設定方法です。NoBlending は、実際には、FX ファイルの先頭で定義されている状態構造体を参照しています。この構造体は、1 つ目 (0) のレンダー ターゲットのブレンディングを無効にします。

    BlendState NoBlending    {        BlendEnable[0] = FALSE;    };

既に説明したように、このブレンディング ステートは、面白いことは何も実行しません。アルファ ブレンディングが無効になっているため、人物のレンダリング時には、単純に、画面に配置されている既存のピクセルがクワッドのピクセルによって上書きされます。しかし、[Quad Render Mode] ボックスの一覧から [RenderQuadSrcAlphaAdd] を選択すると、これがさらに面白くなります。これにより、RenderQuadSrcAlphaAdd テクニックを使用してレンダリングするようにクワッドが変更されます。

    technique10 RenderQuadSrcAlphaAdd    {        pass P0        {            SetVertexShader( CompileShader( vs_4_0, QuadVS() ) );            SetGeometryShader( NULL );            SetPixelShader( CompileShader( ps_4_0, QuadPS() ) );                            SetBlendState( SrcAlphaBlendingAdd, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF );        }    }

このテクニックをよく見ると、これと RenderQuadSolid テクニックとの間に 2 つの違いがあることがわかります。1 つ目は名前です。2 つ目は非常に重要な違いであり、ブレンディング ステートが SetBlendState へ渡されるという点です。NoBlending ブレンディング ステートを渡す代わりに、FX ファイルの先頭で定義されている SrcAlphBlendingAdd ブレンディング ステートを渡しています。

    BlendState SrcAlphaBlendingAdd    {        BlendEnable[0] = TRUE;        SrcBlend = SRC_ALPHA;        DestBlend = ONE;        BlendOp = ADD;        SrcBlendAlpha = ZERO;        DestBlendAlpha = ZERO;        BlendOpAlpha = ADD;        RenderTargetWriteMask[0] = 0x0F;    };

このブレンディング ステートは、前回のものより多少複雑です。ブレンディングは、1 つ目 (0) のレンダー ターゲットに対して有効になります。すべての Blend State パラメーターの詳細については、D3D10_BLEND_DESC に関するドキュメントを参照してください。ここでは、この関数での Direct3D 10 への指示方法について簡単な概要を示します。このテクニックを使用してクワッドをレンダリングする場合は、フレームバッファーへレンダリングされようとしているピクセルが、単純に既存のピクセルと置き換えられることはありません。代わりに、次のような公式を使用して、その色が変更されます。

    outputPixel = ( SourceColor*SourceBlendFactor ) BlendOp ( DestColor*DestinationBlendFactor )    SourceColor is a pixel being rendered when we draw the quad.    DestColor is the pixel that already exists in the framebuffer (from drawing the person)    BlendOp is the BlendOp from the SrcAlphaBlendingAdd blend structure    SourceBlendFactor is SrcBlend in the SrcAlphaBlendingAdd blend structure    DestinationBlendFactor is DestBlend in the SrcAlphaBlendingAdd blend structure

上の SrcAlphaBlendingAdd 構造体を使用することにより、この式を次のように変換できます。

    OutputPixel = ( SourceColor.rgba * SourceColor.aaaa ) ADD ( DestColor.rgba * (1,1,1,1) )

視覚的には、これを次の図によって表すことができます。

Ee416550.d3d10_tutorial14_AlphaBlend(ja-jp,VS.85).jpg

つまり、出力される色は、描画を実行する時点で既にフレームバッファーに存在していた色によって異なります。コンボ ボックスで異なるモードを選択すると、異なるテクニック (したがって、異なるブレンディング ステート) を使用してクワッドが描画されます。各ブレンディング ステートによって変数が方程式に変更されるため、それらすべてを試すようにしてください。ブレンディング ステートを見るだけで起こる結果を予測できるかどうかを見てみてください。

ラスタライザー ステート

選択されたブレンディング ステートにかかわらず、人物の中央が多少異なる方向を向いていることに気付いたでしょうか。一部のポリゴンは、元の位置とは異なる位置に表示されています。人物の足が、まるで直立した筒が半分にカットされているかのように見えることがありました。これについては、ラスタライザー ステートという、次のステート オブジェクトの説明が必要になります。

ラスタライザー ステート (API を通じて使用される場合は ID3D10RasterizerState、および FX を通じて使用される場合は RasterizerState) を使用すると、三角形を実際に画面にレンダリングする方法を制御できます。ブレンディング ステートに関する前のセクションと同様に、FX インターフェイスを通じたラスタライザー ステートの制御については説明しません。これは、FX システムではそれらを使用できないということではありません。実際に、FX でのラスタライザー ステートの使用は、FX でのブレンディング ステートの使用と同じくらい簡単です。ただし、ここでは、Direct3D 10 API を使用して FX 以外のステート管理について知るために、この機会を利用します。

名前からわかるように、ラスタライザー ステートは、画面でのポリゴンのラスター化方法を制御します。チュートリアルの開始時には、ポリゴンはカリングされていません。これは、ポリゴンが自分の方を向いているか、自分から離れる方向を向いている場合に、それらがすべて同等に描画されることを意味します。これが、一部の暗いポリゴンが人物から "突き出して見える" 理由です。この動作を変更するには、まず、目的の動作を定義するラスタライザー ステートを作成する必要があります。ここではこれを FX インターフェイスではなく API によって実行しているため、ブレンディング ステートとは処理が多少異なります。次のコードは、LoadRasterizerStates 関数からの抜粋です。

    D3D10_FILL_MODE fill[MAX_RASTERIZER_MODES] =     {         D3D10_FILL_SOLID,        D3D10_FILL_SOLID,        D3D10_FILL_SOLID,        D3D10_FILL_WIREFRAME,        D3D10_FILL_WIREFRAME,        D3D10_FILL_WIREFRAME    };    D3D10_CULL_MODE cull[MAX_RASTERIZER_MODES] =     {        D3D10_CULL_NONE,        D3D10_CULL_FRONT,        D3D10_CULL_BACK,        D3D10_CULL_NONE,        D3D10_CULL_FRONT,        D3D10_CULL_BACK    };    for( UINT i=0; i<MAX_RASTERIZER_MODES; i++ )    {        D3D10_RASTERIZER_DESC rasterizerState;        rasterizerState.FillMode = fill[i];        rasterizerState.CullMode = cull[i];        rasterizerState.FrontCounterClockwise = true;        rasterizerState.DepthBias = false;        rasterizerState.DepthBiasClamp = 0;        rasterizerState.SlopeScaledDepthBias = 0;        rasterizerState.DepthClipEnable = true;        rasterizerState.ScissorEnable = false;        rasterizerState.MultisampleEnable = false;        rasterizerState.AntialiasedLineEnable = false;        pd3dDevice->CreateRasterizerState( &rasterizerState, &g_pRasterStates[i] );        g_SampleUI.GetComboBox(IDC_SCENERASTERIZER_MODE)->AddItem( g_szRasterizerModes[i], (void*)(UINT64)i );    }

このコードで実行していることは、必要な情報を D3D10_RASTERIZER_DESC 構造体に入力してから、ID3D10Device::CreateRasterizerState を呼び出して ID3D10RasterizerState オブジェクトへのポインターを取得することのみです。ループでは、強調するラスタライザー ステートの各種類に対して 1 つのステートを作成します。最初のステートでは、描画モードとして D3D10_FILL_SOLID を、カリング モードとして D3D10_CULL_NONE を使用しており、これが、人物の外観が奇妙に見える原因となっています。これを変更するには、[Scene Rasterizer Mode] ボックスの一覧から 2 番目のラスタライザー ステートを選択します。このオブジェクトは、後でレンダリング前にステートを設定するために使用できます。これが、現在選択されているラスタライザー ステートを OnD3D10FrameRender に設定する方法です。

    //    // Update the Cull Mode (non-FX method)    //    pd3dDevice->RSSetState(g_pRasterStates[ g_eSceneRasterizerMode ]);

異なるステートが設定されるかデバイスが破棄されるまで、後続のすべての描画処理において、すべてのステートのセットが "維持"されるということに注意する必要があります。これは、ラスタライザー ステートを OnD3D10FrameRender に設定した場合は、別のラスタライザー ステートが設定されるまで、同じラスタライザー ステートが後続のすべての描画処理に適用されるということを意味します。

[Scene Rasterizer Mode] ボックスの一覧から 2 番目のオプションを選択すると、人物の外観ははるかに悪くなり、クワッドは単になくなります。

Ee416550.d3d10_tutorial14_Figure3(ja-jp,VS.85).jpg

これは、前方を向いた三角形を描画しないように Direct3D 10 に指示するカリング モードを選択したためです。次のラスタライザー ステート (D3D10_CULL_BACK および D3D10_FILL_SOLID) では、目的とする結果をもたらさなければなりません (次のセクションで説明する、頭部の周りに散在する黒い三角形以外について)。

Ee416550.d3d10_tutorial14_Figure4(ja-jp,VS.85).jpg

どの三角形を描画するか (または描画しないか) ということのほかに、ラスタライザー ステートによって、レンダリングに関するその他のさまざまな側面を制御できます。 さまざまなシーン ラスタライザー モードの選択肢を試したり、LoadRasterizerStates 内のコードを変更して、どうなるか確認してください。

深度ステンシル ステート

最後のセクションでは、カリング モードを D3D10_CULL_BACK に、描画モードを D3D10_FILL_SOLID に設定することで、優れた外観の人物を中央に表示します。しかし、顔の周りに、まだいくつかの黒いポリゴンが表示されています。これは、それらのポリゴンが、まだ、頭の反対側にある場合でも前方を向くように分類されているためです。ここで、深度ステンシル ステートが関わってきます。このステート オブジェクトは、実際には Direct3D 10 パイプラインの 2 つの異なる部分を制御します。1 つ目は深度バッファーです。

基本的なレベルでは、深度バッファーには、ビュー プレーンからのピクセルの距離を表す値が格納されます。この値が大きくなるほど、距離は遠くなります。深度バッファーは、バックバッファーと同じ解像度 (高さおよび幅) となります。それ自体は、この状況においてはあまり役立たないように見えます。しかし、深度ステンシル ステートによって、既にフレームバッファー内のその位置にあるピクセルの深度に基づいて、現在のピクセルを変更できるようになります。

深度ステンシル ステートは、LoadDepthStencilStates 関数内で作成されます。このメソッドは、LoadRasterizerStates に似ています。ここでは、D3D10_DEPTH_STENCIL_DESC 構造体のいくつかのパラメーターについて説明します。それらのうち最も重要なのは DepthEnable です。これは、深度テストが公平に機能しているかどうかを判断します。おわかりのように、アプリケーションの起動時には、深度テストは無効になっています。これが、頭の後ろ側にある、前面を向いた毛髪のスパイクがまだ表示されている原因です。

深度ステンシル ステートの設定も、1 つの例外を除いては、ラスタライザー ステートの設定と非常によく似ています。それらには、追加のパラメーターがあります。このパラメーターは StencilRef です。これについては、次のセクションで説明します。

    //    // Update the Depth Stencil States (non-FX method)    //    pd3dDevice->OMSetDepthStencilState(g_pDepthStencilStates[ g_eSceneDepthStencilMode ], 0);

[Scene Depth/Stencil Mode] ボックスの一覧の 2 番目の深度ステンシル ステートを使用すると、深度テストが有効になります。深度テストを有効にする場合は、実行するテストの種類を Direct3D 10 に指示する必要があります。その方程式を次に示します。

    DrawThePixel? = DepthOfCurrentPixel D3D10_COMPARISON CurrentDepthInDepthBuffer    D3D10_COMPARISON is the comparison function in the DepthFunc parameter of the D3D10_DEPTH_STENCIL_DESC

2 番目の深度ステンシル ステートから DepthFunc の値を代入することにより、方程式のために以下を取得します。

    DrawThePixel? = DepthOfCurrentPixel D3D10_COMPARISON_LESS CurrentDepthInDepthBuffer

これは、"この位置に既に格納されている深度ではなく深度が LESS の場合のみ、現在のピクセルを描画する" ということを意味しています。さらに、DepthWriteMask を D3D10_DEPTH_WRITE_MASK_ALL に設定して、描画する深度値よりも後続のすべてのピクセルが前面に近くなるように、深度がこの位置の深度バッファーに置かれるようにします (テストに合格するため)。

これにより、欠点なく人物が描画されます。背面にある、前方を向いた毛髪のスパイクはもう表示されなくなります。それらは、顔の前面により近い三角形によって上書きされるか、前方にある三角形がそれらより前面に近い深度値を持つため描画されないかのどちらかです。これにより、クワッドに関して明らかになったこともあります。今までは、それが人物の前面にあるように見えていました。これで、それが実際には人物と交差していることがわかりました。

Ee416550.d3d10_tutorial14_Figure5(ja-jp,VS.85).jpg

さまざまな DepthFunc 値を試し、起こることを確認してください。

ステンシル バッファーを使用したレンダリング

ステンシル パラメーターは、深度ステンシル バッファーの一部ですが、それらの複雑性のため、それ自体の部分を持つに値します。

ステンシル バッファーは、深度バッファーのようなバッファーとして考えることができます。深度バッファーのように、それには、レンダー ターゲットと同じ寸法があります。ただし、深度値を格納する代わりに、ステンシル バッファーには整数値を格納します。それらの値は、アプリケーションのみに意味があります。深度ステンシル ステートのステンシル部分は、それらの値がそこにたどり着く方法、およびアプリケーションに対するそれらの意味を決定します。

深度バッファーの深度テストのように、ステンシル バッファーにはステンシル テストがあります。このステンシル テストにより、入力されたピクセル値と、ステンシル バッファー内の現在の値を比較できます。ただし、深度テストの結果でこの比較を補強することもできます。これが意味することを確認するために、ステンシル テストの設定の 1 つについて説明します。次の情報は、LoadDepthStencilStates 関数内のループの 5 回目の繰り返しからもたらされたものです。これは、[Scene Depth/Stencil Mode] ボックスの一覧の 5 番目の深度ステンシル ステートを示しています。

    D3D10_DEPTH_STENCIL_DESC dsDesc;    dsDesc.DepthEnable = TRUE;    dsDesc.DepthWriteMask = D3D10_DEPTH_WRITE_MASK_ALL;    dsDesc.DepthFunc = D3D10_COMPARISON_LESS;    dsDesc.StencilEnable = TRUE    dsDesc.StencilReadMask = 0xFF;    dsDesc.StencilWriteMask = 0xFF;    // Stencil operations if pixel is front-facing    dsDesc.FrontFace.StencilFailOp = D3D10_STENCIL_OP_KEEP;    dsDesc.FrontFace.StencilDepthFailOp = D3D10_STENCIL_OP_INCR;    dsDesc.FrontFace.StencilPassOp = D3D10_STENCIL_OP_KEEP;    dsDesc.FrontFace.StencilFunc = D3D10_COMPARISON_ALWAYS;    // Stencil operations if pixel is back-facing    dsDesc.BackFace.StencilFailOp = D3D10_STENCIL_OP_KEEP;    dsDesc.BackFace.StencilDepthFailOp = D3D10_STENCIL_OP_INC;    dsDesc.BackFace.StencilPassOp = D3D10_STENCIL_OP_KEEP;    dsDesc.BackFace.StencilFunc = D3D10_COMPARISON_ALWAYS;

前のセクションから、深度テストが、その位置にある古い深度値よりその面に近いピクセルを通過させるように設定されるということがわかりました。しかし、ここでは、StencilEnable を TRUE に設定することによってステンシル テストを有効にしています。また、StencilReadMask と StencilWriteMask に、ステンシル バッファーのすべてのビットに対して読み書き可能な値を設定しました。

次は、ステンシル設定の要点を説明します。ステンシル処理では、ラスター化されている三角形が前向きか後ろ向きかによって異なる効果を得ることができます (ラスタライザー ステートを使用して前向きまたは後ろ向きのポリゴンのみを描画するように選択できることを思い出してください)。簡潔にするために、前向きのポリゴンと後ろ向きのポリゴンに対して同じ操作を使用します。そのため、FrontFace 処理についてのみ説明します。FrontFace.StencilFailOp を D3D10_STENCILL_OP_KEEP に設定します。これは、ステンシル テストに失敗した場合にステンシル バッファー内に現在の値を保持することを意味します。FrontFace.StencilDepthFailOp を D3D10_STENCIL_OP_INC に設定します。これは、深度テストに失敗した場合にステンシル バッファー内の値を 1 増加させることを意味します。FrontFace.STencilPassOp を D3D10_STENCIL_OP_KEEP に設定します。これは、ステンシル テストに合格した場合に現在の値を保持することを意味します。最終的には、FrontFace.StencilFunc は、実際にステンシル テスト (深度テストではない) に合格したかどうかを判断するために使用される比較を表します。これには、任意の D3D10_COMPARISON 値を使用できます。たとえば、D3D10_COMPARISON_LESS は、現在のステンシル値が、ステンシル バッファー内に存在するステンシル値より小さかった場合のみ、ステンシル テストに合格します。しかし、この現在の値はどこからもたらされるのでしょうか。それは、OMSetDepthStencilState 関数への 2 番目のパラメーター (StencilRef パラメーター) です。

    //    // Update the Depth Stencil States (non-FX method)    //    pd3dDevice->OMSetDepthStencilState(g_pDepthStencilStates[ g_eSceneDepthStencilMode ], 0);

この例では、StencilRef パラメーターは、ステンシル比較関数において重要ではありません。なぜなら、StencilFunc を D3D10_COMPARISON_ALWAYS に設定したためです。これは、"常に" テストに合格することを意味します。

この深度ステンシル バッファーを見てわかることは、ピクセルが深度テストに "失敗" すると、ステンシル バッファー内のその位置の値がインクリメントされるということです。ステンシル バッファーに 0 を入力した場合 (OnD3D10FrameRender の初めに行う)、ステンシル バッファー内の 0 以外のすべての値が、ピクセルが深度テストに失敗した位置となります。

実際にこのステンシル バッファーを視覚化できるとしたら、描画しようとしたものより前方に他のものが存在するようなシーンにおいて、すべての平面を判別できます。つまり、既に存在するオブジェクトの後ろに描画しようとしたものの場所がわかります。

残念なことに、ShowMeTheStencilBuffer という Direct3D 10 関数はありません。幸い、同様のことを行う FX テクニックを作成できます。深度ステンシル ステートを Direct3D 10 API と同様に FX システムでも簡単に設定できるということを示すために、FX での深度ステンシル ステートの使用方法を示してステンシル バッファーの内容を確認します。

人物とクワッドの両方が描画されたら、ビューポート全体を覆う別のクワッドをレンダリングします。ビューポート全体を覆うため、前のレンダリング処理によって影響を受けた可能性のあるすべてのピクセルにアクセスできます。このクワッドのレンダリングに使用するテクニックは、FX ファイル内の RenderWithStencil です。

    technique10 RenderWithStencil    {        pass P0        {            SetVertexShader( CompileShader( vs_4_0, ScreenQuadVS() ) );            SetGeometryShader( NULL );            SetPixelShader( CompileShader( ps_4_0, QuadPS() ) );                           SetBlendState( NoBlending, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF );            SetDepthStencilState( RenderWithStencilState, 0 );        }    }

ブレンディング ステートの設定に加えて、深度ステンシル ステートも RenderWithStencilState に設定することに注意してください。2 番目のパラメーターは、StencilRef 値を 0 に設定します。FX ファイルの先頭で定義されている RenderWithStencilState を見てみましょう。

    DepthStencilState RenderWithStencilState    {        DepthEnable = false;        DepthWriteMask = ZERO;        DepthFunc = Less;            // Setup stencil states        StencilEnable = true;        StencilReadMask = 0xFF;        StencilWriteMask = 0x00;            FrontFaceStencilFunc = Not_Equal;        FrontFaceStencilPass = Keep;        FrontFaceStencilFail = Zero;            BackFaceStencilFunc = Not_Equal;        BackFaceStencilPass = Keep;        BackFaceStencilFail = Zero;    };

最初に注目する点は、これが cpp ファイルの LoadDepthStencilStates 関数内で見つけた D3D10_DEPTH_STENCIL_DESC に似ているということです。値は異なりますが、メンバーは同じです。最初に、深度テストを無効にします。次にステンシル テストを有効にしますが、StencilWriteMask を 0 に設定します。ここでは、ステンシル値の読み取りのみが必要となります。最後に、前面と背面の両方に対して、StencilFunc を Not_Equal に、StencilPass を Keep に、および StencilFail を Zero に設定します。ステンシル テストは、現在の入力値と、ステンシル バッファー内に既に格納されている値とをテストするということを忘れないでください。この場合は、SetDepthStencilState(RenderWithStencilState, 0) の呼び出し時に、入力値 (StencilRef) を 0 に設定します。したがって、ステンシル バッファーが 0 (StencilRef) ではない場合にステンシル テストに合格するということを示すように、このステートを変換できます。合格した場合は、ピクセル シェーダーから受け取ったピクセルを "保持" し、それをフレーム バッファーに書き込みます。失敗した場合は、受け取ったピクセルを破棄するため、それが描画されることはありません。したがって、クワッドを覆う画面は、ステンシル バッファーが 0 以外の位置でのみ描画されます。

Ee416550.d3d10_tutorial14_Figure6(ja-jp,VS.85).jpg

[Scene Depth/Stencil Mode] ボックスの一覧から異なる項目を選択すると、深度バッファーおよびステンシル バッファーへの入力方法が変更されます。したがって、最後に描画されるスクリーン サイズのクワッドが実際にどのくらい画面上に配置されるかが変更されます。これらの組み合わせの中には、何も出力しないものもあります。奇妙な効果を生み出すものもあります。それらを適用する前に、どれが何を行うかを確認してみてください。