Formalize directional shadow runtime contracts

This commit is contained in:
2026-04-13 23:11:28 +08:00
parent 4362008b39
commit 0d6b8bf7d8
15 changed files with 740 additions and 178 deletions

View File

@@ -1,14 +1,15 @@
#include "Rendering/Execution/CameraRenderer.h"
#include "Components/CameraComponent.h"
#include "Rendering/Caches/DirectionalShadowSurfaceCache.h"
#include "Rendering/Caches/FullscreenPassSurfaceCache.h"
#include "Rendering/Execution/DirectionalShadowExecutionState.h"
#include "Rendering/Passes/BuiltinDepthOnlyPass.h"
#include "Rendering/Passes/BuiltinObjectIdPass.h"
#include "Rendering/Passes/BuiltinShadowCasterPass.h"
#include "Rendering/Pipelines/BuiltinForwardPipeline.h"
#include "Rendering/RenderPipelineAsset.h"
#include "Rendering/RenderSurface.h"
#include "Rendering/Shadow/DirectionalShadowRuntime.h"
#include "RHI/RHIResourceView.h"
#include "Scene/Scene.h"
@@ -305,7 +306,7 @@ RenderPassContext BuildFrameStagePassContext(
bool ExecuteFrameStage(
CameraFrameStage stage,
const CameraFramePlan& plan,
const ShadowCasterRenderRequest& resolvedShadowCaster,
const DirectionalShadowExecutionState& shadowState,
const RenderSceneData& sceneData,
CameraFrameExecutionState& executionState) {
const RenderPassContext passContext = BuildFrameStagePassContext(stage, plan, sceneData);
@@ -320,7 +321,7 @@ bool ExecuteFrameStage(
case CameraFrameStage::ShadowCaster:
return ExecuteScenePassRequest(
executionState.shadowCasterPass,
resolvedShadowCaster,
shadowState.shadowCasterRequest,
plan.request.context,
sceneData);
case CameraFrameStage::DepthOnly:
@@ -377,32 +378,6 @@ bool ExecuteFrameStage(
}
}
RenderDirectionalShadowData BuildDirectionalShadowData(
const DirectionalShadowRenderPlan& plan,
RHI::RHIResourceView* shadowMapView) {
RenderDirectionalShadowData shadowData = {};
if (!plan.IsValid() || shadowMapView == nullptr) {
return shadowData;
}
shadowData.enabled = true;
shadowData.viewProjection = plan.cameraData.viewProjection;
shadowData.shadowMap = shadowMapView;
const float texelWorldSize = plan.texelWorldSize > Math::EPSILON
? plan.texelWorldSize
: (plan.orthographicHalfExtent > Math::EPSILON && plan.mapWidth > 0u
? (plan.orthographicHalfExtent * 2.0f) / static_cast<float>(plan.mapWidth)
: 0.0f);
shadowData.mapMetrics.inverseMapSize = Math::Vector2(
1.0f / static_cast<float>(plan.mapWidth),
1.0f / static_cast<float>(plan.mapHeight));
shadowData.mapMetrics.worldTexelSize = texelWorldSize;
shadowData.sampling.enabled = 1.0f;
shadowData.sampling.settings = plan.sampling;
shadowData.casterBias.settings = plan.casterBias;
return shadowData;
}
RenderEnvironmentData BuildEnvironmentData(const CameraFramePlan& plan) {
RenderEnvironmentData environment = {};
const RenderSurface& mainSceneSurface = plan.GetMainSceneSurface();
@@ -450,6 +425,7 @@ CameraRenderer::CameraRenderer(
, m_objectIdPass(std::move(objectIdPass))
, m_depthOnlyPass(std::move(depthOnlyPass))
, m_shadowCasterPass(std::move(shadowCasterPass))
, m_directionalShadowRuntime(std::make_unique<DirectionalShadowRuntime>())
, m_postProcessSurfaceCache(std::make_unique<FullscreenPassSurfaceCache>())
, m_finalOutputSurfaceCache(std::make_unique<FullscreenPassSurfaceCache>()) {
if (m_objectIdPass == nullptr) {
@@ -469,6 +445,7 @@ CameraRenderer::CameraRenderer(std::shared_ptr<const RenderPipelineAsset> pipeli
, m_objectIdPass(std::make_unique<Passes::BuiltinObjectIdPass>())
, m_depthOnlyPass(CreateDefaultDepthOnlyPass())
, m_shadowCasterPass(CreateDefaultShadowCasterPass())
, m_directionalShadowRuntime(std::make_unique<DirectionalShadowRuntime>())
, m_postProcessSurfaceCache(std::make_unique<FullscreenPassSurfaceCache>())
, m_finalOutputSurfaceCache(std::make_unique<FullscreenPassSurfaceCache>()) {
SetPipelineAsset(m_pipelineAsset);
@@ -544,43 +521,9 @@ void CameraRenderer::ResetPipeline(std::unique_ptr<RenderPipeline> pipeline) {
}
}
bool CameraRenderer::ResolveShadowCasterRequest(
const CameraFramePlan& plan,
ShadowCasterRenderRequest& outResolvedShadowCaster,
RHI::RHIResourceView*& outShadowMapView) {
outResolvedShadowCaster = plan.shadowCaster;
outShadowMapView = nullptr;
if (outResolvedShadowCaster.IsRequested()) {
return outResolvedShadowCaster.IsValid();
}
if (!plan.directionalShadow.IsValid()) {
return true;
}
if (m_directionalShadowSurface == nullptr) {
m_directionalShadowSurface = std::make_unique<DirectionalShadowSurfaceCache>();
}
if (!m_directionalShadowSurface->EnsureSurface(plan.request.context, plan.directionalShadow)) {
return false;
}
outResolvedShadowCaster.surface = m_directionalShadowSurface->GetSurface();
outResolvedShadowCaster.clearFlags = RenderClearFlags::Depth;
if (!outResolvedShadowCaster.hasCameraDataOverride) {
outResolvedShadowCaster.hasCameraDataOverride = true;
outResolvedShadowCaster.cameraDataOverride = plan.directionalShadow.cameraData;
}
outShadowMapView = m_directionalShadowSurface->GetDepthShaderView();
return true;
}
bool CameraRenderer::BuildSceneDataForPlan(
const CameraFramePlan& plan,
RHI::RHIResourceView* shadowMapView,
const DirectionalShadowExecutionState& shadowState,
RenderSceneData& outSceneData) {
const RenderSurface& mainSceneSurface = plan.GetMainSceneSurface();
outSceneData = m_sceneExtractor.ExtractForCamera(
@@ -592,10 +535,7 @@ bool CameraRenderer::BuildSceneDataForPlan(
return false;
}
if (plan.directionalShadow.IsValid()) {
outSceneData.lighting.mainDirectionalShadow =
BuildDirectionalShadowData(plan.directionalShadow, shadowMapView);
}
outSceneData.lighting.mainDirectionalShadow = shadowState.shadowData;
outSceneData.globalShaderKeywords = BuildSceneGlobalShaderKeywords(outSceneData);
outSceneData.cameraData.clearFlags = plan.request.clearFlags;
@@ -609,7 +549,7 @@ bool CameraRenderer::BuildSceneDataForPlan(
bool CameraRenderer::ExecuteRenderPlan(
const CameraFramePlan& plan,
const ShadowCasterRenderRequest& resolvedShadowCaster,
const DirectionalShadowExecutionState& shadowState,
const RenderSceneData& sceneData) {
CameraFrameExecutionState executionState = {};
executionState.pipeline = m_pipeline.get();
@@ -628,7 +568,7 @@ bool CameraRenderer::ExecuteRenderPlan(
if (!ExecuteFrameStage(
stageInfo.stage,
plan,
resolvedShadowCaster,
shadowState,
sceneData,
executionState)) {
return false;
@@ -689,24 +629,24 @@ bool CameraRenderer::Render(
return false;
}
ShadowCasterRenderRequest resolvedShadowCaster = {};
RHI::RHIResourceView* shadowMapView = nullptr;
if (!ResolveShadowCasterRequest(plan, resolvedShadowCaster, shadowMapView)) {
DirectionalShadowExecutionState shadowState = {};
if (m_directionalShadowRuntime == nullptr ||
!m_directionalShadowRuntime->ResolveExecutionState(plan, shadowState)) {
Debug::Logger::Get().Error(
Debug::LogCategory::Rendering,
"CameraRenderer::Render failed: ResolveShadowCasterRequest returned false");
"CameraRenderer::Render failed: DirectionalShadowRuntime::ResolveExecutionState returned false");
return false;
}
RenderSceneData sceneData = {};
if (!BuildSceneDataForPlan(plan, shadowMapView, sceneData)) {
if (!BuildSceneDataForPlan(plan, shadowState, sceneData)) {
Debug::Logger::Get().Error(
Debug::LogCategory::Rendering,
"CameraRenderer::Render failed: BuildSceneDataForPlan returned false");
return false;
}
if (!ExecuteRenderPlan(plan, resolvedShadowCaster, sceneData)) {
if (!ExecuteRenderPlan(plan, shadowState, sceneData)) {
Debug::Logger::Get().Error(
Debug::LogCategory::Rendering,
"CameraRenderer::Render failed: ExecuteRenderPlan returned false");