Renderizar o mapa de sombra para o buffer de profundidadeRender the shadow map to the depth buffer

Faça a renderização do ponto de vista da luz para criar um mapa de profundidade bidimensional que representa o volume de sombra.Render from the point of view of the light to create a two-dimensional depth map representing the shadow volume. O mapa de profundidade mascara o espaço que será renderizado com sombras.The depth map masks the space that will be rendered in shadow. Parte 2 do Guia passo a passo: implementar volumes de sombra usando buffers de profundidade no Direct3D 11.Part 2 of Walkthrough: Implement shadow volumes using depth buffers in Direct3D 11.

Limpar o buffer de profundidadeClear the depth buffer

Sempre limpe o buffer de profundidade antes de renderizar com ele.Always clear the depth buffer before rendering to it.

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

Renderizar o mapa de sombra para o buffer de profundidadeRender the shadow map to the depth buffer

Para a passagem de renderização de sombra, especifique um buffer de profundidade, mas não defina um destino de renderização.For the shadow rendering pass, specify a depth buffer but do not specify a render target.

Especifique o visor de luz, um sombreador de vértice e defina buffers constantes do espaço de luz.Specify the light viewport, a vertex shader, and set the light space constant buffers. Use o conjunto de face frontal desta passagem para otimizar os valores de profundidade definidos no buffer de sombra.Use front face culling for this pass to optimize the depth values placed in the shadow buffer.

Não se esqueça de que, na maioria dos dispositivos, você pode especificar nullptr para o sombreador de pixel (ou simplesmente não especificar um sombreador de pixel).Note that on most devices, you can specify nullptr for the pixel shader (or skip specifying a pixel shader entirely). Porém, alguns drivers podem emitir uma exceção quando você chama a operação de desenho no dispositivo Direct3D com um sombreador de pixel nulo definido.But some drivers may throw an exception when you call draw on the Direct3D device with a null pixel shader set. Para evitar essa exceção, você pode definir um sombreador de pixel mínimo para a passagem de renderização de sombra.To avoid this exception, you can set a minimal pixel shader for the shadow rendering pass. A saída desse sombreador é descartada; ele pode chamar discard em todos os pixels.The output of this shader is thrown away; it can call discard on every pixel.

Renderize os objetos que podem projetar sombras, mas não se preocupe em renderizar geometrias que não possam fazer isso (como o chão de uma sala ou objetos removidos da passagem de sombra para fins de otimização).Render the objects that can cast shadows, but don't bother rendering geometry that can't cast a shadow (like a floor in a room, or objects removed from the shadow pass for optimization reasons).

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
        );
}

Otimizar o tronco de exibição: garanta que a implementação calcule um tronco de exibição firme, para obter o máximo de precisão com o buffer de profundidade.Optimize the view frustum: Make sure your implementation computes a tight view frustum so that you get the most precision out of your depth buffer. Consulte as técnicas comuns para melhorar mapas de profundidade de sombra para conhecer mais dicas sobre técnicas de sombreamento.See Common Techniques to Improve Shadow Depth Maps for more tips on shadow technique.

Sombreador de vértice para passagem de sombraVertex shader for shadow pass

Use uma versão simplificada do sombreador de vértice para renderizar somente a posição do vértice no espaço de luz.Use a simplified version of your vertex shader to render just the vertex position in light space. Não inclua normais de iluminação, transformações secundárias, entre outros.Don't include any lighting normals, secondary transformations, and so on.

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;
}

Na próxima parte deste guia passo a passo, veremos como adicionar sombras pela renderização com teste de profundidade.In the next part of this walkthrough, learn how to add shadows by rendering with depth testing.