共用方式為


將陰影圖轉譯為深度緩衝區

從光線的角度轉譯,建立代表陰影體的二維深度圖。 深度圖會遮罩將呈現於陰影中的空間。 《逐步解說:使用 Direct3D 11 中的深度緩衝區實作陰影體》第 2 部分。

清除深度緩衝區

在轉譯至深度緩衝區前,一律予以清除。

context->ClearRenderTargetView(m_deviceResources->GetBackBufferRenderTargetView(), DirectX::Colors::CornflowerBlue);
context->ClearDepthStencilView(m_shadowDepthView.Get(), D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);

將陰影圖轉譯為深度緩衝區

針對陰影轉譯階段,請指定深度緩衝區,但不要指定轉譯目標。

指定光線檢視區、頂點著色器,並設定光線空間常數緩衝區。 針對此階段使用正面剔除,最佳化放置於陰影緩衝區的深度值。

請注意,在大部分裝置上,您可以指定像素著色器的 nullptr (或完全略過指定像素著色器)。 但是,如果 Direct3D 裝置的像素著色器設為 null,您呼叫該裝置上的繪製時,部分驅動程式可能會擲回例外狀況。 若要避免這個例外狀況,您可以為陰影轉譯階段設定最精簡的像素著色器。 此著色器的輸出已丟棄;該著色器可對每個像素呼叫 discard

轉譯可投射陰影的物件,但不要轉譯無法投射陰影的幾何 (例如:室內地板,或為了最佳化而從陰影階段移除的物件)。

void ShadowSceneRenderer::RenderShadowMap()
{
    auto context = m_deviceResources->GetD3DDeviceContext();

    // Render all the objects in the scene that can cast shadows onto themselves or onto other objects.

    // Only bind the ID3D11DepthStencilView for output.
    context->OMSetRenderTargets(
        0,
        nullptr,
        m_shadowDepthView.Get()
        );

    // Note that starting with the second frame, the previous call will display
    // warnings in VS debug output about forcing an unbind of the pixel shader
    // resource. This warning can be safely ignored when using shadow buffers
    // as demonstrated in this sample.

    // Set rendering state.
    context->RSSetState(m_shadowRenderState.Get());
    context->RSSetViewports(1, &m_shadowViewport);

    // Each vertex is one instance of the VertexPositionTexNormColor struct.
    UINT stride = sizeof(VertexPositionTexNormColor);
    UINT offset = 0;
    context->IASetVertexBuffers(
        0,
        1,
        m_vertexBuffer.GetAddressOf(),
        &stride,
        &offset
        );

    context->IASetIndexBuffer(
        m_indexBuffer.Get(),
        DXGI_FORMAT_R16_UINT, // Each index is one 16-bit unsigned integer (short).
        0
        );

    context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
    context->IASetInputLayout(m_inputLayout.Get());

    // Attach our vertex shader.
    context->VSSetShader(
        m_simpleVertexShader.Get(),
        nullptr,
        0
        );

    // Send the constant buffers to the Graphics device.
    context->VSSetConstantBuffers(
        0,
        1,
        m_lightViewProjectionBuffer.GetAddressOf()
        );

    context->VSSetConstantBuffers(
        1,
        1,
        m_rotatedModelBuffer.GetAddressOf()
        );

    // In some configurations, it's possible to avoid setting a pixel shader
    // (or set PS to nullptr). Not all drivers are tolerant of this, so to be
    // safe set a minimal shader here.
    //
    // Direct3D will discard output from this shader because the render target
    // view is unbound.
    context->PSSetShader(
        m_textureShader.Get(),
        nullptr,
        0
        );

    // Draw the objects.
    context->DrawIndexed(
        m_indexCountCube,
        0,
        0
        );
}

最佳化檢視範圍:確定實作過程會計算緊密的檢視範圍,以從深度緩衝區獲得最精確的結果。 如需有關陰影技巧的詳細資訊,請參閱<改善陰影深度圖的常見技巧>。

陰影階段的頂點著色器

使用簡化版頂點著色器,只轉譯光線空間的頂點位置。 請勿包含任何光源法線、次要轉換等等。

PixelShaderInput main(VertexShaderInput input)
{
    PixelShaderInput output;
    float4 pos = float4(input.pos, 1.0f);

    // Transform the vertex position into projected space.
    pos = mul(pos, model);
    pos = mul(pos, view);
    pos = mul(pos, projection);
    output.pos = pos;

    return output;
}

請參閱本逐步解說的下一章節,瞭解如何透過深度測試轉譯新增陰影。