將陰影圖轉譯為深度緩衝區
從光線的角度轉譯,建立代表陰影體的二維深度圖。 深度圖會遮罩將呈現於陰影中的空間。 《逐步解說:使用 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;
}
請參閱本逐步解說的下一章節,瞭解如何透過深度測試轉譯新增陰影。
意見反應
https://aka.ms/ContentUserFeedback。
即將登場:在 2024 年,我們將逐步淘汰 GitHub 問題作為內容的意見反應機制,並將它取代為新的意見反應系統。 如需詳細資訊,請參閱:提交並檢視相關的意見反應