次の方法で共有


深度バッファーにシャドウ マップをレンダリングする

ライトの観点からレンダリングして、シャドウ ボリュームを表す 2 次元深度マップを作成します。 深度マップは、影でレンダリングされる空間をマスクします。 チュートリアルのパート 2 : Direct3D 11 で深度バッファーを使用してシャドウ ボリュームを実装する。

深度バッファーをクリアする

レンダリングを行う前に、必ず深度バッファーをクリアしてください。

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

このチュートリアルの次のパートでは、深度テストを使用してレンダリングを してシャドウを追加する方法について説明します。