refactor(rendering): move directional shadow execution defaults into pipeline

This commit is contained in:
2026-04-15 21:48:41 +08:00
parent 02438762fd
commit e23d9710e7
6 changed files with 162 additions and 14 deletions

View File

@@ -51,6 +51,7 @@ struct MockPipelineState {
int initializeCalls = 0;
int shutdownCalls = 0;
int configureRenderSceneDataCalls = 0;
int configureDirectionalShadowExecutionStateCalls = 0;
int renderCalls = 0;
int recordMainSceneCalls = 0;
int executeRecordedMainSceneCalls = 0;
@@ -86,6 +87,10 @@ struct MockPipelineState {
bool lastBlackboardMainDirectionalShadowValid = false;
bool lastBlackboardObjectIdColorValid = false;
std::function<void(const CameraFramePlan&, RenderSceneData&)> configureRenderSceneData = {};
std::function<bool(
const CameraFramePlan&,
const DirectionalShadowSurfaceAllocation&,
DirectionalShadowExecutionState&)> configureDirectionalShadowExecutionState = {};
std::vector<CameraComponent*> renderedCameras;
std::vector<RenderClearFlags> renderedClearFlags;
std::vector<XCEngine::Math::Color> renderedClearColors;
@@ -453,6 +458,24 @@ public:
RenderPipeline::ConfigureRenderSceneData(plan, sceneData);
}
bool ConfigureDirectionalShadowExecutionState(
const CameraFramePlan& plan,
const DirectionalShadowSurfaceAllocation& shadowAllocation,
DirectionalShadowExecutionState& shadowState) const override {
++m_state->configureDirectionalShadowExecutionStateCalls;
if (m_state->configureDirectionalShadowExecutionState) {
return m_state->configureDirectionalShadowExecutionState(
plan,
shadowAllocation,
shadowState);
}
return RenderPipeline::ConfigureDirectionalShadowExecutionState(
plan,
shadowAllocation,
shadowState);
}
void Shutdown() override {
++m_state->shutdownCalls;
ShutdownCameraFrameStandalonePasses();
@@ -2399,6 +2422,88 @@ TEST(CameraRenderer_Test, AutoAllocatesDirectionalShadowSurfaceFromShadowPlan) {
EXPECT_EQ(allocationState->destroyTextureCalls, 1);
}
TEST(CameraRenderer_Test, AllowsPipelineToOverrideAutoAllocatedDirectionalShadowExecutionState) {
Scene scene("CameraRendererDirectionalShadowExecutionPolicyScene");
GameObject* cameraObject = scene.CreateGameObject("Camera");
auto* camera = cameraObject->AddComponent<CameraComponent>();
camera->SetPrimary(true);
camera->SetDepth(2.0f);
auto pipelineState = std::make_shared<MockPipelineState>();
pipelineState->configureDirectionalShadowExecutionState =
[](
const CameraFramePlan& plan,
const DirectionalShadowSurfaceAllocation& shadowAllocation,
DirectionalShadowExecutionState& shadowState) {
ApplyDefaultRenderPipelineDirectionalShadowExecutionPolicy(
plan,
shadowAllocation,
shadowState);
shadowState.shadowCasterRequest.clearFlags = RenderClearFlags::All;
shadowState.shadowCasterRequest.hasCameraDataOverride = true;
shadowState.shadowCasterRequest.cameraDataOverride =
plan.directionalShadow.cameraData;
shadowState.shadowCasterRequest.cameraDataOverride.worldPosition =
XCEngine::Math::Vector3(7.0f, 8.0f, 9.0f);
shadowState.shadowData.sampling.settings.shadowStrength = 0.25f;
return true;
};
auto allocationState = std::make_shared<MockShadowAllocationState>();
MockShadowDevice device(allocationState);
RenderContext context = CreateValidContext();
context.device = &device;
{
auto pipeline = std::make_unique<MockPipeline>(pipelineState);
InstallStandaloneStagePass<MockObjectIdPass>(
*pipeline,
CameraFrameStage::ObjectId,
pipelineState);
MockScenePass* shadowPassRaw =
InstallStandaloneStagePass<MockScenePass>(
*pipeline,
CameraFrameStage::ShadowCaster,
pipelineState,
"shadowCaster");
CameraRenderer renderer(std::move(pipeline));
CameraRenderRequest request;
request.scene = &scene;
request.camera = camera;
request.context = context;
request.surface = RenderSurface(320, 180);
request.cameraDepth = camera->GetDepth();
request.directionalShadow.enabled = true;
request.directionalShadow.mapWidth = 256;
request.directionalShadow.mapHeight = 128;
request.directionalShadow.cameraData.viewportWidth = 256;
request.directionalShadow.cameraData.viewportHeight = 128;
request.directionalShadow.cameraData.clearFlags = RenderClearFlags::Depth;
request.directionalShadow.cameraData.worldPosition =
XCEngine::Math::Vector3(3.0f, 4.0f, 5.0f);
ASSERT_TRUE(renderer.Render(CameraFramePlan::FromRequest(request)));
EXPECT_EQ(
pipelineState->eventLog,
(std::vector<std::string>{
"init:shadowCaster",
"shadowCaster",
"pipeline" }));
EXPECT_EQ(
pipelineState->configureDirectionalShadowExecutionStateCalls,
1);
EXPECT_EQ(shadowPassRaw->lastClearFlags, RenderClearFlags::All);
EXPECT_EQ(
shadowPassRaw->lastWorldPosition,
XCEngine::Math::Vector3(7.0f, 8.0f, 9.0f));
EXPECT_FLOAT_EQ(
pipelineState->lastShadowSampling.settings.shadowStrength,
0.25f);
}
}
TEST(CameraRenderer_Test, PassesShadowDependencyToPipelineRecordedMainScene) {
Scene scene("CameraRendererPipelineRecordedShadowDependency");