311 lines
12 KiB
Markdown
311 lines
12 KiB
Markdown
|
|
# Renderer C++层第一阶段收口计划
|
|||
|
|
|
|||
|
|
日期: `2026-04-13`
|
|||
|
|
|
|||
|
|
## 1. 文档定位
|
|||
|
|
|
|||
|
|
这份文档是 `Render Graph` 之前的最后一轮 `native render kernel v1` 收口计划。
|
|||
|
|
|
|||
|
|
目标不是继续往当前 `Rendering` 层里塞新功能,而是先把下面几件事彻底做清楚:
|
|||
|
|
|
|||
|
|
- `request -> frame plan -> execution` 三层语义分开。
|
|||
|
|
- `RenderSceneExtractor -> CullingResults -> RendererList -> DrawSettings` 这条数据组织链正式化。
|
|||
|
|
- `BuiltinForwardPipeline` 从“大杂烩渲染器”收成“协调器 + 子能力”。
|
|||
|
|
- `Editor` 注入点、阴影、主场景、后处理之间的边界说清楚。
|
|||
|
|
- 给下一步 `C++ Render Graph` 留出稳定输入,而不是把当前混乱直接 graph 化。
|
|||
|
|
|
|||
|
|
结论先写在前面:
|
|||
|
|
|
|||
|
|
- `Render Graph` 应该做在 `C++ native` 层。
|
|||
|
|
- 现在还不应该直接开做 `Render Graph` 或 `Deferred Renderer`。
|
|||
|
|
- 当前更优先的是把现有渲染层整理干净,再往 SRP/URP 方向演进。
|
|||
|
|
|
|||
|
|
## 2. 当前阶段已经完成的收口
|
|||
|
|
|
|||
|
|
截至 `2026-04-13` 晚间,已经落地的内容:
|
|||
|
|
|
|||
|
|
- `CameraRenderRequest -> CameraFramePlan` 已经分层,`CameraRenderer` 开始正式消费 plan。
|
|||
|
|
- `CullingResults / RendererList` contract 已经进入 `RenderSceneData`。
|
|||
|
|
- `Forward / Depth / ObjectId` 已经优先走 `RendererList`,旧 `visibleItems` 只保留过渡 fallback。
|
|||
|
|
- `RendererListUtils` 已经把可见项遍历规则收口成公共工具。
|
|||
|
|
- `Gaussian / Volumetric` 已经从 `BuiltinForwardPipeline` 中抽成统一 `SceneRenderFeaturePass`。
|
|||
|
|
- `FrameExecutionContext / ScenePhase / DrawSettings` 已经引入。
|
|||
|
|
- `RenderPipeline` 已经支持新的 `FrameExecutionContext` 入口,旧三参数入口保留为兼容适配层。
|
|||
|
|
- `BuiltinForwardPipeline` 已经开始按 scene phase 组织主场景执行。
|
|||
|
|
- `CameraRenderer` 主场景阶段已经走新的 execution context,而不是继续只传三参数。
|
|||
|
|
|
|||
|
|
本轮验证结果:
|
|||
|
|
|
|||
|
|
- `XCEditor` 已重新编译通过。
|
|||
|
|
- `rendering_unit_tests` 已重新编译通过。
|
|||
|
|
- `editor_tests` 已重新编译通过。
|
|||
|
|
- `editor_tests --gtest_filter=*ViewportRenderFlow*:*SceneViewportRenderPassBundle* --gtest_brief=1` 通过 `14/14`。
|
|||
|
|
- `rendering_unit_tests --gtest_filter=*BuiltinForwardPipeline*:*RenderPass*:*CameraSceneRenderer*:*Shadow*:*ObjectId* --gtest_brief=1` 通过 `67/68`。
|
|||
|
|
- 唯一失败仍然是既有老问题:
|
|||
|
|
`BuiltinForwardPipeline_Test.OpenGLRuntimeTranspilesForwardShadowVariantToLegacyClipConventions`
|
|||
|
|
|
|||
|
|
## 3. 为什么现在还不能直接上 Render Graph
|
|||
|
|
|
|||
|
|
现在直接上 `Render Graph`,本质上是在 graph 里继续承接当前的隐式耦合,问题只会换个位置存在。
|
|||
|
|
|
|||
|
|
当前还没完全收口的核心问题不是“没有 graph”,而是下面这些边界还不够正式:
|
|||
|
|
|
|||
|
|
- `CameraRenderer` 和各类 scene pass 之间,谁负责组织阶段,谁负责执行,还没有完全模块化。
|
|||
|
|
- `Shadow` 相关逻辑仍然分散在 planner、camera execution、pipeline、surface cache 几处。
|
|||
|
|
- `BuiltinForwardPipeline` 虽然已经开始瘦身,但还没有彻底收成一个明确的 coordinator。
|
|||
|
|
- `Editor` 的扩展点虽然已可用,但 contract 还偏“约定式”,还不够像以后给 `C# SRP` 暴露的正式接口。
|
|||
|
|
- 目录结构仍然在暴露旧历史:一些“子系统”目前还是文件堆,不是真正的模块。
|
|||
|
|
|
|||
|
|
如果这些问题不先解决,`Render Graph` 只会变成一个新的承压层,后面再拆更贵。
|
|||
|
|
|
|||
|
|
## 4. Render Graph 和未来 SRP/URP 的边界
|
|||
|
|
|
|||
|
|
未来的推荐结构仍然是这条线:
|
|||
|
|
|
|||
|
|
`RHI -> Native Render Kernel -> Render Graph -> SRP-like Contract -> Universal Renderer -> C# Custom Pipeline`
|
|||
|
|
|
|||
|
|
其中边界应当明确成这样:
|
|||
|
|
|
|||
|
|
- `C++ native` 保留:
|
|||
|
|
- `Render Graph`
|
|||
|
|
- `CullingResults / RendererList`
|
|||
|
|
- draw / dispatch context
|
|||
|
|
- GPU resource cache
|
|||
|
|
- shadow map / atlas 执行能力
|
|||
|
|
- Gaussian 排序与 working set
|
|||
|
|
- Volume 资源上传与底层执行
|
|||
|
|
- `URP-like` 包层保留:
|
|||
|
|
- feature 编排
|
|||
|
|
- pass 注入顺序
|
|||
|
|
- renderer feature 配置
|
|||
|
|
- 用户级 pipeline 组合
|
|||
|
|
- 未来的 `C#` 自定义渲染管线 API
|
|||
|
|
|
|||
|
|
这意味着:
|
|||
|
|
|
|||
|
|
- 阴影、Gaussian、Volumetric 不是整块搬去包层。
|
|||
|
|
- 包层更像 Unity 的 `URP renderer` 和 `renderer feature`。
|
|||
|
|
- native 层更像 Unity 没公开给用户、但真正负责执行和图资源生命周期的内核。
|
|||
|
|
|
|||
|
|
## 5. 第一阶段还差哪些工作才能收口
|
|||
|
|
|
|||
|
|
### 5.1 Shadow 子系统正式化
|
|||
|
|
|
|||
|
|
这是当前最值得先做的一块。
|
|||
|
|
|
|||
|
|
现状问题:
|
|||
|
|
|
|||
|
|
- 阴影规划在 `Planning`。
|
|||
|
|
- 阴影 surface/cache 在 `Execution/Caches`。
|
|||
|
|
- 阴影执行又是 standalone pass。
|
|||
|
|
- 主场景采样阴影的状态切换仍在 `BuiltinForwardPipeline`。
|
|||
|
|
|
|||
|
|
这说明阴影现在“能跑”,但还不是一个正式子系统。
|
|||
|
|
|
|||
|
|
收口目标:
|
|||
|
|
|
|||
|
|
- 明确 `shadow planning / shadow resources / shadow execution / shadow sampling contract` 四层边界。
|
|||
|
|
- 把方向光阴影相关共享数据收成一组正式类型,而不是散落在多个调用点上。
|
|||
|
|
- 为以后扩展 `cascades / shadow atlas / additional light shadows / baked shadowmask` 留出位置。
|
|||
|
|
|
|||
|
|
### 5.2 Editor 注入点正式化
|
|||
|
|
|
|||
|
|
现状问题:
|
|||
|
|
|
|||
|
|
- 当前有 `pre scene / post scene / overlay / object id / outline / grid` 多种 editor 路径。
|
|||
|
|
- 这些能力已经能工作,但还没有统一成“正式 stage 注入 contract”。
|
|||
|
|
|
|||
|
|
收口目标:
|
|||
|
|
|
|||
|
|
- 明确哪些注入点属于 runtime 正式阶段,哪些属于 editor-only extension。
|
|||
|
|
- 让 `CameraFramePlan` 对这些阶段的描述更加稳定。
|
|||
|
|
- 给以后 `C# renderer feature` 的注入点设计提供 native 对照物。
|
|||
|
|
|
|||
|
|
### 5.3 BuiltinForwardPipeline 继续瘦身
|
|||
|
|
|
|||
|
|
本轮已经完成第一刀,但还没收完。
|
|||
|
|
|
|||
|
|
还需要继续做的事情:
|
|||
|
|
|
|||
|
|
- 把 forward scene phase 执行和底层 draw/resource 逻辑彻底分开。
|
|||
|
|
- 把 forward renderer 自己的内部资源、skybox、feature 协调代码进一步收拢。
|
|||
|
|
- 保证 `BuiltinForwardPipeline` 自己只表达“阶段顺序和协调”,不再继续膨胀。
|
|||
|
|
|
|||
|
|
### 5.4 旧 fallback 的裁边
|
|||
|
|
|
|||
|
|
当前有一些过渡兼容层是故意保留的:
|
|||
|
|
|
|||
|
|
- `RenderPipeline::Render(context, surface, sceneData)` 旧入口
|
|||
|
|
- `visibleItems` fallback
|
|||
|
|
- `BuildRenderRequests` 旧习惯入口
|
|||
|
|
|
|||
|
|
这些现在不该硬删,因为会影响现有 tests 和 editor 链路。
|
|||
|
|
|
|||
|
|
但第一阶段收口前,至少要做到:
|
|||
|
|
|
|||
|
|
- 新主链默认只走正式 contract。
|
|||
|
|
- 旧入口只作为 adapter,不再新增依赖。
|
|||
|
|
- 每个 fallback 都有明确退出条件。
|
|||
|
|
|
|||
|
|
### 5.5 测试和文档补齐
|
|||
|
|
|
|||
|
|
当前已有回归还不够系统。
|
|||
|
|
|
|||
|
|
还需要补的重点测试:
|
|||
|
|
|
|||
|
|
- `FrameExecutionContext` 是否完整透传 source surface / source color view / state。
|
|||
|
|
- `BuiltinForwardPipeline` scene phase 顺序是否稳定。
|
|||
|
|
- feature pass 的 `Prepare -> Execute` 顺序是否稳定。
|
|||
|
|
- editor 注入点在有后处理和无后处理两种情况下是否仍能保持正确 source/destination surface。
|
|||
|
|
- shadow planning 和 main scene shadow sampling 之间的契约测试。
|
|||
|
|
|
|||
|
|
## 6. 下一步最优先该做什么
|
|||
|
|
|
|||
|
|
下一步最优先建议做:
|
|||
|
|
|
|||
|
|
`Shadow 子系统收口`
|
|||
|
|
|
|||
|
|
原因很直接:
|
|||
|
|
|
|||
|
|
- 它横跨 `Planning / Execution / Pipeline / Resources / Sampling`。
|
|||
|
|
- 它是以后 `Deferred / Light Baking / ShadowMask / Additional Light Shadows` 的共同基础。
|
|||
|
|
- 它也是未来 `Render Graph` 最敏感的一类资源依赖链。
|
|||
|
|
- 如果阴影先不收,后面 graph 化时 barrier、resource lifetime、pass dependency 都会更乱。
|
|||
|
|
|
|||
|
|
建议顺序:
|
|||
|
|
|
|||
|
|
1. 先把方向光阴影的 plan/data/resource/execute contract 固化。
|
|||
|
|
2. 再把 editor 注入 contract 固化。
|
|||
|
|
3. 然后做第一轮目录收拢。
|
|||
|
|
4. 最后判断这一阶段是否可以正式收口,进入 `Render Graph` 设计。
|
|||
|
|
|
|||
|
|
## 7. 当前 Rendering 目录结构存在的问题
|
|||
|
|
|
|||
|
|
### 7.1 `FrameData` 目录太杂
|
|||
|
|
|
|||
|
|
现在 `FrameData` 里同时混着:
|
|||
|
|
|
|||
|
|
- camera/environment 数据
|
|||
|
|
- scene snapshot
|
|||
|
|
- visible item
|
|||
|
|
- culling results
|
|||
|
|
- renderer list utils
|
|||
|
|
|
|||
|
|
这说明它不是一个明确模块,而是“跟帧有关的先放这”。
|
|||
|
|
|
|||
|
|
建议方向:
|
|||
|
|
|
|||
|
|
- `FrameData` 保留纯只读帧快照类型。
|
|||
|
|
- 把 `CullingResults / RendererList / Filtering / Sorting / DrawSettings` 逐步收进更明确的 `Execution` 或 `Culling` 子域。
|
|||
|
|
- `RendererListUtils` 这种执行辅助逻辑,不适合长期留在 `FrameData`。
|
|||
|
|
|
|||
|
|
### 7.2 `Passes` 目录混合了三类东西
|
|||
|
|
|
|||
|
|
现在 `Passes` 里同时有:
|
|||
|
|
|
|||
|
|
- 主场景 pass
|
|||
|
|
- fullscreen/post-process pass
|
|||
|
|
- editor pass
|
|||
|
|
|
|||
|
|
这会让“runtime 正式渲染能力”和“editor 辅助渲染能力”继续混在一起。
|
|||
|
|
|
|||
|
|
建议方向:
|
|||
|
|
|
|||
|
|
- `Passes/Scene`
|
|||
|
|
- `Passes/Fullscreen`
|
|||
|
|
- `Passes/Editor`
|
|||
|
|
- `Passes/Shadow`
|
|||
|
|
|
|||
|
|
不一定要一次性全搬,但后面新增文件不应继续平铺。
|
|||
|
|
|
|||
|
|
### 7.3 `BuiltinForwardPipeline` 还没形成真正子模块
|
|||
|
|
|
|||
|
|
当前 forward 相关代码已经分散在:
|
|||
|
|
|
|||
|
|
- `BuiltinForwardPipeline.h/.cpp`
|
|||
|
|
- `BuiltinForwardPipelineSkybox.cpp`
|
|||
|
|
- `Internal/BuiltinForwardPipelineResources.cpp`
|
|||
|
|
|
|||
|
|
这已经具备“应该单独成目录”的条件。
|
|||
|
|
|
|||
|
|
建议方向:
|
|||
|
|
|
|||
|
|
- `Rendering/Pipelines/BuiltinForward/`
|
|||
|
|
- `BuiltinForwardPipeline.h`
|
|||
|
|
- `BuiltinForwardPipeline.cpp`
|
|||
|
|
- `BuiltinForwardPipelineScene.cpp`
|
|||
|
|
- `BuiltinForwardPipelineResources.cpp`
|
|||
|
|
- `BuiltinForwardPipelineSkybox.cpp`
|
|||
|
|
|
|||
|
|
这样后面 forward / deferred / universal renderer 才能并列演进。
|
|||
|
|
|
|||
|
|
### 7.4 `Shadow` 目录还不算真正的 shadow 子系统
|
|||
|
|
|
|||
|
|
目前虽然已经有 `Rendering/Shadow`,但从全链路看,阴影的责任仍然散在其他目录。
|
|||
|
|
|
|||
|
|
建议方向:
|
|||
|
|
|
|||
|
|
- `Shadow` 目录最终至少容纳:
|
|||
|
|
- planning types
|
|||
|
|
- shared frame data
|
|||
|
|
- runtime resources / caches
|
|||
|
|
- shadow executor or shadow renderer
|
|||
|
|
|
|||
|
|
### 7.5 `Internal` 边界不稳定
|
|||
|
|
|
|||
|
|
现在 `src/Rendering/Internal` 更像历史遗留缓冲区。
|
|||
|
|
|
|||
|
|
长期风险:
|
|||
|
|
|
|||
|
|
- 真正属于 forward 的内部实现放在全局 `Internal`
|
|||
|
|
- 真正属于 volume / splat / shadow 的内部实现也可能继续堆进去
|
|||
|
|
|
|||
|
|
建议方向:
|
|||
|
|
|
|||
|
|
- 全局 `Internal` 只保留跨模块公共 helper。
|
|||
|
|
- 各子系统自己的内部文件放回各自目录。
|
|||
|
|
|
|||
|
|
## 8. 建议的第一轮目录收拢动作
|
|||
|
|
|
|||
|
|
这一轮只做低风险收拢,不做大搬家。
|
|||
|
|
|
|||
|
|
建议动作:
|
|||
|
|
|
|||
|
|
- 把 `BuiltinForwardPipeline*` 相关实现收成 `Pipelines/BuiltinForward/` 子目录。
|
|||
|
|
- 给 `Passes` 至少先分出 `Editor` 和 `Fullscreen` 两个子目录。
|
|||
|
|
- 给 `Shadow` 补一组正式 shared types,再决定是否移动更多实现文件。
|
|||
|
|
- 暂时不大动 `include` 层 public 路径,先保证编译和引用稳定。
|
|||
|
|
|
|||
|
|
原则:
|
|||
|
|
|
|||
|
|
- 先按职责拆,再按目录搬。
|
|||
|
|
- 不为了“好看”做纯目录手术。
|
|||
|
|
- 每次收拢都必须带编译和回归。
|
|||
|
|
|
|||
|
|
## 9. 第一阶段收口完成的判定标准
|
|||
|
|
|
|||
|
|
满足下面这些条件,就可以认为 `Render Graph` 之前这一阶段基本收口:
|
|||
|
|
|
|||
|
|
- `CameraFramePlan` 成为主执行入口,旧 request 入口只保留兼容壳。
|
|||
|
|
- `FrameExecutionContext / ScenePhase / DrawSettings` 成为主场景执行正式 contract。
|
|||
|
|
- `CullingResults / RendererList` 成为主要 draw organization contract。
|
|||
|
|
- `BuiltinForwardPipeline` 被收成 coordinator,而不是继续长成总垃圾堆。
|
|||
|
|
- `Shadow` 成为清晰子系统,而不是散点逻辑。
|
|||
|
|
- `Editor` 注入点形成稳定 contract。
|
|||
|
|
- 目录结构不再继续鼓励“新逻辑直接往老文件里塞”。
|
|||
|
|
- 相关 tests 和编译链稳定。
|
|||
|
|
|
|||
|
|
到这一步,再开始 `C++ Render Graph`,代价才是可控的。
|
|||
|
|
|
|||
|
|
## 10. 当前建议
|
|||
|
|
|
|||
|
|
当前最佳路线不变:
|
|||
|
|
|
|||
|
|
- 短期:继续按 Unity 的 `SRP + URP` 方向做 native 基座。
|
|||
|
|
- 中期:先在 `C++` 做出稳定的 `Render Graph + RendererList + Feature Injection` 内核。
|
|||
|
|
- 中长期:再暴露 `C#` 自定义渲染管线接口,做你自己的 `URP-like` 包层。
|
|||
|
|
|
|||
|
|
眼下最正确的动作不是“赶紧补 deferred”,也不是“先把所有特效搬去包层”,而是:
|
|||
|
|
|
|||
|
|
`先把当前 native rendering layer 整理成一个真正可扩展的内核。`
|