Formalize directional shadow runtime contracts
This commit is contained in:
462
docs/plan/Renderer_C++层第一阶段重构计划_RenderGraph前_2026-04-13.md
Normal file
462
docs/plan/Renderer_C++层第一阶段重构计划_RenderGraph前_2026-04-13.md
Normal file
@@ -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` 才会接得稳。
|
||||||
@@ -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/BuiltinPassTypes.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Builtin/BuiltinPassMetadataUtils.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/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/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/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/RenderCameraData.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/FrameData/RenderSceneData.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/VisibleGaussianSplatItem.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/FrameData/VisibleRenderItem.h
|
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/FrameData/VisibleRenderItem.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/FrameData/VisibleVolumeItem.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/RenderPipeline.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/RenderPipelineAsset.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/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/RenderResourceCache.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Caches/DirectionalShadowSurfaceCache.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/BuiltinDepthStylePassBase.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Passes/BuiltinDepthOnlyPass.h
|
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Passes/BuiltinDepthOnlyPass.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Passes/BuiltinShadowCasterPass.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/SceneRenderRequestPlanner.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Planning/Internal/DirectionalShadowPlanning.h
|
${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/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/Execution/SceneRenderer.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Pipelines/BuiltinForwardPipeline.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Pipelines/BuiltinForwardPipeline.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Pipelines/Internal/BuiltinForwardPipelineSkybox.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Pipelines/Internal/BuiltinForwardPipelineSkybox.cpp
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <XCEngine/Rendering/Builtin/BuiltinPassLayoutUtils.h>
|
|
||||||
@@ -14,6 +14,16 @@ namespace Rendering {
|
|||||||
struct DirectionalShadowRenderPlan;
|
struct DirectionalShadowRenderPlan;
|
||||||
struct RenderContext;
|
struct RenderContext;
|
||||||
|
|
||||||
|
struct DirectionalShadowSurfaceAllocation {
|
||||||
|
RenderSurface surface = {};
|
||||||
|
RHI::RHIResourceView* depthShaderView = nullptr;
|
||||||
|
|
||||||
|
bool IsValid() const {
|
||||||
|
return surface.GetDepthAttachment() != nullptr &&
|
||||||
|
depthShaderView != nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class DirectionalShadowSurfaceCache {
|
class DirectionalShadowSurfaceCache {
|
||||||
public:
|
public:
|
||||||
DirectionalShadowSurfaceCache() = default;
|
DirectionalShadowSurfaceCache() = default;
|
||||||
@@ -21,10 +31,9 @@ public:
|
|||||||
DirectionalShadowSurfaceCache& operator=(const DirectionalShadowSurfaceCache&) = delete;
|
DirectionalShadowSurfaceCache& operator=(const DirectionalShadowSurfaceCache&) = delete;
|
||||||
~DirectionalShadowSurfaceCache();
|
~DirectionalShadowSurfaceCache();
|
||||||
|
|
||||||
bool EnsureSurface(const RenderContext& context, const DirectionalShadowRenderPlan& plan);
|
const DirectionalShadowSurfaceAllocation* Resolve(
|
||||||
|
const RenderContext& context,
|
||||||
const RenderSurface& GetSurface() const { return m_surface; }
|
const DirectionalShadowRenderPlan& plan);
|
||||||
RHI::RHIResourceView* GetDepthShaderView() const { return m_depthShaderView; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool Matches(const RenderContext& context, const DirectionalShadowRenderPlan& plan) const;
|
bool Matches(const RenderContext& context, const DirectionalShadowRenderPlan& plan) const;
|
||||||
@@ -35,8 +44,7 @@ private:
|
|||||||
uint32_t m_height = 0;
|
uint32_t m_height = 0;
|
||||||
RHI::RHITexture* m_depthTexture = nullptr;
|
RHI::RHITexture* m_depthTexture = nullptr;
|
||||||
RHI::RHIResourceView* m_depthView = nullptr;
|
RHI::RHIResourceView* m_depthView = nullptr;
|
||||||
RHI::RHIResourceView* m_depthShaderView = nullptr;
|
DirectionalShadowSurfaceAllocation m_allocation = {};
|
||||||
RenderSurface m_surface = {};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Rendering
|
} // namespace Rendering
|
||||||
|
|||||||
@@ -20,7 +20,8 @@ class RHIResourceView;
|
|||||||
|
|
||||||
namespace Rendering {
|
namespace Rendering {
|
||||||
|
|
||||||
class DirectionalShadowSurfaceCache;
|
struct DirectionalShadowExecutionState;
|
||||||
|
class DirectionalShadowRuntime;
|
||||||
class FullscreenPassSurfaceCache;
|
class FullscreenPassSurfaceCache;
|
||||||
class RenderSurface;
|
class RenderSurface;
|
||||||
class RenderPipelineAsset;
|
class RenderPipelineAsset;
|
||||||
@@ -54,17 +55,13 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void ResetPipeline(std::unique_ptr<RenderPipeline> pipeline);
|
void ResetPipeline(std::unique_ptr<RenderPipeline> pipeline);
|
||||||
bool ResolveShadowCasterRequest(
|
|
||||||
const CameraFramePlan& plan,
|
|
||||||
ShadowCasterRenderRequest& outResolvedShadowCaster,
|
|
||||||
RHI::RHIResourceView*& outShadowMapView);
|
|
||||||
bool BuildSceneDataForPlan(
|
bool BuildSceneDataForPlan(
|
||||||
const CameraFramePlan& plan,
|
const CameraFramePlan& plan,
|
||||||
RHI::RHIResourceView* shadowMapView,
|
const DirectionalShadowExecutionState& shadowState,
|
||||||
RenderSceneData& outSceneData);
|
RenderSceneData& outSceneData);
|
||||||
bool ExecuteRenderPlan(
|
bool ExecuteRenderPlan(
|
||||||
const CameraFramePlan& plan,
|
const CameraFramePlan& plan,
|
||||||
const ShadowCasterRenderRequest& resolvedShadowCaster,
|
const DirectionalShadowExecutionState& shadowState,
|
||||||
const RenderSceneData& sceneData);
|
const RenderSceneData& sceneData);
|
||||||
|
|
||||||
RenderSceneExtractor m_sceneExtractor;
|
RenderSceneExtractor m_sceneExtractor;
|
||||||
@@ -73,7 +70,7 @@ private:
|
|||||||
std::unique_ptr<RenderPass> m_objectIdPass;
|
std::unique_ptr<RenderPass> m_objectIdPass;
|
||||||
std::unique_ptr<RenderPass> m_depthOnlyPass;
|
std::unique_ptr<RenderPass> m_depthOnlyPass;
|
||||||
std::unique_ptr<RenderPass> m_shadowCasterPass;
|
std::unique_ptr<RenderPass> m_shadowCasterPass;
|
||||||
std::unique_ptr<DirectionalShadowSurfaceCache> m_directionalShadowSurface;
|
std::unique_ptr<DirectionalShadowRuntime> m_directionalShadowRuntime;
|
||||||
std::unique_ptr<FullscreenPassSurfaceCache> m_postProcessSurfaceCache;
|
std::unique_ptr<FullscreenPassSurfaceCache> m_postProcessSurfaceCache;
|
||||||
std::unique_ptr<FullscreenPassSurfaceCache> m_finalOutputSurfaceCache;
|
std::unique_ptr<FullscreenPassSurfaceCache> m_finalOutputSurfaceCache;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <XCEngine/Rendering/Planning/CameraRenderRequest.h>
|
||||||
|
#include <XCEngine/Rendering/Shadow/DirectionalShadowData.h>
|
||||||
|
|
||||||
|
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
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
#include <XCEngine/Rendering/FrameData/CullingResults.h>
|
#include <XCEngine/Rendering/FrameData/CullingResults.h>
|
||||||
#include <XCEngine/Rendering/FrameData/RenderCameraData.h>
|
#include <XCEngine/Rendering/FrameData/RenderCameraData.h>
|
||||||
#include <XCEngine/Rendering/FrameData/RenderEnvironmentData.h>
|
#include <XCEngine/Rendering/FrameData/RenderEnvironmentData.h>
|
||||||
#include <XCEngine/Rendering/Shadow/DirectionalShadowSettings.h>
|
#include <XCEngine/Rendering/Shadow/DirectionalShadowData.h>
|
||||||
#include <XCEngine/Rendering/FrameData/VisibleGaussianSplatItem.h>
|
#include <XCEngine/Rendering/FrameData/VisibleGaussianSplatItem.h>
|
||||||
#include <XCEngine/Rendering/FrameData/VisibleRenderItem.h>
|
#include <XCEngine/Rendering/FrameData/VisibleRenderItem.h>
|
||||||
#include <XCEngine/Rendering/FrameData/VisibleVolumeItem.h>
|
#include <XCEngine/Rendering/FrameData/VisibleVolumeItem.h>
|
||||||
@@ -21,10 +21,6 @@ namespace Components {
|
|||||||
class CameraComponent;
|
class CameraComponent;
|
||||||
} // namespace Components
|
} // namespace Components
|
||||||
|
|
||||||
namespace RHI {
|
|
||||||
class RHIResourceView;
|
|
||||||
} // namespace RHI
|
|
||||||
|
|
||||||
namespace Rendering {
|
namespace Rendering {
|
||||||
|
|
||||||
struct RenderDirectionalLightData {
|
struct RenderDirectionalLightData {
|
||||||
@@ -53,42 +49,6 @@ struct RenderAdditionalLightData {
|
|||||||
float spotAngle = 0.0f;
|
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 {
|
struct RenderLightingData {
|
||||||
static constexpr uint32_t kMaxAdditionalLightCount = 8u;
|
static constexpr uint32_t kMaxAdditionalLightCount = 8u;
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
#include <XCEngine/Rendering/RenderContext.h>
|
#include <XCEngine/Rendering/RenderContext.h>
|
||||||
#include <XCEngine/Rendering/RenderPass.h>
|
#include <XCEngine/Rendering/RenderPass.h>
|
||||||
#include <XCEngine/Rendering/RenderSurface.h>
|
#include <XCEngine/Rendering/RenderSurface.h>
|
||||||
#include <XCEngine/Rendering/Shadow/DirectionalShadowSettings.h>
|
#include <XCEngine/Rendering/Shadow/DirectionalShadowData.h>
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
@@ -124,29 +124,6 @@ inline bool HasValidSingleSampleColorSource(const RenderSurface& surface) {
|
|||||||
surface.GetSampleQuality() == 0u;
|
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 {
|
struct ObjectIdRenderRequest {
|
||||||
RenderSurface surface;
|
RenderSurface surface;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,82 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <XCEngine/Core/Math/Matrix4.h>
|
||||||
|
#include <XCEngine/Core/Math/Vector2.h>
|
||||||
|
#include <XCEngine/Core/Math/Vector3.h>
|
||||||
|
#include <XCEngine/Rendering/FrameData/RenderCameraData.h>
|
||||||
|
#include <XCEngine/Rendering/Shadow/DirectionalShadowSettings.h>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
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
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <XCEngine/Rendering/Caches/DirectionalShadowSurfaceCache.h>
|
||||||
|
#include <XCEngine/Rendering/Execution/DirectionalShadowExecutionState.h>
|
||||||
|
|
||||||
|
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
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "Rendering/Caches/DirectionalShadowSurfaceCache.h"
|
#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/RHIDevice.h"
|
||||||
#include "RHI/RHIResourceView.h"
|
#include "RHI/RHIResourceView.h"
|
||||||
#include "RHI/RHITexture.h"
|
#include "RHI/RHITexture.h"
|
||||||
@@ -18,15 +19,15 @@ DirectionalShadowSurfaceCache::~DirectionalShadowSurfaceCache() {
|
|||||||
Reset();
|
Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DirectionalShadowSurfaceCache::EnsureSurface(
|
const DirectionalShadowSurfaceAllocation* DirectionalShadowSurfaceCache::Resolve(
|
||||||
const RenderContext& context,
|
const RenderContext& context,
|
||||||
const DirectionalShadowRenderPlan& plan) {
|
const DirectionalShadowRenderPlan& plan) {
|
||||||
if (!context.IsValid() || !plan.IsValid()) {
|
if (!context.IsValid() || !plan.IsValid()) {
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Matches(context, plan)) {
|
if (Matches(context, plan)) {
|
||||||
return true;
|
return &m_allocation;
|
||||||
}
|
}
|
||||||
|
|
||||||
RHI::TextureDesc depthDesc = {};
|
RHI::TextureDesc depthDesc = {};
|
||||||
@@ -43,7 +44,7 @@ bool DirectionalShadowSurfaceCache::EnsureSurface(
|
|||||||
|
|
||||||
RHI::RHITexture* depthTexture = context.device->CreateTexture(depthDesc);
|
RHI::RHITexture* depthTexture = context.device->CreateTexture(depthDesc);
|
||||||
if (depthTexture == nullptr) {
|
if (depthTexture == nullptr) {
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
RHI::ResourceViewDesc depthViewDesc = {};
|
RHI::ResourceViewDesc depthViewDesc = {};
|
||||||
@@ -55,7 +56,7 @@ bool DirectionalShadowSurfaceCache::EnsureSurface(
|
|||||||
if (depthView == nullptr) {
|
if (depthView == nullptr) {
|
||||||
depthTexture->Shutdown();
|
depthTexture->Shutdown();
|
||||||
delete depthTexture;
|
delete depthTexture;
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
RHI::ResourceViewDesc depthShaderViewDesc = {};
|
RHI::ResourceViewDesc depthShaderViewDesc = {};
|
||||||
@@ -68,7 +69,7 @@ bool DirectionalShadowSurfaceCache::EnsureSurface(
|
|||||||
delete depthView;
|
delete depthView;
|
||||||
depthTexture->Shutdown();
|
depthTexture->Shutdown();
|
||||||
delete depthTexture;
|
delete depthTexture;
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Reset();
|
Reset();
|
||||||
@@ -77,11 +78,11 @@ bool DirectionalShadowSurfaceCache::EnsureSurface(
|
|||||||
m_height = plan.mapHeight;
|
m_height = plan.mapHeight;
|
||||||
m_depthTexture = depthTexture;
|
m_depthTexture = depthTexture;
|
||||||
m_depthView = depthView;
|
m_depthView = depthView;
|
||||||
m_depthShaderView = depthShaderView;
|
m_allocation.depthShaderView = depthShaderView;
|
||||||
m_surface = RenderSurface(plan.mapWidth, plan.mapHeight);
|
m_allocation.surface = RenderSurface(plan.mapWidth, plan.mapHeight);
|
||||||
m_surface.SetDepthAttachment(depthView);
|
m_allocation.surface.SetDepthAttachment(depthView);
|
||||||
m_surface.SetSampleDesc(1u, 0u);
|
m_allocation.surface.SetSampleDesc(1u, 0u);
|
||||||
return true;
|
return &m_allocation;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DirectionalShadowSurfaceCache::Matches(
|
bool DirectionalShadowSurfaceCache::Matches(
|
||||||
@@ -92,7 +93,7 @@ bool DirectionalShadowSurfaceCache::Matches(
|
|||||||
m_height == plan.mapHeight &&
|
m_height == plan.mapHeight &&
|
||||||
m_depthTexture != nullptr &&
|
m_depthTexture != nullptr &&
|
||||||
m_depthView != nullptr &&
|
m_depthView != nullptr &&
|
||||||
m_depthShaderView != nullptr;
|
m_allocation.IsValid();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DirectionalShadowSurfaceCache::Reset() {
|
void DirectionalShadowSurfaceCache::Reset() {
|
||||||
@@ -102,10 +103,10 @@ void DirectionalShadowSurfaceCache::Reset() {
|
|||||||
m_depthView = nullptr;
|
m_depthView = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_depthShaderView != nullptr) {
|
if (m_allocation.depthShaderView != nullptr) {
|
||||||
m_depthShaderView->Shutdown();
|
m_allocation.depthShaderView->Shutdown();
|
||||||
delete m_depthShaderView;
|
delete m_allocation.depthShaderView;
|
||||||
m_depthShaderView = nullptr;
|
m_allocation.depthShaderView = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_depthTexture != nullptr) {
|
if (m_depthTexture != nullptr) {
|
||||||
@@ -117,7 +118,7 @@ void DirectionalShadowSurfaceCache::Reset() {
|
|||||||
m_device = nullptr;
|
m_device = nullptr;
|
||||||
m_width = 0;
|
m_width = 0;
|
||||||
m_height = 0;
|
m_height = 0;
|
||||||
m_surface = RenderSurface();
|
m_allocation = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Rendering
|
} // namespace Rendering
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
#include "Rendering/Execution/CameraRenderer.h"
|
#include "Rendering/Execution/CameraRenderer.h"
|
||||||
|
|
||||||
#include "Components/CameraComponent.h"
|
#include "Components/CameraComponent.h"
|
||||||
#include "Rendering/Caches/DirectionalShadowSurfaceCache.h"
|
|
||||||
#include "Rendering/Caches/FullscreenPassSurfaceCache.h"
|
#include "Rendering/Caches/FullscreenPassSurfaceCache.h"
|
||||||
|
#include "Rendering/Execution/DirectionalShadowExecutionState.h"
|
||||||
#include "Rendering/Passes/BuiltinDepthOnlyPass.h"
|
#include "Rendering/Passes/BuiltinDepthOnlyPass.h"
|
||||||
#include "Rendering/Passes/BuiltinObjectIdPass.h"
|
#include "Rendering/Passes/BuiltinObjectIdPass.h"
|
||||||
#include "Rendering/Passes/BuiltinShadowCasterPass.h"
|
#include "Rendering/Passes/BuiltinShadowCasterPass.h"
|
||||||
#include "Rendering/Pipelines/BuiltinForwardPipeline.h"
|
#include "Rendering/Pipelines/BuiltinForwardPipeline.h"
|
||||||
#include "Rendering/RenderPipelineAsset.h"
|
#include "Rendering/RenderPipelineAsset.h"
|
||||||
#include "Rendering/RenderSurface.h"
|
#include "Rendering/RenderSurface.h"
|
||||||
|
#include "Rendering/Shadow/DirectionalShadowRuntime.h"
|
||||||
#include "RHI/RHIResourceView.h"
|
#include "RHI/RHIResourceView.h"
|
||||||
#include "Scene/Scene.h"
|
#include "Scene/Scene.h"
|
||||||
|
|
||||||
@@ -305,7 +306,7 @@ RenderPassContext BuildFrameStagePassContext(
|
|||||||
bool ExecuteFrameStage(
|
bool ExecuteFrameStage(
|
||||||
CameraFrameStage stage,
|
CameraFrameStage stage,
|
||||||
const CameraFramePlan& plan,
|
const CameraFramePlan& plan,
|
||||||
const ShadowCasterRenderRequest& resolvedShadowCaster,
|
const DirectionalShadowExecutionState& shadowState,
|
||||||
const RenderSceneData& sceneData,
|
const RenderSceneData& sceneData,
|
||||||
CameraFrameExecutionState& executionState) {
|
CameraFrameExecutionState& executionState) {
|
||||||
const RenderPassContext passContext = BuildFrameStagePassContext(stage, plan, sceneData);
|
const RenderPassContext passContext = BuildFrameStagePassContext(stage, plan, sceneData);
|
||||||
@@ -320,7 +321,7 @@ bool ExecuteFrameStage(
|
|||||||
case CameraFrameStage::ShadowCaster:
|
case CameraFrameStage::ShadowCaster:
|
||||||
return ExecuteScenePassRequest(
|
return ExecuteScenePassRequest(
|
||||||
executionState.shadowCasterPass,
|
executionState.shadowCasterPass,
|
||||||
resolvedShadowCaster,
|
shadowState.shadowCasterRequest,
|
||||||
plan.request.context,
|
plan.request.context,
|
||||||
sceneData);
|
sceneData);
|
||||||
case CameraFrameStage::DepthOnly:
|
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 BuildEnvironmentData(const CameraFramePlan& plan) {
|
||||||
RenderEnvironmentData environment = {};
|
RenderEnvironmentData environment = {};
|
||||||
const RenderSurface& mainSceneSurface = plan.GetMainSceneSurface();
|
const RenderSurface& mainSceneSurface = plan.GetMainSceneSurface();
|
||||||
@@ -450,6 +425,7 @@ CameraRenderer::CameraRenderer(
|
|||||||
, m_objectIdPass(std::move(objectIdPass))
|
, m_objectIdPass(std::move(objectIdPass))
|
||||||
, m_depthOnlyPass(std::move(depthOnlyPass))
|
, m_depthOnlyPass(std::move(depthOnlyPass))
|
||||||
, m_shadowCasterPass(std::move(shadowCasterPass))
|
, m_shadowCasterPass(std::move(shadowCasterPass))
|
||||||
|
, m_directionalShadowRuntime(std::make_unique<DirectionalShadowRuntime>())
|
||||||
, m_postProcessSurfaceCache(std::make_unique<FullscreenPassSurfaceCache>())
|
, m_postProcessSurfaceCache(std::make_unique<FullscreenPassSurfaceCache>())
|
||||||
, m_finalOutputSurfaceCache(std::make_unique<FullscreenPassSurfaceCache>()) {
|
, m_finalOutputSurfaceCache(std::make_unique<FullscreenPassSurfaceCache>()) {
|
||||||
if (m_objectIdPass == nullptr) {
|
if (m_objectIdPass == nullptr) {
|
||||||
@@ -469,6 +445,7 @@ CameraRenderer::CameraRenderer(std::shared_ptr<const RenderPipelineAsset> pipeli
|
|||||||
, m_objectIdPass(std::make_unique<Passes::BuiltinObjectIdPass>())
|
, m_objectIdPass(std::make_unique<Passes::BuiltinObjectIdPass>())
|
||||||
, m_depthOnlyPass(CreateDefaultDepthOnlyPass())
|
, m_depthOnlyPass(CreateDefaultDepthOnlyPass())
|
||||||
, m_shadowCasterPass(CreateDefaultShadowCasterPass())
|
, m_shadowCasterPass(CreateDefaultShadowCasterPass())
|
||||||
|
, m_directionalShadowRuntime(std::make_unique<DirectionalShadowRuntime>())
|
||||||
, m_postProcessSurfaceCache(std::make_unique<FullscreenPassSurfaceCache>())
|
, m_postProcessSurfaceCache(std::make_unique<FullscreenPassSurfaceCache>())
|
||||||
, m_finalOutputSurfaceCache(std::make_unique<FullscreenPassSurfaceCache>()) {
|
, m_finalOutputSurfaceCache(std::make_unique<FullscreenPassSurfaceCache>()) {
|
||||||
SetPipelineAsset(m_pipelineAsset);
|
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(
|
bool CameraRenderer::BuildSceneDataForPlan(
|
||||||
const CameraFramePlan& plan,
|
const CameraFramePlan& plan,
|
||||||
RHI::RHIResourceView* shadowMapView,
|
const DirectionalShadowExecutionState& shadowState,
|
||||||
RenderSceneData& outSceneData) {
|
RenderSceneData& outSceneData) {
|
||||||
const RenderSurface& mainSceneSurface = plan.GetMainSceneSurface();
|
const RenderSurface& mainSceneSurface = plan.GetMainSceneSurface();
|
||||||
outSceneData = m_sceneExtractor.ExtractForCamera(
|
outSceneData = m_sceneExtractor.ExtractForCamera(
|
||||||
@@ -592,10 +535,7 @@ bool CameraRenderer::BuildSceneDataForPlan(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (plan.directionalShadow.IsValid()) {
|
outSceneData.lighting.mainDirectionalShadow = shadowState.shadowData;
|
||||||
outSceneData.lighting.mainDirectionalShadow =
|
|
||||||
BuildDirectionalShadowData(plan.directionalShadow, shadowMapView);
|
|
||||||
}
|
|
||||||
outSceneData.globalShaderKeywords = BuildSceneGlobalShaderKeywords(outSceneData);
|
outSceneData.globalShaderKeywords = BuildSceneGlobalShaderKeywords(outSceneData);
|
||||||
|
|
||||||
outSceneData.cameraData.clearFlags = plan.request.clearFlags;
|
outSceneData.cameraData.clearFlags = plan.request.clearFlags;
|
||||||
@@ -609,7 +549,7 @@ bool CameraRenderer::BuildSceneDataForPlan(
|
|||||||
|
|
||||||
bool CameraRenderer::ExecuteRenderPlan(
|
bool CameraRenderer::ExecuteRenderPlan(
|
||||||
const CameraFramePlan& plan,
|
const CameraFramePlan& plan,
|
||||||
const ShadowCasterRenderRequest& resolvedShadowCaster,
|
const DirectionalShadowExecutionState& shadowState,
|
||||||
const RenderSceneData& sceneData) {
|
const RenderSceneData& sceneData) {
|
||||||
CameraFrameExecutionState executionState = {};
|
CameraFrameExecutionState executionState = {};
|
||||||
executionState.pipeline = m_pipeline.get();
|
executionState.pipeline = m_pipeline.get();
|
||||||
@@ -628,7 +568,7 @@ bool CameraRenderer::ExecuteRenderPlan(
|
|||||||
if (!ExecuteFrameStage(
|
if (!ExecuteFrameStage(
|
||||||
stageInfo.stage,
|
stageInfo.stage,
|
||||||
plan,
|
plan,
|
||||||
resolvedShadowCaster,
|
shadowState,
|
||||||
sceneData,
|
sceneData,
|
||||||
executionState)) {
|
executionState)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -689,24 +629,24 @@ bool CameraRenderer::Render(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ShadowCasterRenderRequest resolvedShadowCaster = {};
|
DirectionalShadowExecutionState shadowState = {};
|
||||||
RHI::RHIResourceView* shadowMapView = nullptr;
|
if (m_directionalShadowRuntime == nullptr ||
|
||||||
if (!ResolveShadowCasterRequest(plan, resolvedShadowCaster, shadowMapView)) {
|
!m_directionalShadowRuntime->ResolveExecutionState(plan, shadowState)) {
|
||||||
Debug::Logger::Get().Error(
|
Debug::Logger::Get().Error(
|
||||||
Debug::LogCategory::Rendering,
|
Debug::LogCategory::Rendering,
|
||||||
"CameraRenderer::Render failed: ResolveShadowCasterRequest returned false");
|
"CameraRenderer::Render failed: DirectionalShadowRuntime::ResolveExecutionState returned false");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderSceneData sceneData = {};
|
RenderSceneData sceneData = {};
|
||||||
if (!BuildSceneDataForPlan(plan, shadowMapView, sceneData)) {
|
if (!BuildSceneDataForPlan(plan, shadowState, sceneData)) {
|
||||||
Debug::Logger::Get().Error(
|
Debug::Logger::Get().Error(
|
||||||
Debug::LogCategory::Rendering,
|
Debug::LogCategory::Rendering,
|
||||||
"CameraRenderer::Render failed: BuildSceneDataForPlan returned false");
|
"CameraRenderer::Render failed: BuildSceneDataForPlan returned false");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ExecuteRenderPlan(plan, resolvedShadowCaster, sceneData)) {
|
if (!ExecuteRenderPlan(plan, shadowState, sceneData)) {
|
||||||
Debug::Logger::Get().Error(
|
Debug::Logger::Get().Error(
|
||||||
Debug::LogCategory::Rendering,
|
Debug::LogCategory::Rendering,
|
||||||
"CameraRenderer::Render failed: ExecuteRenderPlan returned false");
|
"CameraRenderer::Render failed: ExecuteRenderPlan returned false");
|
||||||
|
|||||||
33
engine/src/Rendering/Shadow/DirectionalShadowData.cpp
Normal file
33
engine/src/Rendering/Shadow/DirectionalShadowData.cpp
Normal file
@@ -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<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;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Rendering
|
||||||
|
} // namespace XCEngine
|
||||||
44
engine/src/Rendering/Shadow/DirectionalShadowRuntime.cpp
Normal file
44
engine/src/Rendering/Shadow/DirectionalShadowRuntime.cpp
Normal file
@@ -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
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
#include <XCEngine/Core/Math/Bounds.h>
|
#include <XCEngine/Core/Math/Bounds.h>
|
||||||
#include <XCEngine/Core/Math/Quaternion.h>
|
#include <XCEngine/Core/Math/Quaternion.h>
|
||||||
#include <XCEngine/Core/Math/Vector3.h>
|
#include <XCEngine/Core/Math/Vector3.h>
|
||||||
#include <XCEngine/Rendering/Builtin/BuiltinPassContract.h>
|
#include <XCEngine/Rendering/Builtin/BuiltinPassLayoutUtils.h>
|
||||||
#include <XCEngine/Rendering/Materials/RenderMaterialResolve.h>
|
#include <XCEngine/Rendering/Materials/RenderMaterialResolve.h>
|
||||||
#include <XCEngine/Rendering/Materials/RenderMaterialStateUtils.h>
|
#include <XCEngine/Rendering/Materials/RenderMaterialStateUtils.h>
|
||||||
#include <XCEngine/Rendering/Extraction/RenderSceneExtractor.h>
|
#include <XCEngine/Rendering/Extraction/RenderSceneExtractor.h>
|
||||||
|
|||||||
Reference in New Issue
Block a user