From f2be5627be7dd67cb15cbe891f15dc4191131723 Mon Sep 17 00:00:00 2001 From: ssdfasd <2156608475@qq.com> Date: Tue, 21 Apr 2026 15:44:19 +0800 Subject: [PATCH] refactor(srp): move core stage defaults into universal renderer --- ...ndererOwnershipPlan_完成归档_2026-04-21.md | 83 ++++++++++++++ ...wStageOwnershipPlan_完成归档_2026-04-21.md | 99 ++++++++++++++++ .../Rendering/Execution/CameraFramePlan.h | 12 ++ .../Rendering/Execution/CameraFramePlan.cpp | 32 +++++- .../Shadow/DirectionalShadowRuntime.cpp | 4 + .../src/Scripting/Mono/MonoScriptRuntime.cpp | 25 ++++ managed/CMakeLists.txt | 2 +- .../Universal/BuiltinFinalColorPass.cs | 29 +++++ .../BuiltinFinalColorRendererFeature.cs | 107 ------------------ ...DisableDirectionalShadowRendererFeature.cs | 11 ++ .../Rendering/Universal/UniversalRenderer.cs | 88 ++++++++++++++ .../Universal/UniversalRendererData.cs | 3 +- managed/XCEngine.ScriptCore/InternalCalls.cs | 10 ++ ...ScriptableRenderPipelinePlanningContext.cs | 14 +++ 14 files changed, 408 insertions(+), 111 deletions(-) create mode 100644 docs/used/SRP_UnityStyleURPCoreRendererOwnershipPlan_完成归档_2026-04-21.md create mode 100644 docs/used/SRP_UnityStyleURPShadowStageOwnershipPlan_完成归档_2026-04-21.md create mode 100644 managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/BuiltinFinalColorPass.cs delete mode 100644 managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/BuiltinFinalColorRendererFeature.cs diff --git a/docs/used/SRP_UnityStyleURPCoreRendererOwnershipPlan_完成归档_2026-04-21.md b/docs/used/SRP_UnityStyleURPCoreRendererOwnershipPlan_完成归档_2026-04-21.md new file mode 100644 index 00000000..449daa38 --- /dev/null +++ b/docs/used/SRP_UnityStyleURPCoreRendererOwnershipPlan_完成归档_2026-04-21.md @@ -0,0 +1,83 @@ +# SRP Unity-Style URP Core Renderer Ownership Plan + +日期:2026-04-21 + +## 阶段目标 + +在已经完成 `ShadowCaster` stage ownership 的基础上,继续把 URP 的核心职责收回到 `UniversalRenderer` 本体,向 Unity 的 `ScriptableRenderer` 组织方式靠拢。 + +这一阶段先不碰 deferred,也不碰大范围的 RenderPassEvent 扩表。先把最明显、最不符合 Unity 的地方收干净: + +- `FinalColor / FinalOutput` 不再由默认 `RendererFeature` 伪装承载 +- `UniversalRenderer` 显式拥有核心收尾 stage 的默认规划与录制 +- `RendererFeature` 只保留扩展/注入职责,不再混入明显属于 renderer core 的默认 pass + +## 当前问题 + +当前 managed 层虽然已经有了 `RendererData -> Renderer -> RendererFeature -> Pass` 结构,但还存在一个关键偏差: + +1. `BuiltinFinalColorRendererFeature` 仍然承担 `FinalOutput` stage 的默认规划 +2. `BuiltinFinalColorRendererFeature` 仍然承担核心 final color pass 的录制 +3. `UniversalRendererData.rendererFeatures` 默认列表里混入了 renderer core pass + +这跟 Unity 的真实边界不一致。Unity 里: + +- `ScriptableRenderer` 负责核心 pass 的组织 +- `ScriptableRendererFeature` 负责附加、覆写、注入 +- `RendererData` 主要是 renderer 配置资产,而不是“默认核心 pass 容器” + +如果继续把 core pass 塞在默认 feature 里,后面会直接影响: + +- renderer 自己的阶段所有权 +- future renderer variant(不同 renderer)的拆分 +- 后续 post-process block / shadow block / prepass block 的继续归位 + +## 本阶段实施内容 + +### 1. 收回 FinalColor 核心职责 + +把 `BuiltinFinalColor` 的默认规划与录制从默认 `RendererFeature` 收回到 `UniversalRenderer`: + +1. `UniversalRenderer.ConfigureCameraFramePlan(...)` 显式拥有 `FinalOutput` 的默认规划 +2. `UniversalRenderer.AddRenderPasses(...)` 显式拥有内建 final color pass 的入队 +3. 后续 feature 仍然可以在 renderer 之后覆写/补充 + +### 2. 清理默认 RendererFeature 列表 + +调整 `UniversalRendererData` 的默认 feature 列表,只保留扩展性质的 feature: + +1. `BuiltinFinalColorRendererFeature` 退出默认列表 +2. `rendererFeatures` 不再承担 renderer core 职责 +3. 默认 feature 列表表达“扩展点”,而不是“核心管线本体” + +### 3. 保持现有行为不回退 + +这一步不是改效果,而是改职责边界: + +1. 有 final color processing 时,`FinalOutput` 仍会被正确请求 +2. 若 `PostProcess` 已占用 graph-managed color,`FinalOutput` 仍沿用正确 source +3. 旧版 `XCEditor` 冒烟结果不能回退 + +## 本阶段不做的事情 + +1. 不做 deferred renderer +2. 不做 GBuffer +3. 不做完整 post-process block 体系 +4. 不做阴影 pass managed 化 +5. 不一口气重写所有 `RendererFeature` + +## 完成标准 + +1. `FinalOutput` 的默认规划位于 `UniversalRenderer` +2. 内建 final color pass 的默认录制位于 `UniversalRenderer` +3. `UniversalRendererData` 默认 feature 列表不再包含 core final color feature +4. 旧版 `XCEditor` Debug 编译通过 +5. 旧版编辑器冒烟 10 秒以上,并在新的 `editor.log` 中出现 `SceneReady` + +## 下一阶段前置条件 + +只有这一阶段收口后,再进入下一个更像 Unity 的阶段: + +- `PostProcess / Core Block Ownership` + +也就是继续把 renderer core 的 block 组织,从 feature 侧收回到 `UniversalRenderer`,为后续更完整的 Unity 风格 `RenderPassEvent` 与 renderer variant 演进做准备。 diff --git a/docs/used/SRP_UnityStyleURPShadowStageOwnershipPlan_完成归档_2026-04-21.md b/docs/used/SRP_UnityStyleURPShadowStageOwnershipPlan_完成归档_2026-04-21.md new file mode 100644 index 00000000..7be6e765 --- /dev/null +++ b/docs/used/SRP_UnityStyleURPShadowStageOwnershipPlan_完成归档_2026-04-21.md @@ -0,0 +1,99 @@ +# SRP Unity-Style URP Shadow Stage Ownership Plan + +日期:2026-04-21 + +## 阶段目标 + +本阶段不做 deferred。本阶段只做一件更关键的事: + +- 按 Unity 的 `SRP -> URP Asset -> RendererData -> Renderer -> RendererFeature/Pass` 分层, + 把 `ShadowCaster` 阶段的组织权从 native 默认宿主继续收回到 URP 包层。 + +当前主线已经完成了 SRP generic seam 收口,但 `ShadowCaster` 仍主要由 native 默认流程决定: + +1. native request/build-plan 默认逻辑决定阴影阶段是否存在。 +2. URP 目前只能改阴影 planning settings 和 execution policy key,不能显式组织阴影阶段。 +3. 这会直接阻塞后续 renderer model 和 deferred 演进。 + +## 为什么这一阶段优先级最高 + +如果现在直接做 deferred,会把以下职责继续错误地压在 C++ 宿主层: + +1. 阶段存在性判定 +2. ShadowCaster 与 MainScene 的耦合关系 +3. Forward/Deferred 的 renderer path 组织 + +最终会得到一个“有 C# 外壳的 C++ 内建管线”,而不是 Unity 风格的 `SRP + URP`。 + +## 对齐 Unity 的实现原则 + +这一阶段严格按下面的边界推进: + +1. `ScriptableRenderPipelineAsset` + - 只保留 SRP 抽象宿主职责。 + +2. `UniversalRenderPipelineAsset` + - 负责首方 URP 级别的全局设置与默认 renderer 组织。 + +3. `UniversalRendererData` + - 负责 renderer 级配置,不再只做 key 映射容器。 + +4. `UniversalRenderer` + - 负责主场景与阴影等核心 renderer stage 的组织。 + +5. `ScriptableRendererFeature` + - 负责注入和覆写,不负责继续依赖 native 默认猜测阶段。 + +## 本阶段具体工作 + +### 1. ShadowCaster 显式规划 API + +给 managed planning context 增加 `ShadowCaster` 显式请求/清理能力: + +1. native `CameraFramePlan` 记录 `ShadowCaster` 显式配置状态。 +2. managed `ScriptableRenderPipelinePlanningContext` 暴露对应 API。 +3. `DirectionalShadowRuntime` 尊重显式关闭,不再无条件按 native 默认继续推导。 + +### 2. URP 默认阴影阶段归位 + +让 `UniversalRenderPipelineAsset` 在 planning 阶段显式声明: + +1. 允许阴影时,请求 `ShadowCaster` +2. 关闭阴影时,清理 `ShadowCaster` + +这一步的意义不是改变最终效果,而是把“阶段组织权”显式放回 URP。 + +### 3. Feature 覆写路径归位 + +让类似 `DisableDirectionalShadowRendererFeature` 这类 feature: + +1. 不再只靠 request 阶段清掉 directional shadow 数据 +2. 同时在 plan 阶段显式清掉 `ShadowCaster` + +这样以后 renderer feature 覆写路径才符合 Unity 的思路。 + +## 本阶段不做的事 + +1. 不做 deferred renderer +2. 不做 GBuffer +3. 不重写整个 shadow runtime +4. 不一次性泛化所有 standalone stage + +## 完成标准 + +1. managed planning context 可以显式控制 `ShadowCaster` +2. `UniversalRenderPipelineAsset` 显式拥有默认阴影阶段组织权 +3. feature 可以显式覆写 `ShadowCaster` +4. 旧版 `XCEditor` Debug 编译通过 +5. 旧版编辑器冒烟 10 秒以上并出现新的 `SceneReady` + +## 下一阶段前置条件 + +只有本阶段完成,才进入下一阶段: + +- `URP Renderer Model Formalization` + +也就是: + +1. 把 `UniversalRendererData` 从“forward 默认配置袋”演进成真正的 renderer data 模型 +2. 为未来 `ForwardRenderer / DeferredRenderer` 拆分做好结构准备 diff --git a/engine/include/XCEngine/Rendering/Execution/CameraFramePlan.h b/engine/include/XCEngine/Rendering/Execution/CameraFramePlan.h index da1fb43f..fac8290f 100644 --- a/engine/include/XCEngine/Rendering/Execution/CameraFramePlan.h +++ b/engine/include/XCEngine/Rendering/Execution/CameraFramePlan.h @@ -16,6 +16,11 @@ struct CameraFrameFullscreenStagePlan { CameraFrameColorSource source = CameraFrameColorSource::ExplicitSurface; }; +struct CameraFrameStandaloneStagePlan { + bool requested = false; + bool explicitlyConfigured = false; +}; + struct CameraFrameColorChainPlan { bool usesGraphManagedSceneColor = false; CameraFrameFullscreenStagePlan postProcess = {}; @@ -35,6 +40,7 @@ struct CameraFramePlan { RenderPassSequence* preScenePasses = nullptr; RenderPassSequence* postScenePasses = nullptr; RenderPassSequence* overlayPasses = nullptr; + CameraFrameStandaloneStagePlan shadowCasterStage = {}; CameraFrameColorChainPlan colorChain = {}; RenderSurface graphManagedSceneSurface = {}; @@ -64,8 +70,14 @@ struct CameraFramePlan { void ClearFullscreenStage( CameraFrameStage stage, bool explicitlyConfigured = false); + bool RequestShadowCasterStage( + bool explicitlyConfigured = false); + void ClearShadowCasterStage( + bool explicitlyConfigured = false); bool HasExplicitFullscreenStageConfiguration( CameraFrameStage stage) const; + bool HasExplicitShadowCasterStageConfiguration() const; + bool IsShadowCasterStageRequested() const; bool IsPostProcessStageValid() const; bool IsFinalOutputStageValid() const; bool HasFrameStage(CameraFrameStage stage) const; diff --git a/engine/src/Rendering/Execution/CameraFramePlan.cpp b/engine/src/Rendering/Execution/CameraFramePlan.cpp index 11231797..ec2d4fda 100644 --- a/engine/src/Rendering/Execution/CameraFramePlan.cpp +++ b/engine/src/Rendering/Execution/CameraFramePlan.cpp @@ -60,6 +60,9 @@ CameraFramePlan CameraFramePlan::FromRequest(const CameraRenderRequest& request) plan.preScenePasses = request.preScenePasses; plan.postScenePasses = request.postScenePasses; plan.overlayPasses = request.overlayPasses; + plan.shadowCasterStage.requested = + request.shadowCaster.IsRequested() || + request.directionalShadow.IsValid(); plan.colorChain.postProcess.requested = request.postProcess.IsRequested(); plan.colorChain.finalOutput.requested = request.finalOutput.IsRequested(); return plan; @@ -210,6 +213,25 @@ void CameraFramePlan::ClearFullscreenStage( RefreshGraphManagedSceneSurfaceState(); } +bool CameraFramePlan::RequestShadowCasterStage( + bool explicitlyConfigured) { + shadowCasterStage.requested = + shadowCaster.IsRequested() || + directionalShadow.IsValid(); + shadowCasterStage.explicitlyConfigured = + shadowCasterStage.explicitlyConfigured || + explicitlyConfigured; + return shadowCasterStage.requested; +} + +void CameraFramePlan::ClearShadowCasterStage( + bool explicitlyConfigured) { + shadowCasterStage.requested = false; + shadowCasterStage.explicitlyConfigured = + shadowCasterStage.explicitlyConfigured || + explicitlyConfigured; +} + bool CameraFramePlan::HasExplicitFullscreenStageConfiguration( CameraFrameStage stage) const { if (const CameraFrameFullscreenStagePlan* fullscreenStagePlan = @@ -221,6 +243,14 @@ bool CameraFramePlan::HasExplicitFullscreenStageConfiguration( return false; } +bool CameraFramePlan::HasExplicitShadowCasterStageConfiguration() const { + return shadowCasterStage.explicitlyConfigured; +} + +bool CameraFramePlan::IsShadowCasterStageRequested() const { + return shadowCasterStage.requested; +} + bool CameraFramePlan::IsPostProcessStageValid() const { if (!IsFullscreenStageRequested(CameraFrameStage::PostProcess)) { return true; @@ -286,7 +316,7 @@ bool CameraFramePlan::HasFrameStage(CameraFrameStage stage) const { switch (GetCameraFrameStageRequestKind(stage)) { case CameraFrameStageRequestKind::ShadowCaster: - return shadowCaster.IsRequested() || directionalShadow.IsValid(); + return IsShadowCasterStageRequested(); case CameraFrameStageRequestKind::DepthOnly: return request.depthOnly.IsRequested(); case CameraFrameStageRequestKind::ObjectId: diff --git a/engine/src/Rendering/Shadow/DirectionalShadowRuntime.cpp b/engine/src/Rendering/Shadow/DirectionalShadowRuntime.cpp index baa4c0cd..9fedf407 100644 --- a/engine/src/Rendering/Shadow/DirectionalShadowRuntime.cpp +++ b/engine/src/Rendering/Shadow/DirectionalShadowRuntime.cpp @@ -11,6 +11,10 @@ bool DirectionalShadowRuntime::ResolveExecutionState( const RenderPipeline& pipeline, DirectionalShadowExecutionState& outShadowState) { outShadowState = {}; + if (!plan.IsShadowCasterStageRequested()) { + return true; + } + outShadowState.shadowCasterRequest = plan.shadowCaster; if (outShadowState.shadowCasterRequest.IsRequested()) { diff --git a/engine/src/Scripting/Mono/MonoScriptRuntime.cpp b/engine/src/Scripting/Mono/MonoScriptRuntime.cpp index cb5fba4c..0dff1566 100644 --- a/engine/src/Scripting/Mono/MonoScriptRuntime.cpp +++ b/engine/src/Scripting/Mono/MonoScriptRuntime.cpp @@ -5882,6 +5882,29 @@ void InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_ClearFullscr state->plan->ClearFullscreenStage(resolvedStage, true); } +mono_bool +InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_RequestShadowCasterStage( + uint64_t nativeHandle) { + ManagedScriptableRenderPipelinePlanningContextState* const state = + FindManagedScriptableRenderPipelinePlanningContextState(nativeHandle); + return state != nullptr && + state->plan != nullptr && + state->plan->RequestShadowCasterStage(true) + ? 1 + : 0; +} + +void InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_ClearShadowCasterStage( + uint64_t nativeHandle) { + ManagedScriptableRenderPipelinePlanningContextState* const state = + FindManagedScriptableRenderPipelinePlanningContextState(nativeHandle); + if (state == nullptr || state->plan == nullptr) { + return; + } + + state->plan->ClearShadowCasterStage(true); +} + mono_bool InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_GetHasFinalColorProcessing( uint64_t nativeHandle) { @@ -6098,6 +6121,8 @@ void RegisterInternalCalls() { mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderPipelinePlanningContext_GetStageUsesGraphManagedOutputColor", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_GetStageUsesGraphManagedOutputColor)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderPipelinePlanningContext_RequestFullscreenStage", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_RequestFullscreenStage)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderPipelinePlanningContext_ClearFullscreenStage", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_ClearFullscreenStage)); + mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderPipelinePlanningContext_RequestShadowCasterStage", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_RequestShadowCasterStage)); + mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderPipelinePlanningContext_ClearShadowCasterStage", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_ClearShadowCasterStage)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderPipelinePlanningContext_GetHasFinalColorProcessing", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_GetHasFinalColorProcessing)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_CameraRenderRequestContext_GetRenderedBaseCameraCount", reinterpret_cast(&InternalCall_Rendering_CameraRenderRequestContext_GetRenderedBaseCameraCount)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_CameraRenderRequestContext_GetRenderedRequestCount", reinterpret_cast(&InternalCall_Rendering_CameraRenderRequestContext_GetRenderedRequestCount)); diff --git a/managed/CMakeLists.txt b/managed/CMakeLists.txt index 41e7fd91..dd40e2b4 100644 --- a/managed/CMakeLists.txt +++ b/managed/CMakeLists.txt @@ -210,7 +210,7 @@ set(XCENGINE_RENDER_PIPELINES_UNIVERSAL_SOURCES # Universal renderer package ${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/CameraData.cs ${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/ColorScalePostProcessRendererFeature.cs - ${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/BuiltinFinalColorRendererFeature.cs + ${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/BuiltinFinalColorPass.cs ${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/BuiltinGaussianSplatRendererFeature.cs ${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/BuiltinVolumetricRendererFeature.cs ${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/DirectionalLightData.cs diff --git a/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/BuiltinFinalColorPass.cs b/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/BuiltinFinalColorPass.cs new file mode 100644 index 00000000..6eeb628f --- /dev/null +++ b/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/BuiltinFinalColorPass.cs @@ -0,0 +1,29 @@ +using XCEngine; +using XCEngine.Rendering; + +namespace XCEngine.Rendering.Universal +{ + internal sealed class BuiltinFinalColorPass + : ScriptableRenderPass + { + public BuiltinFinalColorPass() + { + renderPassEvent = + RenderPassEvent.BeforeRenderingFinalOutput; + } + + protected override bool RecordRenderGraph( + ScriptableRenderContext context, + RenderingData renderingData) + { + return context != null && + renderingData != null && + renderingData.isFinalOutputStage && + (!renderingData.finalColorData.requiresProcessing || + RecordFinalColorFullscreenPass( + context, + renderingData.finalColorData.settings, + "Universal.BuiltinFinalColor")); + } + } +} diff --git a/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/BuiltinFinalColorRendererFeature.cs b/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/BuiltinFinalColorRendererFeature.cs deleted file mode 100644 index 0d55992f..00000000 --- a/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/BuiltinFinalColorRendererFeature.cs +++ /dev/null @@ -1,107 +0,0 @@ -using XCEngine; -using XCEngine.Rendering; - -namespace XCEngine.Rendering.Universal -{ - internal sealed class BuiltinFinalColorPass - : ScriptableRenderPass - { - public BuiltinFinalColorPass() - { - renderPassEvent = - RenderPassEvent.BeforeRenderingFinalOutput; - } - - protected override bool RecordRenderGraph( - ScriptableRenderContext context, - RenderingData renderingData) - { - return context != null && - renderingData != null && - renderingData.isFinalOutputStage && - (!renderingData.finalColorData.requiresProcessing || - RecordFinalColorFullscreenPass( - context, - renderingData.finalColorData.settings, - "Universal.BuiltinFinalColor")); - } - } - - public sealed class BuiltinFinalColorRendererFeature - : ScriptableRendererFeature - { - private BuiltinFinalColorPass m_pass; - - public override void Create() - { - m_pass = new BuiltinFinalColorPass(); - } - - public override void ConfigureCameraFramePlan( - ScriptableRenderPipelinePlanningContext context) - { - if (context == null || - !context.HasFinalColorProcessing()) - { - return; - } - - CameraFrameColorSource finalOutputSource = - CameraFrameColorSource.MainSceneColor; - if (context.IsStageRequested( - CameraFrameStage.PostProcess)) - { - CameraFrameColorSource postProcessSource = - context.GetStageColorSource( - CameraFrameStage.PostProcess); - if (postProcessSource != - CameraFrameColorSource.ExplicitSurface) - { - if (!context.UsesGraphManagedOutputColor( - CameraFrameStage.PostProcess)) - { - context.ClearFullscreenStage( - CameraFrameStage.PostProcess); - context.RequestFullscreenStage( - CameraFrameStage.PostProcess, - postProcessSource, - true); - } - - finalOutputSource = - CameraFrameColorSource.PostProcessColor; - } - } - - context.ClearFullscreenStage( - CameraFrameStage.FinalOutput); - context.RequestFullscreenStage( - CameraFrameStage.FinalOutput, - finalOutputSource); - } - - public override void AddRenderPasses( - ScriptableRenderer renderer, - RenderingData renderingData) - { - if (renderer == null || - renderingData == null) - { - return; - } - - if (!renderingData.isFinalOutputStage && - !renderingData.finalColorData.requiresProcessing) - { - return; - } - - if (m_pass == null) - { - CreateInstance(); - } - - renderer.EnqueuePass(m_pass); - } - } -} diff --git a/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/DisableDirectionalShadowRendererFeature.cs b/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/DisableDirectionalShadowRendererFeature.cs index 5e790d49..c65c6417 100644 --- a/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/DisableDirectionalShadowRendererFeature.cs +++ b/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/DisableDirectionalShadowRendererFeature.cs @@ -14,6 +14,17 @@ namespace XCEngine.Rendering.Universal ClearDirectionalShadow(context); } } + + public override void ConfigureCameraFramePlan( + ScriptableRenderPipelinePlanningContext context) + { + if (context == null) + { + return; + } + + context.ClearShadowCasterStage(); + } } } diff --git a/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/UniversalRenderer.cs b/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/UniversalRenderer.cs index 5f0a5e83..bf6b8974 100644 --- a/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/UniversalRenderer.cs +++ b/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/UniversalRenderer.cs @@ -6,6 +6,8 @@ namespace XCEngine.Rendering.Universal public sealed class UniversalRenderer : ScriptableRenderer { private readonly UniversalRendererData m_rendererData; + private readonly BuiltinFinalColorPass m_builtinFinalColorPass = + new BuiltinFinalColorPass(); private readonly DrawObjectsPass m_drawOpaqueObjectsPass = new DrawObjectsPass( RenderPassEvent.RenderOpaques, @@ -28,6 +30,18 @@ namespace XCEngine.Rendering.Universal rendererData ?? new UniversalRendererData(); } + protected override void ConfigureCameraFramePlan( + ScriptableRenderPipelinePlanningContext context) + { + if (context == null) + { + return; + } + + ConfigureShadowCasterStage(context); + ConfigureFinalOutputStage(context); + } + protected override void AddRenderPasses( RenderingData renderingData) { @@ -53,6 +67,8 @@ namespace XCEngine.Rendering.Universal { EnqueueTransparentPasses(mainScene); } + + EnqueueFinalOutputPasses(renderingData); } private void EnqueueOpaquePasses( @@ -84,5 +100,77 @@ namespace XCEngine.Rendering.Universal mainScene.transparentDrawingSettings); EnqueuePass(m_drawTransparentObjectsPass); } + + private static void ConfigureShadowCasterStage( + ScriptableRenderPipelinePlanningContext context) + { + if (context.IsStageRequested( + CameraFrameStage.ShadowCaster)) + { + context.RequestShadowCasterStage(); + return; + } + + context.ClearShadowCasterStage(); + } + + private static void ConfigureFinalOutputStage( + ScriptableRenderPipelinePlanningContext context) + { + context.ClearFullscreenStage( + CameraFrameStage.FinalOutput); + if (!context.HasFinalColorProcessing()) + { + return; + } + + CameraFrameColorSource finalOutputSource = + CameraFrameColorSource.MainSceneColor; + if (context.IsStageRequested( + CameraFrameStage.PostProcess)) + { + CameraFrameColorSource postProcessSource = + context.GetStageColorSource( + CameraFrameStage.PostProcess); + if (postProcessSource != + CameraFrameColorSource.ExplicitSurface) + { + if (!context.UsesGraphManagedOutputColor( + CameraFrameStage.PostProcess)) + { + context.ClearFullscreenStage( + CameraFrameStage.PostProcess); + context.RequestFullscreenStage( + CameraFrameStage.PostProcess, + postProcessSource, + true); + } + + finalOutputSource = + CameraFrameColorSource.PostProcessColor; + } + } + + context.RequestFullscreenStage( + CameraFrameStage.FinalOutput, + finalOutputSource); + } + + private void EnqueueFinalOutputPasses( + RenderingData renderingData) + { + if (renderingData == null) + { + return; + } + + if (!renderingData.isFinalOutputStage && + !renderingData.finalColorData.requiresProcessing) + { + return; + } + + EnqueuePass(m_builtinFinalColorPass); + } } } diff --git a/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/UniversalRendererData.cs b/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/UniversalRendererData.cs index 190d2a35..e235b790 100644 --- a/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/UniversalRendererData.cs +++ b/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/UniversalRendererData.cs @@ -74,8 +74,7 @@ namespace XCEngine.Rendering.Universal return new ScriptableRendererFeature[] { new BuiltinGaussianSplatRendererFeature(), - new BuiltinVolumetricRendererFeature(), - new BuiltinFinalColorRendererFeature() + new BuiltinVolumetricRendererFeature() }; } } diff --git a/managed/XCEngine.ScriptCore/InternalCalls.cs b/managed/XCEngine.ScriptCore/InternalCalls.cs index 1a03ce09..5feefa3c 100644 --- a/managed/XCEngine.ScriptCore/InternalCalls.cs +++ b/managed/XCEngine.ScriptCore/InternalCalls.cs @@ -522,6 +522,16 @@ namespace XCEngine ulong nativeHandle, int stage); + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern bool + Rendering_ScriptableRenderPipelinePlanningContext_RequestShadowCasterStage( + ulong nativeHandle); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern void + Rendering_ScriptableRenderPipelinePlanningContext_ClearShadowCasterStage( + ulong nativeHandle); + [MethodImpl(MethodImplOptions.InternalCall)] internal static extern bool Rendering_ScriptableRenderPipelinePlanningContext_GetHasFinalColorProcessing( diff --git a/managed/XCEngine.ScriptCore/Rendering/Core/ScriptableRenderPipelinePlanningContext.cs b/managed/XCEngine.ScriptCore/Rendering/Core/ScriptableRenderPipelinePlanningContext.cs index 5b5bb81c..1c09c229 100644 --- a/managed/XCEngine.ScriptCore/Rendering/Core/ScriptableRenderPipelinePlanningContext.cs +++ b/managed/XCEngine.ScriptCore/Rendering/Core/ScriptableRenderPipelinePlanningContext.cs @@ -66,6 +66,20 @@ namespace XCEngine.Rendering (int)stage); } + public bool RequestShadowCasterStage() + { + return InternalCalls + .Rendering_ScriptableRenderPipelinePlanningContext_RequestShadowCasterStage( + m_nativeHandle); + } + + public void ClearShadowCasterStage() + { + InternalCalls + .Rendering_ScriptableRenderPipelinePlanningContext_ClearShadowCasterStage( + m_nativeHandle); + } + public bool HasFinalColorProcessing() { return InternalCalls