Condividi tramite


Eseguire il rendering della mappa delle ombre nel buffer di profondità

Eseguire il rendering dal punto di vista della luce per creare una mappa di profondità bidimensionale che rappresenta il volume d'ombra. La mappa di profondità maschera lo spazio che verrà reso nell'ombra. Parte 2 di Guida dettagliata: Implementazione di volumi d'ombra utilizzando i buffer di profondità in Direct3D 11.

Cancellare il buffer di profondità

Cancellare sempre il buffer di profondità prima di eseguirne il rendering.

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

Eseguire il rendering della mappa delle ombre nel buffer di profondità

Per il passaggio di renderizzazione dell'ombra, specificare un buffer di profondità ma non specificare una destinazione di rendering.

Specificare il viewport della luce, un vertex shader e impostare i buffer costanti dello spazio della luce. Per ottimizzare i valori di profondità inseriti nel buffer delle ombre, utilizzare il culling delle facce frontali per questo passaggio.

Si noti che nella maggior parte dei dispositivi è possibile specificare nullptr per il pixel shader (o ignorare completamente la specifica di un pixel shader). Tuttavia, alcuni driver possono generare un'eccezione quando si chiama Draw sul dispositivo Direct3D con un set di pixel shader nullo. Per evitare questa eccezione, è possibile impostare un pixel shader minimo per la fase di rendering delle ombre. L'output di questo shader viene eliminato; può chiamare scartare su ogni pixel.

Eseguire il rendering degli oggetti che possono proiettare ombre, ma non eseguire il rendering della geometria che non può proiettare ombre (ad esempio un pavimento in una stanza o oggetti rimossi dal passaggio delle ombre per motivi di ottimizzazione).

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

Ottimizzare il frustum della vista: Assicurarsi che l'implementazione calcoli un frustum di visualizzazione preciso in modo da ottenere la massima precisione dal buffer di profondità. Vedi Tecniche Comuni per Migliorare le Mappe di Profondità delle Ombreggiature per altri suggerimenti sulle tecniche di ombreggiatura.

Vertex shader per il passaggio ombreggiatura

Usare una versione semplificata dello shader del vertice per eseguire il rendering solo della posizione del vertice nello spazio della luce. Non includere normali di illuminazione, trasformazioni secondarie e così via.

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

Nella parte successiva di questa procedura dettagliata viene illustrato come aggiungere ombreggiature rendering con test di profondità.