0

DXUT を使用して、DirectX9 を使用してグラフィック アプリケーションを作成しています。私のアプリケーションでは、ディファード シェーディングを実装したいと考えています。このライティング方法では、シーン内のライトごとにステンシル ボリューム ( mask ) をレンダリングする必要があります。ボリュームを個別にレンダリングすることを避けるために、DirectX のインスタンス化機能を使用したいと考えています。頂点シェーダー 3.0 とピクセル シェーダー 3.0 を使用して、特定のモデルの複数のインスタンスの描画に成功しましたが、インスタンス化されたステンシル ボリュームを描画しようとすると、バックバッファーの深度ステンシル サーフェスにデータが書き込まれないようです。

遅延シェーディングの私の実装は、擬似コードで次のようになります。

すべてのシーン ジオメトリ (インスタンス化されたジオメトリ パス) をバックバッファに描画します。

  • Z を有効にする ( D3DRS_ZENABLE, TRUE )
  • ZWrite を有効にする ( D3DRS_ZWRITEENABLE, TRUE )
  • ステンシルを無効にする ( D3DRS_STENCILENABLE, FALSE )
  • CullMode の設定 ( D3DRS_CULLMODE, D3DCULL_CCW )
  • ColorWrites を無効にする ( D3DRS_COLORWRITEENABLE, 0 )
  • アルファブレンディングを無効にする ( D3DRS_ALPHABLENDENABLE, FALSE )
  • レンダーシーン

バックバッファーへのポインターを取得します。

  • IDirect3DDevice9::GetRenderTarget( 0, pBackbufferSurface )

3 つの rendertargets ( COLOR( 0 )、NORMAL( 1 )、POSITION( 2 ) ) を設定します。

  • IDirect3DDevice9::SetRenderTarget( 0 -> 2, COLOR -> POSITION)

すべてのシーン ジオメトリを 3 つのレンダー ターゲットに描画します。

  • ColorWrites を有効にする ( D3DRS_COLORWRITEENABLE、CW_RED、CW_GREEN、CW_BLUE、CW_ALPHA )
  • シーンをレンダリング

バックバッファをデバイス RenderTarget 0 にリセットします。

  • IDirect3DDevice9::SetRenderTarget( 0, pBackbufferSurface )

エフェクト テクスチャ ( SrcColor ) を COLOR レンダー ターゲットに設定します。

  • ID3DXEffect::SetTexture( "g_TextureSrcColor", pRTColor )

フルスクリーンのクワッドをレンダリングし、COLOR レンダー ターゲットからサンプルを作成します (シーンをペイントします)。


Instancing Technique を使用してすべてのシーン ライトをステンシルします (ここに実際のコードを示します)。

// set the instance buffer vertex declaration
    hr = pd3dDevice->SetVertexDeclaration( CContentManager::GetInstanceBufferVertexDeclaration() );
    if( FAILED( hr ) )
    {
        DebugStringDX( ClassName, "Failed to IDirect3DDevice9::SetVertexDeclaration( instances )at RenderScene()", __LINE__, hr );
        return hr;
    }

    // render instances of each light( sphere and cone )
    for( UINT i = 0; i < 2; ++i )
    {
        // point to base model
        CXModel *pXBase = ( CXModel* )pCM->GetAppObject( i );
        if( !pXBase )
        {
            DebugStringDX( ClassName, 
                "Failed to retrieve the base light model at index( " + ToString( i ) + " ) at Render()", 
                __LINE__,
                E_POINTER );
            continue;
        }

        // if the model has no instances
        //      there is no reason to try and draw
        UINT ucInstances = pXBase->GetNumInstances();
        if( ucInstances < 1 )
            continue;

        // Set up the geometry data stream
        hr = pd3dDevice->SetStreamSourceFreq( 0,
            ( D3DSTREAMSOURCE_INDEXEDDATA | ucInstances ) );
        if( FAILED( hr ) )
        {
            DebugStringDX( ClassName, "Failed to IDirect3DDevice9::SetStreamSourceFreq( source )( index - " + ToString( i ) + " ) at RenderScene()", __LINE__, hr );
            continue;
        }

        // Set up the instance data stream
        IDirect3DVertexBuffer9 *pVBInstances = pXBase->GetInstanceBuffer();
        hr = pd3dDevice->SetStreamSource( 1, pVBInstances, 0, 
            sizeof( CXModel::sInstanceEntry ) );
        if( FAILED( hr ) )
        {
            DebugStringDX( ClassName, "Failed to IDirect3DDevice9::SetStreamSource( instances )( index - " + ToString( i ) + " ) at RenderScene()", __LINE__, hr );
            continue;
        }

        hr = pd3dDevice->SetStreamSourceFreq( 1,
            ( D3DSTREAMSOURCE_INSTANCEDATA | 1ul ) );
        if( FAILED( hr ) )
        {
            DebugStringDX( ClassName, "Failed to IDirect3DDevice9::SetStreamSourceFreq( instances )( index - " + ToString( i ) + " ) at Render()", __LINE__, hr );
            continue;
        }

        // get light model frame root
        pFrame = pXBase->GetFrameRoot();    
        if( !pFrame )
        {
            DebugStringDX( ClassName, "Failed to CXModel::GetFrameRoot( Light Model ) at Render()", __LINE__, hr );
            continue;
        }

        //------------------------------------------------------------------------------------------------------------
        // Stencil Volume Mask Pass
        //------------------------------------------------------------------------------------------------------------
        dev.SetRenderState( D3DRS_ZENABLE, TRUE );
        dev.SetRenderState( D3DRS_ZWRITEENABLE, FALSE );
        dev.SetRenderState( D3DRS_STENCILENABLE, TRUE );
        dev.SetRenderState( D3DRS_STENCILFUNC, D3DCMP_ALWAYS );
        dev.SetRenderState( D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP );
        dev.SetRenderState( D3DRS_STENCILZFAIL, D3DSTENCILOP_INCR );
        dev.SetRenderState( D3DRS_STENCILPASS, D3DSTENCILOP_KEEP );
        dev.SetRenderState( D3DRS_STENCILWRITEMASK, 0xffffffff );
        dev.SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
        dev.SetRenderState( D3DRS_COLORWRITEENABLE, 0 );

        hr = BeginPass( CFXDeferred::STENCIL );
        if( FAILED( hr ) )
        {
            DebugStringDX( ClassName, "Failed to BeginPass( StencilVolumeMask ) at Render()", __LINE__, hr );
            continue;
        }

        // draw the light model
        hr = DrawStaticModel( pd3dDevice, pFrame, &mWorld, pmView, pmProjection, true, bRenderStrips );
        if( FAILED( hr ) )
        {
            DebugStringDX( ClassName, "Failed to DrawStaticModel( Light Model ) at Render()", __LINE__, hr );
            continue;
        }

        hr = pE->EndPass();
        if( FAILED( hr ) )
        {
            DebugStringDX( ClassName, "Failed to ID3DXEffect::EndPass() at Render()", __LINE__, hr );
            continue;
        }

        //------------------------------------------------------------------------------------------------------------
        // Diffuse Light Pass
        //------------------------------------------------------------------------------------------------------------
        dev.SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
        dev.SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ONE );
        dev.SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE );
        dev.SetRenderState( D3DRS_ZENABLE, FALSE );
        dev.SetRenderState( D3DRS_CULLMODE, D3DCULL_CW );
        dev.SetRenderState( D3DRS_COLORWRITEENABLE, 
            D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_ALPHA );
        dev.SetRenderState( D3DRS_STENCILENABLE, TRUE );
        dev.SetRenderState( D3DRS_STENCILFUNC, D3DCMP_EQUAL );
        dev.SetRenderState( D3DRS_STENCILMASK, 0x1 );
        dev.SetRenderState( D3DRS_STENCILPASS, D3DSTENCILOP_ZERO );
        dev.SetRenderState( D3DRS_STENCILREF, 0x1 );
        dev.SetRenderState( D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP );
        dev.SetRenderState( D3DRS_STENCILFAIL, D3DSTENCILOP_ZERO );

        hr = BeginPass( CFXDeferred::DIFFUSELIGHTSTENCIL );
        if( FAILED( hr ) )
        {
            DebugStringDX( ClassName, "Failed to BeginPass( DiffuseSpecularLightStencilPass ) at Render()", __LINE__, hr );
            continue;
        }

        // draw light model
        hr = DrawStaticModel( pd3dDevice, pFrame, &mWorld, pmView, pmProjection, true, bRenderStrips );
        if( FAILED( hr ) )
        {
            DebugStringDX( ClassName, "Failed to DrawStaticModel( Light Model ) at Render()", __LINE__, hr );
            continue;
        }

        hr = pE->EndPass();
        if( FAILED( hr ) )
        {
            DebugStringDX( ClassName, "Failed to ID3DXEffect::EndPass() at Render()", __LINE__, hr );
            continue;
        }
    }

インスタンス バッファの頂点宣言は次のとおりです。

// create instance vertex declaration
    D3DVERTEXELEMENT9 pElements[] = {
        { 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
        { 0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0 },
        { 0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
        { 1, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1 },
        { 1, 16, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 2 },
        { 1, 32, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 3 },
        { 1, 48, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 4 },
        { 1, 64, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 5 },
        D3DDECL_END()
    };

このメソッドは、インスタンス化せずに正常に機能します...インスタンス化により、深度ステンシルの書き込みが妨げられますか? PIX を使用してデバッグすると、「ピクセルがステンシル テストに失敗しました」と表示されます。レンダリング前にバックバッファをクリアする呼び出しは次のとおりです。

pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL, D3DCOLOR_ARGB( 0, 0, 0, 0 ), 1.0f, 0 ) );

デバイスの作成中に、次のように AutoDepthStencilFormat D3DFMT_D24S8 を使用するように設定を変更します。

// check for D3DFMT_D24S8 AutoDepthStencilFormat
    // if present set the AutoDepthStencilFormat to D3DFMT_D24S8
    if( DXUTGetD3D9Enumeration()->GetPossibleDepthStencilFormatList()->Contains( D3DFMT_D24S8 ) )
    {
        pDeviceSettings->d3d9.pp.AutoDepthStencilFormat = D3DFMT_D24S8;
    }

IDirect3DDevice9::Clear() のステンシル パラメーター (最後のパラメーター) を 1 に変更すると、ステンシル ボリュームはステンシル テストに合格します。ボリューム マスクがバックバッファのピクセルと交差し、そのイベントで、ライトのピクセル カラーが許可されます。これは、次の 2 つの問題のいずれかがあることを示しています。

  1. 'Instanced Geometry Pass' 中にシーン ( オブジェクト ) を描画するとき...オブジェクトが描画されるとき、バックバッファはオブジェクトの深さを保存していません (そのため、ステンシル テストは比較のために '0' の値を持ちます。
  2. ステンシル ボリューム ( ライト ) を描画するとき、バックバッファは描画されたボリュームの深さを格納していません...

これは私のインスタンス化方法によるものですか? シェーダーのバージョン(vs3、ps3)やDXのバージョンによるものでしょうか?

4

1 に答える 1

0

問題は、頂点シェーダー (ステンシル ボリューム マスク用) を vs_3_0 でコンパイルしたことでした... vs_2_0 に変更したところ、正常に動作するようになりました...頂点シェーダー モデル 3.0 を使用する必要があると考えたため、わかりませんインスタンス化で...

于 2013-07-26T18:47:05.157 に答える