그림자 맵을 깊이 버퍼로 렌더링

조명의 관점에서 렌더링하여 섀도 볼륨을 나타내는 2차원 깊이 맵을 생성합니다. 깊이 맵은 섀도로 렌더링될 공간을 마스킹합니다. 연습: 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을 지정하거나 픽셀 셰이더를 완전히 지정하지 않아도 됩니다. 그러나 일부 드라이버는 Null 픽셀 셰이더가 설정된 Direct3D 디바이스에서 그리기를 호출할 경우 예외가 강제로 발생할 수 있습니다. 이 예외를 방지하기 위해 섀도 렌더링 패스에 최소 픽셀 셰이더를 설정할 수 있습니다. 이 셰이더의 출력이 강제 발생됩니다. 모든 픽셀에서 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;
}

이 연습의 다음 부분에서는 깊이 테스트로 렌더링하여 섀도를 추가하는 방법을 알아봅니다.