From 0d6b8bf7d89b6af7f42b96204398edb9e27b1313 Mon Sep 17 00:00:00 2001 From: ssdfasd <2156608475@qq.com> Date: Mon, 13 Apr 2026 23:11:28 +0800 Subject: [PATCH] Formalize directional shadow runtime contracts --- ...一阶段重构计划_RenderGraph前_2026-04-13.md | 462 ++++++++++++++++++ engine/CMakeLists.txt | 13 +- .../Rendering/Builtin/BuiltinPassContract.h | 3 - .../Caches/DirectionalShadowSurfaceCache.h | 20 +- .../Rendering/Execution/CameraRenderer.h | 13 +- .../DirectionalShadowExecutionState.h | 23 + .../Rendering/FrameData/RenderSceneData.h | 42 +- .../Rendering/Planning/CameraRenderRequest.h | 25 +- .../Rendering/Shadow/DirectionalShadowData.h | 82 ++++ .../Shadow/DirectionalShadowRuntime.h | 27 + .../Caches/DirectionalShadowSurfaceCache.cpp | 37 +- .../Rendering/Execution/CameraRenderer.cpp | 92 +--- .../Shadow/DirectionalShadowData.cpp | 33 ++ .../Shadow/DirectionalShadowRuntime.cpp | 44 ++ .../unit/test_render_scene_extractor.cpp | 2 +- 15 files changed, 740 insertions(+), 178 deletions(-) create mode 100644 docs/plan/Renderer_C++层第一阶段重构计划_RenderGraph前_2026-04-13.md delete mode 100644 engine/include/XCEngine/Rendering/Builtin/BuiltinPassContract.h create mode 100644 engine/include/XCEngine/Rendering/Execution/DirectionalShadowExecutionState.h create mode 100644 engine/include/XCEngine/Rendering/Shadow/DirectionalShadowData.h create mode 100644 engine/include/XCEngine/Rendering/Shadow/DirectionalShadowRuntime.h create mode 100644 engine/src/Rendering/Shadow/DirectionalShadowData.cpp create mode 100644 engine/src/Rendering/Shadow/DirectionalShadowRuntime.cpp diff --git a/docs/plan/Renderer_C++层第一阶段重构计划_RenderGraph前_2026-04-13.md b/docs/plan/Renderer_C++层第一阶段重构计划_RenderGraph前_2026-04-13.md new file mode 100644 index 00000000..594cc027 --- /dev/null +++ b/docs/plan/Renderer_C++层第一阶段重构计划_RenderGraph前_2026-04-13.md @@ -0,0 +1,462 @@ +# Renderer C++层第一阶段重构计划(Render Graph 前) + +日期:`2026-04-13` + +## 1. 文档定位 + +这份计划只处理 `Render Graph` 之前的那一步,也就是把当前 `Rendering` 原生主链先整理成一个可长期演进的正式架构。 + +这一步的目标不是新增大功能,而是先把下面这些边界收口: + +1. `SceneRenderer / CameraRenderer / SceneRenderRequestPlanner` 的职责边界 +2. `RenderSceneExtractor / RenderSceneData / VisibleRenderItem` 的数据边界 +3. `RenderPipeline / RenderPass / BuiltinForwardPipeline` 的执行边界 +4. Runtime 主链与 Editor 注入点的边界 + +这一步做完之后,下一阶段才适合引入真正的 `Render Graph`。 + +--- + +## 2. 关于 Render Graph 的结论 + +结论很明确: + +1. `Render Graph` 应该先做在 `C++ native` 层 +2. 它不应该直接作为第一阶段的一部分 +3. 第一阶段的任务,是先把当前 native renderer 收口到足够清晰,避免后面只是把现有混乱机械搬进 graph + +后面的目标结构应该是: + +`RHI -> Native Render Kernel -> Render Graph -> SRP-like Contract -> Universal Renderer -> C# Custom Pipeline` + +其中: + +1. `Render Graph` 属于 `Native Render Kernel` +2. `C#` 层以后可以编排 pass,但图资源生命周期、资源状态、barrier、跨 pass 读写依赖仍应先由 native graph 掌控 + +--- + +## 3. 当前代码里的真实主链 + +当前项目并不是没有架构,而是已经形成了一条手工编排的 mini-SRP 主链: + +1. `SceneRenderRequestPlanner` + - 收集 camera + - 生成 `CameraRenderRequest` + - 负责方向光阴影规划参数 +2. `SceneRenderer` + - 调 planner + - 解析 final color policy + - 为 post-process / final-output 附加 fullscreen stage request +3. `CameraRenderer` + - 做 shadow request resolve + - 提取 `RenderSceneData` + - 按固定 stage 顺序执行 +4. `BuiltinForwardPipeline` + - 负责主场景绘制 + - 同时背着 shader 绑定、PSO 缓存、材质资源解析、skybox、splat、volumetric 等大量职责 + +对应的当前入口主要是: + +1. `engine/include/XCEngine/Rendering/Execution/SceneRenderer.h` +2. `engine/include/XCEngine/Rendering/Execution/CameraRenderer.h` +3. `engine/include/XCEngine/Rendering/Planning/SceneRenderRequestPlanner.h` +4. `engine/include/XCEngine/Rendering/Planning/CameraRenderRequest.h` +5. `engine/include/XCEngine/Rendering/FrameData/RenderSceneData.h` +6. `engine/include/XCEngine/Rendering/FrameData/VisibleRenderItem.h` +7. `engine/include/XCEngine/Rendering/RenderPipeline.h` +8. `engine/include/XCEngine/Rendering/RenderPipelineAsset.h` +9. `engine/include/XCEngine/Rendering/Pipelines/BuiltinForwardPipeline.h` +10. `engine/src/Rendering/Execution/SceneRenderer.cpp` +11. `engine/src/Rendering/Execution/CameraRenderer.cpp` +12. `engine/src/Rendering/Extraction/RenderSceneExtractor.cpp` +13. `engine/src/Rendering/Pipelines/BuiltinForwardPipeline.cpp` +14. `engine/src/Rendering/Pipelines/Internal/BuiltinForwardPipelineResources.cpp` + +--- + +## 4. 当前真正的问题 + +当前主要不是“功能太少”,而是“职责层次还不够正式”。 + +### 4.1 request、plan、execution 混在一起 + +`CameraRenderRequest` 现在既像外部请求,又像内部执行计划,还夹带了一部分 runtime surface / fullscreen chain 组织信息。 +`SceneRenderer` 也同时承担了 request build、final color resolve、fullscreen intermediate surface ownership 这几类事情。 + +这样的问题是: + +1. 后面很难区分“用户想渲染什么”和“引擎决定怎么执行” +2. Editor 也会继续直接依赖底层 stage 细节 +3. Render Graph 以后很难接到一个稳定的 frame plan 输入 + +### 4.2 extraction 数据还偏早期 + +`RenderSceneExtractor` 现在能工作,但产物仍然偏“把可见对象收集成数组”。 +它还没有正式长成后续 SRP / Render Graph 真正需要的那种中间层: + +1. `CullingResults` +2. `RendererList` +3. `FilteringSettings` +4. `SortingSettings` +5. `DrawSettings` + +如果这层不先正式化,后面 forward、deferred、shadow、object-id、editor overlay 都会继续各自拿 `visibleItems` 做自己的隐式解释。 + +### 4.3 BuiltinForwardPipeline 过重 + +当前 `BuiltinForwardPipeline` 不只是一个 renderer,它已经同时包含: + +1. 主场景 pass 编排 +2. 材质资源布局解析 +3. descriptor set 组织 +4. pipeline state cache +5. lighting / shadow 绑定 +6. skybox 逻辑 +7. gaussian splat 特殊路径 +8. volumetric 特殊路径 + +这会带来两个后果: + +1. 后面任何主场景新能力都会继续往这个类里堆 +2. 未来要抽 `Universal Renderer` 或切出 `Deferred` 时,拆分成本会很高 + +### 4.4 runtime 主线和 editor 扩展点还没正式隔离 + +现在 Editor 已经深度依赖 request stage 注入点,这个方向本身没错,但 contract 还不够正式。 +如果不先收口,后面 graph 化时 editor 特殊路径会变成额外复杂度来源。 + +### 4.5 pipeline contract 还不够像未来的 SRP 底座 + +当前 `RenderPipeline` 还是: + +`Render(context, surface, sceneData)` + +这个接口对当前 builtin forward 足够,但对未来这些东西不够: + +1. renderer list +2. graph resource declaration +3. per-frame context +4. pass feature 注入 +5. 多渲染路径共存 + +第一阶段不要求一步到位,但至少要把它朝这个方向整理。 + +--- + +## 5. 本阶段明确不做的事 + +为了保证收口不失控,这一阶段明确不做下面这些: + +1. 不引入真正运行时 `Render Graph` +2. 不做完整 `Deferred Renderer` +3. 不做 `C# SRP` 暴露 +4. 不重写 RHI +5. 不新增大型渲染特性来打断架构收口 + +本阶段只做一件事: + +`把当前 native rendering layer 整理成 Render Graph 之前的正式形态` + +--- + +## 6. 第一阶段完成后应该达到什么状态 + +本阶段完成后,native renderer 至少应满足下面这些条件: + +1. 外部 request、内部 frame plan、实际 execution 三层语义分开 +2. extraction / culling / draw organization 有正式中间层,不再只靠裸 `visibleItems` +3. `BuiltinForwardPipeline` 明显瘦身,不再继续当总垃圾桶 +4. runtime pass 与 editor pass 有明确注入 contract +5. 后续 `Render Graph` 能接一个稳定的 `Frame Plan + Renderer Lists + Resource Needs` 输入 + +--- + +## 7. 第一阶段的重构原则 + +### 7.1 先 formalize,再 graphize + +先把 contract 和边界做清楚,再做 graph。 +不要反过来。 + +### 7.2 不破坏现有主链闭环 + +当前 `Scene / Game / Editor Viewport` 已经能跑通,第一阶段不能为了“好看”把现有可运行链条打散。 + +### 7.3 新中间层优先 native internal + +这一阶段新补的 `Frame Plan`、`CullingResults`、`RendererList`、`DrawSettings` 都先是 C++ 内部契约,不急着暴露给 C#。 + +### 7.4 先解耦职责,再决定目录长相 + +不要先做大范围目录搬家。 +先把职责拆开,目录只是最后的外显结果。 + +### 7.5 editor contract 正式化,但不去特殊化主链 + +Editor 的 object-id、outline、grid、overlay 依然要保留,但它们应该依附在正式 contract 上,而不是继续共享 runtime 的隐式细节。 + +--- + +## 8. 工作包拆分 + +## 工作包 A:request / frame plan 分层 + +目标: + +把“用户想渲染什么”和“引擎这帧怎么执行”拆开。 + +建议结果: + +1. 保留 `CameraRenderRequest` 作为外部请求描述 +2. 新增内部 `CameraFramePlan` 或等价类型,承载: + - 实际启用的 stage + - fullscreen chain + - resolved target/surface + - 阴影计划结果 + - editor 注入点 +3. `SceneRenderer` 只负责: + - 请求收集 + - 请求排序 + - request -> frame plan 转换 +4. `CameraRenderer` 只负责: + - frame plan 执行 + - 调 scene extraction + - 调 pipeline / standalone pass + +优先涉及文件: + +1. `engine/include/XCEngine/Rendering/Planning/CameraRenderRequest.h` +2. `engine/include/XCEngine/Rendering/Execution/SceneRenderer.h` +3. `engine/src/Rendering/Execution/SceneRenderer.cpp` +4. `engine/include/XCEngine/Rendering/Execution/CameraRenderer.h` +5. `engine/src/Rendering/Execution/CameraRenderer.cpp` + +完成标准: + +1. request 不再混入过多 runtime-owned intermediate state +2. frame plan 成为 camera 执行的正式输入 +3. SceneRenderer 和 CameraRenderer 的边界可以一句话说清 + +## 工作包 B:scene extraction -> culling results / renderer list + +目标: + +把当前 `RenderSceneExtractor` 的数组式输出,推进为后续 SRP/RenderGraph 可用的原生中间层。 + +建议结果: + +1. 在 native 层引入等价于以下概念的类型: + - `CullingResults` + - `RendererListDesc` + - `RendererList` + - `FilteringSettings` + - `SortingSettings` + - `DrawSettings` +2. `RenderSceneData` 不再承担过多“什么都往里塞”的职责 +3. `VisibleRenderItem` 继续保留为底层记录,但不再直接成为所有 pass 的唯一公共输入 +4. shadow、main scene、object-id 等路径逐步改为消费 `RendererList` + +优先涉及文件: + +1. `engine/include/XCEngine/Rendering/FrameData/RenderSceneData.h` +2. `engine/include/XCEngine/Rendering/FrameData/VisibleRenderItem.h` +3. `engine/src/Rendering/Extraction/RenderSceneExtractor.cpp` +4. `engine/include/XCEngine/Rendering/Extraction/` +5. `engine/include/XCEngine/Rendering/Builtin/` + +完成标准: + +1. opaque、transparent、shadow、object-id 至少能共用同一套 draw organization contract +2. 后面新增 deferred 时,不需要再发明第二套“可见对象数组解释逻辑” + +## 工作包 C:pipeline contract 收口 + +目标: + +把当前 `RenderPipeline / RenderPass / RenderPipelineAsset` 收口到更像未来 SRP native kernel 的形态。 + +建议结果: + +1. 继续保留 `RenderPipelineAsset -> RenderPipeline` 这条总方向 +2. 明确区分: + - pipeline asset:配置与默认策略 + - pipeline runtime:本帧执行 + - standalone pass:独立功能 pass +3. 给主场景 pipeline 引入更正式的执行输入,而不是继续只吃 `surface + sceneData` +4. 为下一阶段 graph 化预留清晰输入面: + - frame context + - renderer lists + - per-frame resources + +优先涉及文件: + +1. `engine/include/XCEngine/Rendering/RenderPipeline.h` +2. `engine/include/XCEngine/Rendering/RenderPipelineAsset.h` +3. `engine/include/XCEngine/Rendering/RenderPass.h` +4. `engine/include/XCEngine/Rendering/Pipelines/BuiltinForwardPipeline.h` + +完成标准: + +1. 主 pipeline 输入面能明显映射到未来 `Universal Renderer` +2. standalone pass 与 main scene pipeline 的边界清楚 + +## 工作包 D:BuiltinForwardPipeline 瘦身 + +目标: + +把 `BuiltinForwardPipeline` 从“大一统实现类”拆成可长期维护的 renderer 内部模块。 + +建议结果: + +1. 按职责切成内部模块或 helper: + - main scene draw + - skybox draw + - lighting binding + - shadow binding + - material binding + - pipeline state cache + - per-frame resource cache +2. `GaussianSplat` 和 `Volumetric` 继续保留,但从“主 pipeline 杂糅逻辑”变成清晰的 feature-style 子模块 +3. `BuiltinForwardPipelineResources.cpp` 里和运行时编排无关的资源/绑定组织进一步下沉 + +优先涉及文件: + +1. `engine/include/XCEngine/Rendering/Pipelines/BuiltinForwardPipeline.h` +2. `engine/src/Rendering/Pipelines/BuiltinForwardPipeline.cpp` +3. `engine/src/Rendering/Pipelines/Internal/BuiltinForwardPipelineResources.cpp` +4. `engine/include/XCEngine/Rendering/Materials/RenderMaterialResolve.h` + +完成标准: + +1. `BuiltinForwardPipeline` 主类显著变薄 +2. 新增一种主场景能力时,不需要继续把所有逻辑堆回同一个 cpp + +## 工作包 E:editor 注入点正式化 + +目标: + +保留当前 editor 渲染能力,但把它从“依赖阶段细节”变成“依赖正式 extension contract”。 + +建议结果: + +1. 继续保留: + - object-id + - outline + - grid + - overlay +2. 把这些能力明确分成: + - runtime stage + - editor-only extension stage +3. 收口 `RenderPassSequence` 在 request 上的使用边界,避免后续 graph 化时出现“谁都能往 request 里塞东西”的状态 + +优先涉及文件: + +1. `engine/include/XCEngine/Rendering/Planning/CameraRenderRequest.h` +2. `editor/src/Viewport/SceneViewportRenderPlan.h` +3. `editor/src/Viewport/` +4. `engine/src/Rendering/Execution/CameraRenderer.cpp` + +完成标准: + +1. Editor 仍能完整接入当前主链 +2. 但 editor 不再直接绑死 runtime 内部实现细节 + +## 工作包 F:测试与文档同步 + +目标: + +把第一阶段重构做成可回归、可交接的正式收口,而不是一次只靠手工验证的大重排。 + +建议结果: + +1. 补 `tests/Rendering/unit` +2. 保底回归现有 `tests/Rendering/integration` +3. 必要时补 editor viewport 级验证 +4. 更新 API 文档与后续计划入口 + +完成标准: + +1. request / extractor / pipeline 边界都有对应测试覆盖 +2. 当前 forward、shadow、object-id、editor scene view 不回退 + +--- + +## 9. 执行顺序 + +必须按下面的顺序推进: + +1. 先做工作包 A +2. 再做工作包 B +3. 再做工作包 C +4. 然后做工作包 D +5. 接着做工作包 E +6. 最后统一做工作包 F + +原因: + +1. 不先分清 request 和 frame plan,后面所有 contract 都会悬空 +2. 不先把 extraction 推进到 `renderer list` 层,pipeline 收口只是表面整理 +3. 不先把 pipeline contract 稳住,`BuiltinForwardPipeline` 的瘦身会缺少稳定目标 +4. 不先把 native 主线收紧,editor contract 很容易继续沿着旧细节扩张 + +--- + +## 10. 建议新增或调整的 native 类型 + +第一阶段不要求名字完全按这个来,但建议至少出现这些等价层: + +1. `CameraFramePlan` +2. `FrameExecutionContext` +3. `CullingResults` +4. `RendererListDesc` +5. `RendererList` +6. `DrawSettings` +7. `FilteringSettings` +8. `SortingSettings` +9. `EditorRenderExtensions` 或等价 editor 注入描述 + +注意: + +1. 这些类型先是 `C++ internal contract` +2. 这一阶段不急着桥接到 `managed` +3. 下一阶段 `Render Graph` 会直接消费其中一部分 + +--- + +## 11. 这一阶段完成的验收标准 + +当以下条件同时成立时,这一阶段才算完成: + +1. `SceneRenderer / CameraRenderer / Planner` 三者职责边界稳定 +2. native 渲染主链内部已经形成 request、frame plan、execution 三层 +3. `RenderSceneExtractor` 不再只是输出裸数组,而是能支持正式的 draw organization +4. `BuiltinForwardPipeline` 不再承担明显超载职责 +5. editor 的注入点已经正规化,且没有破坏当前 Scene View / Game View 能力 +6. 现有 forward、shadow、post-process、final-output、object-id、overlay 主路径回归通过 + +--- + +## 12. 下一阶段如何接 Render Graph + +等本阶段完成后,下一阶段才进入真正的 `Render Graph`。 + +那时的接法应该是: + +1. `CameraFramePlan` 提供本帧逻辑阶段与 feature 需求 +2. `CullingResults / RendererList` 提供 draw 输入 +3. `FrameExecutionContext` 提供本帧统一资源上下文 +4. `Render Graph` 负责: + - pass declaration + - resource creation/import + - read/write dependency + - barrier / lifetime + - transient resource reuse + +也就是说,`Render Graph` 不是来替代第一阶段,而是建立在第一阶段之上。 + +--- + +## 13. 一句话结论 + +当前最佳路线不是立刻补 `Deferred`,也不是立刻补 `Render Graph`,而是先把你现有这条 native rendering 主链整理成真正的 `Render Kernel v1`;这一步做实了,后面的 `Render Graph`、`Universal Renderer`、`C# SRP` 才会接得稳。 diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt index 230441b0..00abdac4 100644 --- a/engine/CMakeLists.txt +++ b/engine/CMakeLists.txt @@ -478,11 +478,17 @@ add_library(XCEngine STATIC ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Builtin/BuiltinPassTypes.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Builtin/BuiltinPassMetadataUtils.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Builtin/BuiltinPassLayoutUtils.h - ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Builtin/BuiltinPassContract.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Execution/CameraFramePlan.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Execution/CameraRenderer.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Execution/DirectionalShadowExecutionState.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Execution/DrawSettings.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Execution/FrameExecutionContext.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Execution/ScenePhase.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Execution/SceneRenderer.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/FrameData/CullingResults.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/FrameData/RenderCameraData.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/FrameData/RenderSceneData.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/FrameData/RendererListUtils.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/FrameData/VisibleGaussianSplatItem.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/FrameData/VisibleRenderItem.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/FrameData/VisibleVolumeItem.h @@ -500,8 +506,11 @@ add_library(XCEngine STATIC ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/RenderPipeline.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/RenderPipelineAsset.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/RenderSurface.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/SceneRenderFeaturePass.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Caches/RenderResourceCache.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Caches/DirectionalShadowSurfaceCache.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Shadow/DirectionalShadowData.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Shadow/DirectionalShadowRuntime.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Passes/BuiltinDepthStylePassBase.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Passes/BuiltinDepthOnlyPass.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Passes/BuiltinShadowCasterPass.h @@ -540,6 +549,8 @@ add_library(XCEngine STATIC ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Planning/SceneRenderRequestPlanner.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Planning/Internal/DirectionalShadowPlanning.h ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Planning/Internal/DirectionalShadowPlanning.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Shadow/DirectionalShadowData.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Shadow/DirectionalShadowRuntime.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Execution/SceneRenderer.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Pipelines/BuiltinForwardPipeline.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Pipelines/Internal/BuiltinForwardPipelineSkybox.cpp diff --git a/engine/include/XCEngine/Rendering/Builtin/BuiltinPassContract.h b/engine/include/XCEngine/Rendering/Builtin/BuiltinPassContract.h deleted file mode 100644 index 242740d5..00000000 --- a/engine/include/XCEngine/Rendering/Builtin/BuiltinPassContract.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -#include diff --git a/engine/include/XCEngine/Rendering/Caches/DirectionalShadowSurfaceCache.h b/engine/include/XCEngine/Rendering/Caches/DirectionalShadowSurfaceCache.h index b3beb71e..46f4b1c8 100644 --- a/engine/include/XCEngine/Rendering/Caches/DirectionalShadowSurfaceCache.h +++ b/engine/include/XCEngine/Rendering/Caches/DirectionalShadowSurfaceCache.h @@ -14,6 +14,16 @@ namespace Rendering { struct DirectionalShadowRenderPlan; struct RenderContext; +struct DirectionalShadowSurfaceAllocation { + RenderSurface surface = {}; + RHI::RHIResourceView* depthShaderView = nullptr; + + bool IsValid() const { + return surface.GetDepthAttachment() != nullptr && + depthShaderView != nullptr; + } +}; + class DirectionalShadowSurfaceCache { public: DirectionalShadowSurfaceCache() = default; @@ -21,10 +31,9 @@ public: DirectionalShadowSurfaceCache& operator=(const DirectionalShadowSurfaceCache&) = delete; ~DirectionalShadowSurfaceCache(); - bool EnsureSurface(const RenderContext& context, const DirectionalShadowRenderPlan& plan); - - const RenderSurface& GetSurface() const { return m_surface; } - RHI::RHIResourceView* GetDepthShaderView() const { return m_depthShaderView; } + const DirectionalShadowSurfaceAllocation* Resolve( + const RenderContext& context, + const DirectionalShadowRenderPlan& plan); private: bool Matches(const RenderContext& context, const DirectionalShadowRenderPlan& plan) const; @@ -35,8 +44,7 @@ private: uint32_t m_height = 0; RHI::RHITexture* m_depthTexture = nullptr; RHI::RHIResourceView* m_depthView = nullptr; - RHI::RHIResourceView* m_depthShaderView = nullptr; - RenderSurface m_surface = {}; + DirectionalShadowSurfaceAllocation m_allocation = {}; }; } // namespace Rendering diff --git a/engine/include/XCEngine/Rendering/Execution/CameraRenderer.h b/engine/include/XCEngine/Rendering/Execution/CameraRenderer.h index 4e2f4f82..02788081 100644 --- a/engine/include/XCEngine/Rendering/Execution/CameraRenderer.h +++ b/engine/include/XCEngine/Rendering/Execution/CameraRenderer.h @@ -20,7 +20,8 @@ class RHIResourceView; namespace Rendering { -class DirectionalShadowSurfaceCache; +struct DirectionalShadowExecutionState; +class DirectionalShadowRuntime; class FullscreenPassSurfaceCache; class RenderSurface; class RenderPipelineAsset; @@ -54,17 +55,13 @@ public: private: void ResetPipeline(std::unique_ptr pipeline); - bool ResolveShadowCasterRequest( - const CameraFramePlan& plan, - ShadowCasterRenderRequest& outResolvedShadowCaster, - RHI::RHIResourceView*& outShadowMapView); bool BuildSceneDataForPlan( const CameraFramePlan& plan, - RHI::RHIResourceView* shadowMapView, + const DirectionalShadowExecutionState& shadowState, RenderSceneData& outSceneData); bool ExecuteRenderPlan( const CameraFramePlan& plan, - const ShadowCasterRenderRequest& resolvedShadowCaster, + const DirectionalShadowExecutionState& shadowState, const RenderSceneData& sceneData); RenderSceneExtractor m_sceneExtractor; @@ -73,7 +70,7 @@ private: std::unique_ptr m_objectIdPass; std::unique_ptr m_depthOnlyPass; std::unique_ptr m_shadowCasterPass; - std::unique_ptr m_directionalShadowSurface; + std::unique_ptr m_directionalShadowRuntime; std::unique_ptr m_postProcessSurfaceCache; std::unique_ptr m_finalOutputSurfaceCache; }; diff --git a/engine/include/XCEngine/Rendering/Execution/DirectionalShadowExecutionState.h b/engine/include/XCEngine/Rendering/Execution/DirectionalShadowExecutionState.h new file mode 100644 index 00000000..3ab80254 --- /dev/null +++ b/engine/include/XCEngine/Rendering/Execution/DirectionalShadowExecutionState.h @@ -0,0 +1,23 @@ +#pragma once + +#include +#include + +namespace XCEngine { +namespace Rendering { + +struct DirectionalShadowExecutionState { + ShadowCasterRenderRequest shadowCasterRequest = {}; + RenderDirectionalShadowData shadowData = {}; + + bool HasShadowPass() const { + return shadowCasterRequest.IsRequested(); + } + + bool HasShadowSampling() const { + return shadowData.IsValid(); + } +}; + +} // namespace Rendering +} // namespace XCEngine diff --git a/engine/include/XCEngine/Rendering/FrameData/RenderSceneData.h b/engine/include/XCEngine/Rendering/FrameData/RenderSceneData.h index 501b0169..a348fbed 100644 --- a/engine/include/XCEngine/Rendering/FrameData/RenderSceneData.h +++ b/engine/include/XCEngine/Rendering/FrameData/RenderSceneData.h @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include #include @@ -21,10 +21,6 @@ namespace Components { class CameraComponent; } // namespace Components -namespace RHI { -class RHIResourceView; -} // namespace RHI - namespace Rendering { struct RenderDirectionalLightData { @@ -53,42 +49,6 @@ struct RenderAdditionalLightData { float spotAngle = 0.0f; }; -struct RenderDirectionalShadowMapMetrics { - Math::Vector2 inverseMapSize = Math::Vector2::Zero(); - float worldTexelSize = 0.0f; - float padding = 0.0f; -}; - -static_assert( - sizeof(RenderDirectionalShadowMapMetrics) == sizeof(float) * 4u, - "RenderDirectionalShadowMapMetrics must stay float4-sized for GPU constant layout"); - -struct RenderDirectionalShadowSamplingData { - float enabled = 0.0f; - DirectionalShadowSamplingSettings settings = {}; -}; - -static_assert( - sizeof(RenderDirectionalShadowSamplingData) == sizeof(float) * 4u, - "RenderDirectionalShadowSamplingData must stay float4-sized for GPU constant layout"); - -struct RenderDirectionalShadowCasterBiasData { - DirectionalShadowCasterBiasSettings settings = {}; -}; - -struct RenderDirectionalShadowData { - bool enabled = false; - Math::Matrix4x4 viewProjection = Math::Matrix4x4::Identity(); - RenderDirectionalShadowMapMetrics mapMetrics = {}; - RenderDirectionalShadowSamplingData sampling = {}; - RenderDirectionalShadowCasterBiasData casterBias = {}; - RHI::RHIResourceView* shadowMap = nullptr; - - bool IsValid() const { - return enabled && shadowMap != nullptr; - } -}; - struct RenderLightingData { static constexpr uint32_t kMaxAdditionalLightCount = 8u; diff --git a/engine/include/XCEngine/Rendering/Planning/CameraRenderRequest.h b/engine/include/XCEngine/Rendering/Planning/CameraRenderRequest.h index 67a631cb..8653d022 100644 --- a/engine/include/XCEngine/Rendering/Planning/CameraRenderRequest.h +++ b/engine/include/XCEngine/Rendering/Planning/CameraRenderRequest.h @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include #include @@ -124,29 +124,6 @@ inline bool HasValidSingleSampleColorSource(const RenderSurface& surface) { surface.GetSampleQuality() == 0u; } -struct DirectionalShadowRenderPlan { - bool enabled = false; - Math::Vector3 lightDirection = Math::Vector3::Back(); - Math::Vector3 focusPoint = Math::Vector3::Zero(); - float orthographicHalfExtent = 0.0f; - float texelWorldSize = 0.0f; - float nearClipPlane = 0.1f; - float farClipPlane = 0.0f; - DirectionalShadowSamplingSettings sampling = {}; - DirectionalShadowCasterBiasSettings casterBias = {}; - uint32_t mapWidth = 0; - uint32_t mapHeight = 0; - RenderCameraData cameraData = {}; - - bool IsValid() const { - return enabled && - mapWidth > 0 && - mapHeight > 0 && - cameraData.viewportWidth == mapWidth && - cameraData.viewportHeight == mapHeight; - } -}; - struct ObjectIdRenderRequest { RenderSurface surface; diff --git a/engine/include/XCEngine/Rendering/Shadow/DirectionalShadowData.h b/engine/include/XCEngine/Rendering/Shadow/DirectionalShadowData.h new file mode 100644 index 00000000..8a722204 --- /dev/null +++ b/engine/include/XCEngine/Rendering/Shadow/DirectionalShadowData.h @@ -0,0 +1,82 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include + +namespace XCEngine { +namespace RHI { +class RHIResourceView; +} // namespace RHI + +namespace Rendering { + +struct DirectionalShadowRenderPlan { + bool enabled = false; + Math::Vector3 lightDirection = Math::Vector3::Back(); + Math::Vector3 focusPoint = Math::Vector3::Zero(); + float orthographicHalfExtent = 0.0f; + float texelWorldSize = 0.0f; + float nearClipPlane = 0.1f; + float farClipPlane = 0.0f; + DirectionalShadowSamplingSettings sampling = {}; + DirectionalShadowCasterBiasSettings casterBias = {}; + uint32_t mapWidth = 0; + uint32_t mapHeight = 0; + RenderCameraData cameraData = {}; + + bool IsValid() const { + return enabled && + mapWidth > 0 && + mapHeight > 0 && + cameraData.viewportWidth == mapWidth && + cameraData.viewportHeight == mapHeight; + } +}; + +struct RenderDirectionalShadowMapMetrics { + Math::Vector2 inverseMapSize = Math::Vector2::Zero(); + float worldTexelSize = 0.0f; + float padding = 0.0f; +}; + +static_assert( + sizeof(RenderDirectionalShadowMapMetrics) == sizeof(float) * 4u, + "RenderDirectionalShadowMapMetrics must stay float4-sized for GPU constant layout"); + +struct RenderDirectionalShadowSamplingData { + float enabled = 0.0f; + DirectionalShadowSamplingSettings settings = {}; +}; + +static_assert( + sizeof(RenderDirectionalShadowSamplingData) == sizeof(float) * 4u, + "RenderDirectionalShadowSamplingData must stay float4-sized for GPU constant layout"); + +struct RenderDirectionalShadowCasterBiasData { + DirectionalShadowCasterBiasSettings settings = {}; +}; + +struct RenderDirectionalShadowData { + bool enabled = false; + Math::Matrix4x4 viewProjection = Math::Matrix4x4::Identity(); + RenderDirectionalShadowMapMetrics mapMetrics = {}; + RenderDirectionalShadowSamplingData sampling = {}; + RenderDirectionalShadowCasterBiasData casterBias = {}; + RHI::RHIResourceView* shadowMap = nullptr; + + bool IsValid() const { + return enabled && shadowMap != nullptr; + } +}; + +RenderDirectionalShadowData BuildRenderDirectionalShadowData( + const DirectionalShadowRenderPlan& plan, + RHI::RHIResourceView* shadowMapView); + +} // namespace Rendering +} // namespace XCEngine diff --git a/engine/include/XCEngine/Rendering/Shadow/DirectionalShadowRuntime.h b/engine/include/XCEngine/Rendering/Shadow/DirectionalShadowRuntime.h new file mode 100644 index 00000000..ea3e2ebc --- /dev/null +++ b/engine/include/XCEngine/Rendering/Shadow/DirectionalShadowRuntime.h @@ -0,0 +1,27 @@ +#pragma once + +#include +#include + +namespace XCEngine { +namespace Rendering { + +struct CameraFramePlan; + +class DirectionalShadowRuntime { +public: + DirectionalShadowRuntime() = default; + DirectionalShadowRuntime(const DirectionalShadowRuntime&) = delete; + DirectionalShadowRuntime& operator=(const DirectionalShadowRuntime&) = delete; + ~DirectionalShadowRuntime() = default; + + bool ResolveExecutionState( + const CameraFramePlan& plan, + DirectionalShadowExecutionState& outShadowState); + +private: + DirectionalShadowSurfaceCache m_surfaceCache; +}; + +} // namespace Rendering +} // namespace XCEngine diff --git a/engine/src/Rendering/Caches/DirectionalShadowSurfaceCache.cpp b/engine/src/Rendering/Caches/DirectionalShadowSurfaceCache.cpp index e87c6c9f..f5bb8815 100644 --- a/engine/src/Rendering/Caches/DirectionalShadowSurfaceCache.cpp +++ b/engine/src/Rendering/Caches/DirectionalShadowSurfaceCache.cpp @@ -1,6 +1,7 @@ #include "Rendering/Caches/DirectionalShadowSurfaceCache.h" -#include "Rendering/Planning/CameraRenderRequest.h" +#include "Rendering/RenderContext.h" +#include "Rendering/Shadow/DirectionalShadowData.h" #include "RHI/RHIDevice.h" #include "RHI/RHIResourceView.h" #include "RHI/RHITexture.h" @@ -18,15 +19,15 @@ DirectionalShadowSurfaceCache::~DirectionalShadowSurfaceCache() { Reset(); } -bool DirectionalShadowSurfaceCache::EnsureSurface( +const DirectionalShadowSurfaceAllocation* DirectionalShadowSurfaceCache::Resolve( const RenderContext& context, const DirectionalShadowRenderPlan& plan) { if (!context.IsValid() || !plan.IsValid()) { - return false; + return nullptr; } if (Matches(context, plan)) { - return true; + return &m_allocation; } RHI::TextureDesc depthDesc = {}; @@ -43,7 +44,7 @@ bool DirectionalShadowSurfaceCache::EnsureSurface( RHI::RHITexture* depthTexture = context.device->CreateTexture(depthDesc); if (depthTexture == nullptr) { - return false; + return nullptr; } RHI::ResourceViewDesc depthViewDesc = {}; @@ -55,7 +56,7 @@ bool DirectionalShadowSurfaceCache::EnsureSurface( if (depthView == nullptr) { depthTexture->Shutdown(); delete depthTexture; - return false; + return nullptr; } RHI::ResourceViewDesc depthShaderViewDesc = {}; @@ -68,7 +69,7 @@ bool DirectionalShadowSurfaceCache::EnsureSurface( delete depthView; depthTexture->Shutdown(); delete depthTexture; - return false; + return nullptr; } Reset(); @@ -77,11 +78,11 @@ bool DirectionalShadowSurfaceCache::EnsureSurface( m_height = plan.mapHeight; m_depthTexture = depthTexture; m_depthView = depthView; - m_depthShaderView = depthShaderView; - m_surface = RenderSurface(plan.mapWidth, plan.mapHeight); - m_surface.SetDepthAttachment(depthView); - m_surface.SetSampleDesc(1u, 0u); - return true; + m_allocation.depthShaderView = depthShaderView; + m_allocation.surface = RenderSurface(plan.mapWidth, plan.mapHeight); + m_allocation.surface.SetDepthAttachment(depthView); + m_allocation.surface.SetSampleDesc(1u, 0u); + return &m_allocation; } bool DirectionalShadowSurfaceCache::Matches( @@ -92,7 +93,7 @@ bool DirectionalShadowSurfaceCache::Matches( m_height == plan.mapHeight && m_depthTexture != nullptr && m_depthView != nullptr && - m_depthShaderView != nullptr; + m_allocation.IsValid(); } void DirectionalShadowSurfaceCache::Reset() { @@ -102,10 +103,10 @@ void DirectionalShadowSurfaceCache::Reset() { m_depthView = nullptr; } - if (m_depthShaderView != nullptr) { - m_depthShaderView->Shutdown(); - delete m_depthShaderView; - m_depthShaderView = nullptr; + if (m_allocation.depthShaderView != nullptr) { + m_allocation.depthShaderView->Shutdown(); + delete m_allocation.depthShaderView; + m_allocation.depthShaderView = nullptr; } if (m_depthTexture != nullptr) { @@ -117,7 +118,7 @@ void DirectionalShadowSurfaceCache::Reset() { m_device = nullptr; m_width = 0; m_height = 0; - m_surface = RenderSurface(); + m_allocation = {}; } } // namespace Rendering diff --git a/engine/src/Rendering/Execution/CameraRenderer.cpp b/engine/src/Rendering/Execution/CameraRenderer.cpp index 698897d0..06b2aff0 100644 --- a/engine/src/Rendering/Execution/CameraRenderer.cpp +++ b/engine/src/Rendering/Execution/CameraRenderer.cpp @@ -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(plan.mapWidth) - : 0.0f); - shadowData.mapMetrics.inverseMapSize = Math::Vector2( - 1.0f / static_cast(plan.mapWidth), - 1.0f / static_cast(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()) , m_postProcessSurfaceCache(std::make_unique()) , m_finalOutputSurfaceCache(std::make_unique()) { if (m_objectIdPass == nullptr) { @@ -469,6 +445,7 @@ CameraRenderer::CameraRenderer(std::shared_ptr pipeli , m_objectIdPass(std::make_unique()) , m_depthOnlyPass(CreateDefaultDepthOnlyPass()) , m_shadowCasterPass(CreateDefaultShadowCasterPass()) + , m_directionalShadowRuntime(std::make_unique()) , m_postProcessSurfaceCache(std::make_unique()) , m_finalOutputSurfaceCache(std::make_unique()) { SetPipelineAsset(m_pipelineAsset); @@ -544,43 +521,9 @@ void CameraRenderer::ResetPipeline(std::unique_ptr 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(); - } - - 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"); diff --git a/engine/src/Rendering/Shadow/DirectionalShadowData.cpp b/engine/src/Rendering/Shadow/DirectionalShadowData.cpp new file mode 100644 index 00000000..0430cd1a --- /dev/null +++ b/engine/src/Rendering/Shadow/DirectionalShadowData.cpp @@ -0,0 +1,33 @@ +#include "Rendering/Shadow/DirectionalShadowData.h" + +namespace XCEngine { +namespace Rendering { + +RenderDirectionalShadowData BuildRenderDirectionalShadowData( + 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(plan.mapWidth) + : 0.0f); + shadowData.mapMetrics.inverseMapSize = Math::Vector2( + 1.0f / static_cast(plan.mapWidth), + 1.0f / static_cast(plan.mapHeight)); + shadowData.mapMetrics.worldTexelSize = texelWorldSize; + shadowData.sampling.enabled = 1.0f; + shadowData.sampling.settings = plan.sampling; + shadowData.casterBias.settings = plan.casterBias; + return shadowData; +} + +} // namespace Rendering +} // namespace XCEngine diff --git a/engine/src/Rendering/Shadow/DirectionalShadowRuntime.cpp b/engine/src/Rendering/Shadow/DirectionalShadowRuntime.cpp new file mode 100644 index 00000000..f8ed43d5 --- /dev/null +++ b/engine/src/Rendering/Shadow/DirectionalShadowRuntime.cpp @@ -0,0 +1,44 @@ +#include "Rendering/Shadow/DirectionalShadowRuntime.h" + +#include "Rendering/Execution/CameraFramePlan.h" +#include "Rendering/Shadow/DirectionalShadowData.h" + +namespace XCEngine { +namespace Rendering { + +bool DirectionalShadowRuntime::ResolveExecutionState( + const CameraFramePlan& plan, + DirectionalShadowExecutionState& outShadowState) { + outShadowState = {}; + outShadowState.shadowCasterRequest = plan.shadowCaster; + + if (outShadowState.shadowCasterRequest.IsRequested()) { + return outShadowState.shadowCasterRequest.IsValid(); + } + + if (!plan.directionalShadow.IsValid()) { + return true; + } + + const DirectionalShadowSurfaceAllocation* shadowAllocation = + m_surfaceCache.Resolve(plan.request.context, plan.directionalShadow); + if (shadowAllocation == nullptr || !shadowAllocation->IsValid()) { + return false; + } + + outShadowState.shadowCasterRequest.surface = shadowAllocation->surface; + outShadowState.shadowCasterRequest.clearFlags = RenderClearFlags::Depth; + if (!outShadowState.shadowCasterRequest.hasCameraDataOverride) { + outShadowState.shadowCasterRequest.hasCameraDataOverride = true; + outShadowState.shadowCasterRequest.cameraDataOverride = plan.directionalShadow.cameraData; + } + + outShadowState.shadowData = + BuildRenderDirectionalShadowData( + plan.directionalShadow, + shadowAllocation->depthShaderView); + return true; +} + +} // namespace Rendering +} // namespace XCEngine diff --git a/tests/Rendering/unit/test_render_scene_extractor.cpp b/tests/Rendering/unit/test_render_scene_extractor.cpp index 0a2aa7c9..42914b70 100644 --- a/tests/Rendering/unit/test_render_scene_extractor.cpp +++ b/tests/Rendering/unit/test_render_scene_extractor.cpp @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include