diff --git a/engine/include/XCEngine/Rendering/Planning/SceneRenderRequestPlanner.h b/engine/include/XCEngine/Rendering/Planning/SceneRenderRequestPlanner.h index 45439455..faf9dfb1 100644 --- a/engine/include/XCEngine/Rendering/Planning/SceneRenderRequestPlanner.h +++ b/engine/include/XCEngine/Rendering/Planning/SceneRenderRequestPlanner.h @@ -12,6 +12,8 @@ class Scene; namespace Rendering { +class RenderPipelineAsset; + // Planner-owned knobs for the single main-light shadow, including both camera // fitting and the default sampling / caster bias values emitted into the // runtime shadow contract. @@ -45,7 +47,8 @@ public: const Components::Scene& scene, Components::CameraComponent* overrideCamera, const RenderContext& context, - const RenderSurface& surface) const; + const RenderSurface& surface, + const RenderPipelineAsset* pipelineAsset = nullptr) const; private: DirectionalShadowPlanningSettings m_directionalShadowPlanningSettings = {}; diff --git a/engine/include/XCEngine/Rendering/RenderPipelineAsset.h b/engine/include/XCEngine/Rendering/RenderPipelineAsset.h index 3048a3d0..25ebdfa5 100644 --- a/engine/include/XCEngine/Rendering/RenderPipelineAsset.h +++ b/engine/include/XCEngine/Rendering/RenderPipelineAsset.h @@ -5,11 +5,23 @@ #include namespace XCEngine { +namespace Components { +class Scene; +} // namespace Components + namespace Rendering { +struct CameraRenderRequest; struct CameraFramePlan; +struct DirectionalShadowPlanningSettings; class RenderPipeline; +void ApplyDefaultRenderPipelineAssetCameraRenderRequestPolicy( + CameraRenderRequest& request, + size_t renderedBaseCameraCount, + size_t renderedRequestCount, + const DirectionalShadowPlanningSettings& directionalShadowSettings); + void ApplyDefaultRenderPipelineAssetCameraFramePlanPolicy( CameraFramePlan& plan, const FinalColorSettings& pipelineDefaults = FinalColorSettings{}); @@ -20,6 +32,11 @@ public: virtual std::unique_ptr CreatePipeline() const = 0; virtual void ConfigurePipeline(RenderPipeline&) const {} + virtual void ConfigureCameraRenderRequest( + CameraRenderRequest& request, + size_t renderedBaseCameraCount, + size_t renderedRequestCount, + const DirectionalShadowPlanningSettings& directionalShadowSettings) const; virtual FinalColorSettings GetDefaultFinalColorSettings() const { return {}; } virtual void ConfigureCameraFramePlan(CameraFramePlan& plan) const; }; diff --git a/engine/src/Rendering/Execution/SceneRenderer.cpp b/engine/src/Rendering/Execution/SceneRenderer.cpp index 5a8a2e96..998a27a8 100644 --- a/engine/src/Rendering/Execution/SceneRenderer.cpp +++ b/engine/src/Rendering/Execution/SceneRenderer.cpp @@ -33,7 +33,12 @@ std::vector SceneRenderer::BuildFramePlans( const RenderContext& context, const RenderSurface& surface) { const std::vector requests = - m_requestPlanner.BuildRequests(scene, overrideCamera, context, surface); + m_requestPlanner.BuildRequests( + scene, + overrideCamera, + context, + surface, + m_pipelineHost.GetPipelineAsset()); return m_pipelineHost.BuildFramePlans(requests); } diff --git a/engine/src/Rendering/Planning/SceneRenderRequestPlanner.cpp b/engine/src/Rendering/Planning/SceneRenderRequestPlanner.cpp index 54dd2850..f57848c4 100644 --- a/engine/src/Rendering/Planning/SceneRenderRequestPlanner.cpp +++ b/engine/src/Rendering/Planning/SceneRenderRequestPlanner.cpp @@ -1,10 +1,9 @@ #include "Rendering/Planning/SceneRenderRequestPlanner.h" #include "Components/CameraComponent.h" -#include "Components/LightComponent.h" -#include "Rendering/Extraction/RenderSceneUtility.h" #include "Rendering/Planning/Internal/DirectionalShadowPlanning.h" #include "Rendering/Planning/SceneRenderRequestUtils.h" +#include "Rendering/RenderPipelineAsset.h" #include "Scene/Scene.h" #include @@ -50,7 +49,8 @@ std::vector SceneRenderRequestPlanner::BuildRequests( const Components::Scene& scene, Components::CameraComponent* overrideCamera, const RenderContext& context, - const RenderSurface& surface) const { + const RenderSurface& surface, + const RenderPipelineAsset* pipelineAsset) const { std::vector requests; const std::vector cameras = CollectCameras(scene, overrideCamera); @@ -69,33 +69,18 @@ std::vector SceneRenderRequestPlanner::BuildRequests( continue; } - if (Internal::ShouldPlanDirectionalShadowForCamera( - *camera, + if (pipelineAsset != nullptr) { + pipelineAsset->ConfigureCameraRenderRequest( + request, renderedBaseCameraCount, - requests.size())) { - if (Components::LightComponent* mainDirectionalLight = - FindMainDirectionalLight(scene, camera->GetCullingMask()); - mainDirectionalLight != nullptr && - mainDirectionalLight->GetCastsShadows()) { - const float viewportAspect = surface.GetRenderAreaHeight() > 0 - ? static_cast(surface.GetRenderAreaWidth()) / - static_cast(surface.GetRenderAreaHeight()) - : 1.0f; - DirectionalShadowPlanningSettings effectiveShadowSettings = - m_directionalShadowPlanningSettings; - if (mainDirectionalLight->GetOverridesDirectionalShadowSettings()) { - effectiveShadowSettings.sampling = - mainDirectionalLight->GetDirectionalShadowSamplingSettings(); - effectiveShadowSettings.casterBias = - mainDirectionalLight->GetDirectionalShadowCasterBiasSettings(); - } - request.directionalShadow = Internal::BuildDirectionalShadowRenderPlan( - scene, - *camera, - *mainDirectionalLight, - effectiveShadowSettings, - viewportAspect); - } + requests.size(), + m_directionalShadowPlanningSettings); + } else { + ApplyDefaultRenderPipelineAssetCameraRenderRequestPolicy( + request, + renderedBaseCameraCount, + requests.size(), + m_directionalShadowPlanningSettings); } requests.push_back(request); diff --git a/engine/src/Rendering/RenderPipelineAsset.cpp b/engine/src/Rendering/RenderPipelineAsset.cpp index 61eb0435..05931a69 100644 --- a/engine/src/Rendering/RenderPipelineAsset.cpp +++ b/engine/src/Rendering/RenderPipelineAsset.cpp @@ -1,12 +1,66 @@ #include #include "Components/CameraComponent.h" +#include "Components/LightComponent.h" #include "Rendering/Execution/CameraFramePlan.h" +#include "Rendering/Extraction/RenderSceneUtility.h" #include "Rendering/Planning/Internal/CameraFrameFullscreenStagePlanner.h" +#include "Rendering/Planning/Internal/DirectionalShadowPlanning.h" +#include "Rendering/Planning/CameraRenderRequest.h" +#include "Rendering/Planning/SceneRenderRequestPlanner.h" namespace XCEngine { namespace Rendering { +void ApplyDefaultRenderPipelineAssetCameraRenderRequestPolicy( + CameraRenderRequest& request, + size_t renderedBaseCameraCount, + size_t renderedRequestCount, + const DirectionalShadowPlanningSettings& directionalShadowSettings) { + if (request.scene == nullptr || + request.camera == nullptr) { + return; + } + + if (!Internal::ShouldPlanDirectionalShadowForCamera( + *request.camera, + renderedBaseCameraCount, + renderedRequestCount)) { + return; + } + + Components::LightComponent* const mainDirectionalLight = + FindMainDirectionalLight( + *request.scene, + request.camera->GetCullingMask()); + if (mainDirectionalLight == nullptr || + !mainDirectionalLight->GetCastsShadows()) { + return; + } + + DirectionalShadowPlanningSettings effectiveShadowSettings = + Internal::SanitizeDirectionalShadowPlanningSettings( + directionalShadowSettings); + if (mainDirectionalLight->GetOverridesDirectionalShadowSettings()) { + effectiveShadowSettings.sampling = + mainDirectionalLight->GetDirectionalShadowSamplingSettings(); + effectiveShadowSettings.casterBias = + mainDirectionalLight->GetDirectionalShadowCasterBiasSettings(); + } + + const float viewportAspect = request.surface.GetRenderAreaHeight() > 0 + ? static_cast(request.surface.GetRenderAreaWidth()) / + static_cast(request.surface.GetRenderAreaHeight()) + : 1.0f; + request.directionalShadow = + Internal::BuildDirectionalShadowRenderPlan( + *request.scene, + *request.camera, + *mainDirectionalLight, + effectiveShadowSettings, + viewportAspect); +} + void ApplyDefaultRenderPipelineAssetCameraFramePlanPolicy( CameraFramePlan& plan, const FinalColorSettings& pipelineDefaults) { @@ -19,6 +73,18 @@ void ApplyDefaultRenderPipelineAssetCameraFramePlanPolicy( Internal::PlanCameraFrameFullscreenStages(plan); } +void RenderPipelineAsset::ConfigureCameraRenderRequest( + CameraRenderRequest& request, + size_t renderedBaseCameraCount, + size_t renderedRequestCount, + const DirectionalShadowPlanningSettings& directionalShadowSettings) const { + ApplyDefaultRenderPipelineAssetCameraRenderRequestPolicy( + request, + renderedBaseCameraCount, + renderedRequestCount, + directionalShadowSettings); +} + void RenderPipelineAsset::ConfigureCameraFramePlan(CameraFramePlan& plan) const { ApplyDefaultRenderPipelineAssetCameraFramePlanPolicy( plan, diff --git a/tests/Rendering/unit/test_camera_scene_renderer.cpp b/tests/Rendering/unit/test_camera_scene_renderer.cpp index dc3644d3..478cd818 100644 --- a/tests/Rendering/unit/test_camera_scene_renderer.cpp +++ b/tests/Rendering/unit/test_camera_scene_renderer.cpp @@ -1,6 +1,7 @@ #include #include +#include #include #include #include @@ -420,10 +421,16 @@ public: struct MockPipelineAssetState { int createCalls = 0; + int configureCameraRenderRequestCalls = 0; int configureCameraFramePlanCalls = 0; bool createNullPipeline = false; std::shared_ptr lastCreatedPipelineState; FinalColorSettings defaultFinalColorSettings = {}; + std::function configureCameraRenderRequest = {}; std::function configureCameraFramePlan = {}; }; @@ -705,6 +712,28 @@ public: return m_state->defaultFinalColorSettings; } + void ConfigureCameraRenderRequest( + CameraRenderRequest& request, + size_t renderedBaseCameraCount, + size_t renderedRequestCount, + const DirectionalShadowPlanningSettings& directionalShadowSettings) const override { + ++m_state->configureCameraRenderRequestCalls; + if (m_state->configureCameraRenderRequest) { + m_state->configureCameraRenderRequest( + request, + renderedBaseCameraCount, + renderedRequestCount, + directionalShadowSettings); + return; + } + + RenderPipelineAsset::ConfigureCameraRenderRequest( + request, + renderedBaseCameraCount, + renderedRequestCount, + directionalShadowSettings); + } + void ConfigureCameraFramePlan(CameraFramePlan& plan) const override { ++m_state->configureCameraFramePlanCalls; if (m_state->configureCameraFramePlan) { @@ -3322,6 +3351,43 @@ TEST(SceneRenderer_Test, UsesPipelineAssetCameraFramePlanConfigurationHook) { EXPECT_FALSE(plan.finalOutput.IsRequested()); } +TEST(SceneRenderer_Test, UsesPipelineAssetCameraRenderRequestConfigurationHook) { + Scene scene("SceneRendererRequestConfigurationHookScene"); + + GameObject* cameraObject = scene.CreateGameObject("Camera"); + auto* camera = cameraObject->AddComponent(); + camera->SetPrimary(true); + camera->SetDepth(2.0f); + + GameObject* shadowLightObject = scene.CreateGameObject("ShadowLight"); + auto* shadowLight = shadowLightObject->AddComponent(); + shadowLight->SetLightType(LightType::Directional); + shadowLight->SetCastsShadows(true); + + auto assetState = std::make_shared(); + assetState->configureCameraRenderRequest = + []( + CameraRenderRequest& request, + size_t renderedBaseCameraCount, + size_t renderedRequestCount, + const DirectionalShadowPlanningSettings& directionalShadowSettings) { + ApplyDefaultRenderPipelineAssetCameraRenderRequestPolicy( + request, + renderedBaseCameraCount, + renderedRequestCount, + directionalShadowSettings); + request.directionalShadow = {}; + }; + + SceneRenderer renderer(std::make_shared(assetState)); + const std::vector plans = + renderer.BuildFramePlans(scene, nullptr, CreateValidContext(), RenderSurface(640, 360)); + + ASSERT_EQ(plans.size(), 1u); + EXPECT_EQ(assetState->configureCameraRenderRequestCalls, 1); + EXPECT_FALSE(plans[0].directionalShadow.IsValid()); +} + TEST(SceneRenderer_Test, BuildsFinalOutputRequestFromResolvedFinalColorPolicy) { Scene scene("SceneRendererFinalOutputScene");