Direct X 12 – Depth Complexity

Depth Complexity based on DirectX 12 and the Blend demo of Introduction To 3D Game Programming With DirectX 12:

cpp code:

// define the depth complexity level
const int gDepthComplexityLevel = 5;

// constant buffer define the color at different depth complexity level
struct StencilBufferConstants
{
    DirectX::XMFLOAT4 Color = { 0.f, 0.f, 0.f, 0.f };
};
std::unique_ptr<UploadBuffer<StencilBufferConstants>> mStencilBufferCB = nullptr;

// root signature for the depth complexity
ComPtr<ID3D12RootSignature> mStencilBufferRootSignature = nullptr;

bool BlendApp::Initialize()
{
    ...

    // at initialization stage, we create the different color for different depth complexity level.
    // and store the color in the constant buffer.
    mStencilBufferCB = std::make_unique<UploadBuffer>(md3dDevice.Get(), gDepthComplexityLevel, true);
    for (int i = 0; i < gDepthComplexityLevel; i++) 
    { 
        StencilBufferConstants sBC; 
        sBC.Color = XMFLOAT4(1.f / gDepthComplexityLevel * i, 1.f / gDepthComplexityLevel * i, 1.f / gDepthComplexityLevel * i, 1.f / gDepthComplexityLevel * i); 
        mStencilBufferCB.get()->CopyData(i, sBC);
    }

    ...
    return true;
}

void BlendApp::Draw(const GameTimer& gt)
{
    ...

    // after we draw all the render item in the scene.
    // we need to switch to depth complexity's pipeline state object and root signature.
    mCommandList->SetPipelineState(mPSOs["stencilBuffer"].Get());
    mCommandList->SetGraphicsRootSignature(mStencilBufferRootSignature.Get());
    UINT sCBByteSize = d3dUtil::CalcConstantBufferByteSize(sizeof(StencilBufferConstants));

    // we use some post process tech to draw the depth complexity picture.
    // pls refer to the hlsl file.
    mCommandList->IASetVertexBuffers(0, 0, nullptr);
    mCommandList->IASetIndexBuffer(nullptr);
    mCommandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
    for (int i = 0; i < gDepthComplexityLevel; i++) 
    { 
        // choose the corlor for different depth complexity. 
        D3D12_GPU_VIRTUAL_ADDRESS sCBAddress = mStencilBufferCB->Resource()->GetGPUVirtualAddress() + i * sCBByteSize;
        mCommandList->SetGraphicsRootConstantBufferView(0, sCBAddress);
        mCommandList->OMSetStencilRef(i); // set the stencil test benchmark.
        mCommandList->DrawInstanced(3, 1, 0, 0);
    }

    ...
}

void BlendApp::BuildRootSignature()
{
    ...

    // we use the specific root signature for the depth complexity.
    CD3DX12_ROOT_PARAMETER stencilBufferSlotRootParameter[1];
    stencilBufferSlotRootParameter[0].InitAsConstantBufferView(0);
    CD3DX12_ROOT_SIGNATURE_DESC stencilBufferRootSigDesc(1, stencilBufferSlotRootParameter,
        0, nullptr,
        D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);
    hr = D3D12SerializeRootSignature(&stencilBufferRootSigDesc, D3D_ROOT_SIGNATURE_VERSION_1,
        serializedRootSig.GetAddressOf(), errorBlob.GetAddressOf());
    if (errorBlob != nullptr)
    {
        ::OutputDebugStringA((char*)errorBlob->GetBufferPointer());
    }
    ThrowIfFailed(hr);
    ThrowIfFailed(md3dDevice->CreateRootSignature(
        0,
        serializedRootSig->GetBufferPointer(),
        serializedRootSig->GetBufferSize(),
        IID_PPV_ARGS(mStencilBufferRootSignature.GetAddressOf())));
}

void BlendApp::BuildShadersAndInputLayout()
{
    ...

    // specific vertex / pixel shader for depth complexity.
    mShaders["stencilBufferVS"] = d3dUtil::CompileShader(L"Shaders\StencilBuffer.hlsl", nullptr, "VS", "vs_5_0");
    mShaders["stencilBufferPS"] = d3dUtil::CompileShader(L"Shaders\StencilBuffer.hlsl", nullptr, "PS", "ps_5_0");

    ...
}

void BlendApp::BuildPSOs()
{
    // Use depth / stencil settings to record the depth complexity.
    D3D12_DEPTH_STENCIL_DESC depthComplexitySS;
    depthComplexitySS.DepthEnable = true;
    depthComplexitySS.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
    depthComplexitySS.DepthFunc = D3D12_COMPARISON_FUNC_LESS;
    depthComplexitySS.StencilEnable = true;
    depthComplexitySS.StencilReadMask = 0xff;
    depthComplexitySS.StencilWriteMask = 0xff;

    // no matter pixel pass the depth test, we need to add the value in stencil buffer
    depthComplexitySS.FrontFace.StencilFunc = D3D12_COMPARISON_FUNC_ALWAYS;
    depthComplexitySS.FrontFace.StencilPassOp = D3D12_STENCIL_OP_INCR;
    depthComplexitySS.FrontFace.StencilDepthFailOp = D3D12_STENCIL_OP_INCR;
    depthComplexitySS.FrontFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;

    ...
    opaquePsoDesc.DepthStencilState = depthComplexitySS;
    ...

    // PSO for Stencil Buffer Quad.
    D3D12_GRAPHICS_PIPELINE_STATE_DESC stencilBufferPsoDesc = opaquePsoDesc;

    D3D12_DEPTH_STENCIL_DESC stencilBufferDSS;
    stencilBufferDSS.DepthEnable = false;
    stencilBufferDSS.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
    stencilBufferDSS.DepthFunc = D3D12_COMPARISON_FUNC_LESS;
    stencilBufferDSS.StencilEnable = true;
    stencilBufferDSS.StencilReadMask = 0xff;
    stencilBufferDSS.StencilWriteMask = 0xff;

    // we need the draw depth complexity for several times for each level.
    // only the stencil buffer's value match the depth complexity level, then we draw it.
    // but we do not need to update the stencil buffer any longer.
    stencilBufferDSS.FrontFace.StencilFunc = D3D12_COMPARISON_FUNC_EQUAL;
    stencilBufferDSS.FrontFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
    stencilBufferDSS.FrontFace.StencilPassOp = D3D12_STENCIL_OP_KEEP;
    stencilBufferDSS.FrontFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;

    ...

    stencilBufferPsoDesc.DepthStencilState = stencilBufferDSS;
    stencilBufferPsoDesc.InputLayout = { nullptr, 0 };
    stencilBufferPsoDesc.pRootSignature = mStencilBufferRootSignature.Get();
    stencilBufferPsoDesc.VS =
    {
        reinterpret_cast&lt<BYTE*>(mShaders["stencilBufferVS"]->GetBufferPointer()),
        mShaders["stencilBufferVS"]->GetBufferSize()
    };
    stencilBufferPsoDesc.PS =
    {
        reinterpret_cast<BYTE*>(mShaders["stencilBufferPS"]->GetBufferPointer()),
        mShaders["stencilBufferPS"]->GetBufferSize()
    };

    ThrowIfFailed(md3dDevice->CreateGraphicsPipelineState(&stencilBufferPsoDesc, IID_PPV_ARGS(&mPSOs["stencilBuffer"])));
}

HLSL code:

// StencilBuffer.HLSL
cbuffer cbMaterial : register(b0)
{
    float4 color;
};

// for this part, we dont need vertex buffer, index buffer or input layout.
// what we do is to draw a triangle with three vertices.
// this triangle will cover the whole window.
struct VertexOut
{
    float4 Pos : SV_POSITION;
};

// in the NDC space, the position of the vertex will be (x/w, y/w, z/w, 1).
// the id will be 0, 1 and 2.
// so the position will be (-1, 1, 0, 1), (1, 3, 0, 1), (3, -3, 0, 1).
// it means that the triangle is much larger than the window, and we can let hardware to do the clip.
VertexOut VS(uint id : SV_VERTEXID)
{
    VertexOut vout;

    vout.Pos.x = (float)(id / 2) * 4 - 1.0;
    vout.Pos.y = (float)(id % 2) * 4 - 1.0;
    vout.Pos.z = 0.0;
    vout.Pos.w = 1.0;

    return vout;
}

float4 PS(VertexOut pin) : SV_Target
{
    return color;
}

留下评论

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据