docs: sync viewport render flow and builtin pass docs

This commit is contained in:
2026-04-04 16:51:39 +08:00
parent 8d715eb40f
commit b9cde699cc
19 changed files with 377 additions and 205 deletions

View File

@@ -23,29 +23,32 @@ std::unique_ptr<Rendering::RenderPass> CreateSceneViewportEditorOverlayPass(
当前工厂函数会返回一个内部 `SceneViewportEditorOverlayPass` 实例。这个 pass
- 持有对 `renderer` 的引用
- 持有一份按值拷贝/移动进来的 `frameData`
- 按值拷贝一份 `frameData`
- `GetName()` 固定返回 `"SceneViewportEditorOverlay"`
- `Execute(...)` 时调用 `renderer.Render(context.renderContext, context.surface, m_frameData)`
- `Execute(...)` 时调用
因此它本质上是一个很薄的 `RenderPass` 适配层,用来把 Editor overlay renderer 接到 `SceneRenderer` 的 overlay pass 序列里。
```cpp
renderer.Render(context.renderContext, context.surface, m_frameData)
```
## 所有权与生命周期
- 返回值拥有 pass 对象本身
- `renderer` 不被 pass 拥有调用方必须保证在 pass 执行期间仍然有效
- `frameData`入 pass 对象内部,因此可以安全跨过当前调用栈,等到真正渲染时再消费
- 返回值拥有 pass 对象本身
- `renderer` 不被 pass 拥有调用方必须保证在 pass 执行期有效
- `frameData`被拷入 pass 内部,因此可以安全跨过当前调用栈
## 当前使用位置
## 当前用位置
典型调用方是 [ViewportHostService](../../ViewportHostService/ViewportHostService.md)
1.合成 cached editor overlay 和 transient gizmo overlay
2. 再调用 `CreateSceneViewportEditorOverlayPass(...)`
3. 把结果挂进 `requests[0].overlayPasses`
1.通过 `GetSceneViewEditorOverlayFrameData(...)` 取得当前 canonical frame data。
2. 再调用 `CreateSceneViewportEditorOverlayPass(...)`
3. 把结果挂进 `requests[0].overlayPasses`
当前不会在这里再做“cached overlay + transient gizmo overlay”的二次合成合成已经发生在 canonical frame data 构建阶段。
## 相关文档
- [SceneViewportEditorOverlayPass](SceneViewportEditorOverlayPass.md)
- [Render](Render.md)
- [Shutdown](Shutdown.md)
- [ViewportHostService](../../ViewportHostService/ViewportHostService.md)
- [SceneViewportEditorOverlayData](../../SceneViewportEditorOverlayData/SceneViewportEditorOverlayData.md)

View File

@@ -6,13 +6,13 @@
**源文件**: `editor/src/Viewport/Passes/SceneViewportEditorOverlayPass.h`
**描述**: Scene View 世界 overlay 的 GPU 渲染器与 pass 工厂,负责把 overlay 线段和图标批次画进场景颜色目标。
**描述**: Scene View 世界 overlay 的 GPU 渲染器与 pass 工厂,负责把 line、screen triangle 与 sprite 画进 Scene 视口颜色目标。
## 概
## 概
`SceneViewportEditorOverlayPass` 这套代码解决的是“如何把 Scene View 的世界辅助元素真正画进 render target”。和 [SceneViewportOverlayRenderer](../../SceneViewportOverlayRenderer/SceneViewportOverlayRenderer.md) 不同,它不是 ImGui 前端 helper而是 `RenderPass` 级别能力
`SceneViewportEditorOverlayPass` 解决的是“如何把 canonical `SceneViewportOverlayFrameData` 真正画到 Scene View render target”
当前入口包括两部分:
它不是 ImGui HUD helper而是 `RenderPass` 级别能力。当前入口包括两部分:
- `SceneViewportEditorOverlayPassRenderer`
- `CreateSceneViewportEditorOverlayPass(...)`
@@ -20,23 +20,26 @@
## 生命周期与公开入口
- [Render](Render.md)
把当前帧 `worldLines / screenTriangles / worldSprites` 转成 GPU draw call,并画进 Scene 视口颜色目标
把当前帧 `worldLines / screenTriangles / worldSprites` 转成 GPU draw call。
- [Shutdown](Shutdown.md)
释放 pipeline、descriptor set、动态图元 buffer 内置 icon 纹理。
释放 pipeline、descriptorbuffer 内置 icon 纹理。
- [CreateSceneViewportEditorOverlayPass](CreateSceneViewportEditorOverlayPass.md)
生成一帧使用的 `RenderPass` 包装对象,把 `frameData` 绑定到当前 renderer
生成一帧使用的 `RenderPass` 包装对象。
## 当前实现行为
`SceneViewportEditorOverlayPass.cpp` 的实现:
- `Render(...)` 只在有效 `RenderContext` 且后端类型`D3D12`可成功初始化
- 会分别维护:
- `Render(...)` 只在有效 `RenderContext` 且后端为 `D3D12`真正执行
- 渲染器内部维护:
- line pipeline
- sprite pipeline
- depth-tested / always-on-top 两套状态
- 会按需扩容动态 line vertex buffer 与 sprite vertex buffer。
- sprite 贴图当前只加载两张内置 PNG
- 会按需扩容
- line vertex buffer
- screen-triangle vertex buffer
- sprite vertex buffer
- 内置 sprite 纹理当前只有:
- `resources/Icons/camera_gizmo.png`
- `resources/Icons/main_light_gizmo.png`
@@ -44,39 +47,31 @@
这个 pass 消费的是 [SceneViewportOverlayFrameData](../../SceneViewportEditorOverlayData/SceneViewportEditorOverlayData.md)
- `worldLines` -> 线段批次
- `worldSprites` -> 图标 sprite 批次
- `worldLines` -> 世界线段批次
- `screenTriangles` -> transform gizmo 等屏幕空间三角形批次
- `worldSprites` -> camera / light 图标批次
通常由 [ViewportHostService](../../ViewportHostService/ViewportHostService.md) 在 Scene View 渲染请求里注入
`handleRecords` 不参与渲染;它们只供 hit tester / resolver 使用
通常由 [ViewportHostService](../../ViewportHostService/ViewportHostService.md) 在 Scene View render plan 中注入。
## 设计说明
为什么这部分要走 GPU pass而不是和 gizmo 一样直接画在 ImGui 上?
当前这层仍然坚持 GPU pass而不是把所有 overlay 都挪到 ImGui,原因是:
- 世界 overlay 需要和场景深度关系一致。
- 这些内容本质上属于“场景的一部分辅助可视化”,不是纯 UI chrome
- 这样能更自然地支持 `DepthTested``AlwaysOnTop` 两种模式
这是商业引擎常见的分工方式:真正属于 3D 空间的信息放在 render pass编辑器控件壳子放在 UI 层。
## 生命周期与资源管理
- `SceneViewportEditorOverlayPassRenderer` 内部持有 pipeline、descriptor pool、sampler、buffer 和 icon texture 资源。
- [Shutdown](Shutdown.md) / `DestroyResources()` 会释放这些 GPU 资源。
- [CreateSceneViewportEditorOverlayPass](CreateSceneViewportEditorOverlayPass.md) 只是生成一帧使用的 `RenderPass` 包装对象,不拥有长期资源。
- transform gizmo 的正式出图也已经并入 canonical frame可直接在同一 pass 中消费 `screenTriangles`
- HUD orientation gizmo 与世界 overlay 职责不同,仍应留在 UI 层
## 当前限制
- 当前只支持 `D3D12`
- sprite 贴图种类是固定内置集合,不支持开放式资源扩展
- 当前实现专门服务 Editor Scene View不是通用渲染管线 pass
- sprite 种类是固定内置集合。
- 这是专门服务 Editor Scene View 的 pass,不是通用渲染管线组件
## 相关文档
- [Passes](../Passes.md)
- [Render](Render.md)
- [Shutdown](Shutdown.md)
- [CreateSceneViewportEditorOverlayPass](CreateSceneViewportEditorOverlayPass.md)
- [SceneViewportEditorOverlayData](../../SceneViewportEditorOverlayData/SceneViewportEditorOverlayData.md)
- [SceneViewportOverlayBuilder](../../SceneViewportOverlayBuilder/SceneViewportOverlayBuilder.md)
- [SceneViewportHudOverlay](../../SceneViewportHudOverlay/SceneViewportHudOverlay.md)
- [ViewportHostService](../../ViewportHostService/ViewportHostService.md)

View File

@@ -32,7 +32,7 @@
- [SceneViewportRenderPlan](../../SceneViewportRenderPlan/SceneViewportRenderPlan.md) 里的 `SceneViewportGridPassFactory` 负责把 `BuildSceneViewportGridPassData(...)` 的结果转成 `RenderPass`
- [ViewportHostService](../../ViewportHostService/ViewportHostService.md) 当前把这个 factory 绑定到 `CreateSceneViewportGridPass(m_sceneViewportGridRenderer, data)`
- `tests/editor/test_viewport_render_flow_utils.cpp``BuildSceneViewportRenderPlanCollectsPostSceneAndOverlayPasses` 覆盖了 grid factory 被调用的路径
- `tests/Editor/test_viewport_render_flow_utils.cpp``BuildSceneViewportRenderPlanCollectsPostSceneAndOverlayPasses` 覆盖了 grid factory 被调用的路径
## 设计含义

View File

@@ -39,7 +39,7 @@
- [SceneViewportRenderPlan](../../SceneViewportRenderPlan/SceneViewportRenderPlan.md) 的 `SceneViewportSelectionOutlinePassFactory` 会在“有选中对象且 `objectIdShaderView` 可用”时创建这个 pass
- [ViewportHostService](../../ViewportHostService/ViewportHostService.md) 当前把该 factory 绑定到 `CreateSceneViewportSelectionOutlinePass(m_sceneViewportSelectionOutlineRenderer, ...)`
- `tests/editor/test_viewport_render_flow_utils.cpp` 覆盖了:
- `tests/Editor/test_viewport_render_flow_utils.cpp` 覆盖了:
- 选中对象存在时 factory 被调用
- `outlineWidthPixels == 2.0f`
- object-id 纹理缺失时返回警告文案

View File

@@ -14,7 +14,6 @@ SceneViewportRenderPlanBuildResult BuildSceneViewportRenderPlan(
const SceneViewportOverlayData& overlay,
const std::vector<uint64_t>& selectedObjectIds,
const SceneViewportOverlayFrameData& editorOverlayFrameData,
const SceneViewportOverlayFrameData& transientOverlayFrameData,
const SceneViewportGridPassFactory& gridPassFactory,
const SceneViewportSelectionOutlinePassFactory& selectionOutlinePassFactory,
const SceneViewportOverlayPassFactory& overlayPassFactory,
@@ -23,29 +22,87 @@ SceneViewportRenderPlanBuildResult BuildSceneViewportRenderPlan(
## 作用
根据当前 Scene View 的 overlay、选中对象和视口 render targets,构建一份可直接应用到 `CameraRenderRequest` 的 render plan。
根据当前 Scene View 的相机 overlay 状态、选中对象render target 可用性以及当前帧 editor overlay 数据,构建一份可直接应用到 `CameraRenderRequest` 的 render plan。
## 输入分别承担什么职责
| 参数 | 作用 |
|------|------|
| `targets` | 提供 object-id SRV 等 render target 能力信息,决定 selection outline 能否被规划。 |
| `overlay` | 提供 Scene View 相机姿态,供 grid 规划与有效性判断使用。 |
| `selectedObjectIds` | 决定是否需要 selection outline。 |
| `editorOverlayFrameData` | 决定是否需要 editor overlay pass。 |
| `gridPassFactory` | 真正创建 grid pass 的工厂。 |
| `selectionOutlinePassFactory` | 真正创建 selection outline pass 的工厂。 |
| `overlayPassFactory` | 真正创建 editor overlay pass 的工厂。 |
| `debugSelectionMask` | 控制 selection outline 样式中的 debug mask 行为,并影响缺失 object-id SRV 时是否返回 warning。 |
## 当前实现行为
当前函数按下面顺序执行:
当前函数按下面顺序执行:
1. `overlay.valid == false`,直接返回默认结果
2. 调用 `BuildSceneViewportGridPassData(...)` 生成 grid 参数
3. `gridPassData.valid == true``gridPassFactory` 非空,则创建 grid pass 并加入 `result.plan.postScenePasses`
4.`selectedObjectIds` 非空,并且 `targets.objectIdShaderView` `selectionOutlinePassFactory` 都可用,则创建 selection outline pass 并加入 `result.plan.postScenePasses`
5.选中了对象,但缺少 `objectIdShaderView`,且 `debugSelectionMask == false`,则写入警告文案 `Scene object id shader view is unavailable`
6. `editorOverlayFrameData` `transientOverlayFrameData` 合并成一份最终 overlay frame data。
7. 若合成后的 frame data 含有 overlay primitive`overlayPassFactory` 非空,则调用 factory 创建 overlay pass。
8.factory 返回非空 pass则把它加入 `result.plan.overlayPasses`
1. 初始化 `SceneViewportRenderPlanBuildResult result = {}`
2. `overlay.valid == false`,直接返回默认结果
3. 调用 [BuildSceneViewportGridPassData](../ViewportHostRenderFlowUtils/BuildSceneViewportGridPassData.md)
4.`gridPassData.valid == true` `gridPassFactory` 非空,则创建 grid pass 并加入 `result.plan.postScenePasses`
5. `selectedObjectIds` 非空:
- `targets.objectIdShaderView != nullptr` `selectionOutlinePassFactory` 非空时,创建 selection outline pass 并加入 `result.plan.postScenePasses`
- 否则若 `debugSelectionMask == false`,写入 warning `Scene object id shader view is unavailable`
6.`editorOverlayFrameData.HasOverlayPrimitives()``overlayPassFactory` 非空,则创建 overlay pass。
7. 若 overlay pass 非空,加入 `result.plan.overlayPasses`
## 当前返回值语义
- `result.plan.postScenePasses`
- 当前承载 Scene View 的 grid 和 selection outline 两类附加 pass。
- `result.plan.overlayPasses`
- 承载 editor overlay / transient overlay 合并后的最终叠加层。
- `result.warningStatusText`
- 当前主要用于提示“Scene object id shader view is unavailable”这类可降级的 Scene View 缺口。
### `result.plan`
当前 plan 可能同时包含三种附加语义:
- 默认 clear-color override
- `postScenePasses`
- grid
- selection outline
- `overlayPasses`
- editor overlay
### `result.warningStatusText`
这是“可降级但值得提示”的状态,不代表 Scene View 整体失败。
当前最典型的来源是:
- 选中了对象
- 需要 selection outline
-`targets.objectIdShaderView == nullptr`
- 且当前不是 debug mask 模式
此时 Scene View 仍然可以继续渲染,只是失去 selection outline 能力。
## 为什么要把三类 pass 分开规划
### Grid
网格本质上是 Scene View 的空间参考层。它应该紧跟主场景之后,但仍属于“场景空间辅助信息”,所以进入 `postScenePasses`
### Selection Outline
选中轮廓依赖 object-id 结果,也属于“主场景之后的空间增强”,因此同样进入 `postScenePasses`
### Editor Overlay
相机 / 灯光图标、gizmo、屏幕辅助图形更接近“最终 HUD / overlay 叠加层”,所以进入 `overlayPasses`
这种划分并不是为了形式好看,而是为了让未来不同 pass 类别可以有不同的执行约束,而不会全部挤在一个线性列表里。
## 为什么 `overlay.valid == false` 时直接返回
因为当前 grid 规划依赖 Scene View 相机姿态,而 Scene View overlay 的有效性本身就代表“当前 editor camera 数学状态是否成立”。
当它无效时:
- grid 不应硬拼
- selection outline 和 overlay 也不再值得继续按正常 Scene View 语义规划
但这里返回的仍是默认 plan而不是失败状态失败处理属于 [ViewportHostRenderFlowUtils](../ViewportHostRenderFlowUtils/ViewportHostRenderFlowUtils.md) 与 `ViewportHostService` 的职责。
## 测试锚点
@@ -54,9 +111,18 @@ SceneViewportRenderPlanBuildResult BuildSceneViewportRenderPlan(
这些测试确认了:
- grid、selection outlineoverlay pass 的规划入口已经拆开
- overlay frame data 会先合并,再交给 overlay factory
- object-id SRV 缺失时会返回警告而不是直接崩掉整条 Scene View 组装链
- grid、selection outlineoverlay 三条规划入口已经拆开
- overlay pass 直接消费合成后的 `SceneViewportOverlayFrameData`
- object-id SRV 缺失时会返回 warning而不是把整个 Scene View 规划链直接打断
## 设计说明
把工厂回调作为参数传入,而不是在这里直接 new 具体 pass有两个重要收益
- 规划逻辑不依赖具体 renderer 类型,测试更轻
- `ViewportHostService` 可以自由决定 pass renderer 的生命周期与实现细节
这是一种非常实用的商业引擎式写法:数据规划层只描述“需要什么”,资源与执行层决定“具体怎么创建”。
## 相关文档
@@ -65,4 +131,7 @@ SceneViewportRenderPlanBuildResult BuildSceneViewportRenderPlan(
- [SceneViewportGridPassFactory](SceneViewportGridPassFactory.md)
- [SceneViewportSelectionOutlinePassFactory](SceneViewportSelectionOutlinePassFactory.md)
- [SceneViewportOverlayPassFactory](SceneViewportOverlayPassFactory.md)
- [ApplySceneViewportRenderPlan](ApplySceneViewportRenderPlan.md)
- [BuildSceneViewportGridPassData](../ViewportHostRenderFlowUtils/BuildSceneViewportGridPassData.md)
- [BuildSceneViewportSelectionOutlineStyle](../ViewportHostRenderFlowUtils/BuildSceneViewportSelectionOutlineStyle.md)
- [ViewportHostRenderFlowUtils](../ViewportHostRenderFlowUtils/ViewportHostRenderFlowUtils.md)
- [Scene View Render Plan And Failure Flow](../../../../_guides/Editor/Scene-Viewport-Render-Plan-And-Failure-Flow.md)

View File

@@ -6,19 +6,26 @@
**源文件**: `editor/src/Viewport/SceneViewportRenderPlan.h`
**描述**: Scene View 一次渲染提交所需的 post-scene pass、overlay pass 和清屏色覆盖收口成可复用的轻量 request plan
**描述**: Scene View 这一帧额外规划 post-scene pass、overlay pass 和 clear-color override并把这些编辑器专属附加项与基础 `CameraRenderRequest` 装配解耦
## 概览
`SceneViewportRenderPlan.h` 处在 [ViewportHostRenderFlowUtils](../ViewportHostRenderFlowUtils/ViewportHostRenderFlowUtils.md) 和 [ViewportHostService](../ViewportHostService/ViewportHostService.md) 之间
`SceneViewportRenderPlan.h` 处在 [ViewportHostService](../ViewportHostService/ViewportHostService.md) 的 Scene View 主路径中段
解决的不是“如何渲染 Scene View”而是“如何把这一帧 Scene View 额外挂到 `CameraRenderRequest` 上的东西组织好”:
不负责决定“场景里有哪些相机需要渲染”,那是运行时 [SceneRenderer](../../../Rendering/SceneRenderer/SceneRenderer.md) 与 [SceneRenderRequestPlanner](../../../Rendering/SceneRenderRequestPlanner/SceneRenderRequestPlanner.md) 的职责。
- post-scene pass 序列
- overlay pass 序列
- 默认 clear-color override
它负责的是 Scene View 这一层独有的编辑器附加项:
这样 `ViewportHostService` 的 Scene View 路径可以更像“构建 request -> 执行 request”而不是把所有额外 pass 拼装细节都塞在一个方法里。
- 在主场景之后还要不要画无限网格
- 是否需要给当前选中对象做 selection outline
- 是否需要把相机图标、灯光辅助几何、transform gizmo 等 editor overlay 叠上去
- 是否要用统一的 Scene View 背景清屏色覆盖相机自身 clear 结果
这类逻辑如果直接写死在 `ViewportHostService::RenderSceneViewportEntry(...)` 里,会让 service 变成“又要懂主流程,又要懂每种 pass 细节”的大杂糅。当前拆成 render plan 之后,调用链会更清晰:
1. `ViewportHostService` 负责总调度
2. `SceneViewportRenderPlan` 负责“本帧额外挂什么”
3. [ViewportHostRenderFlowUtils](../ViewportHostRenderFlowUtils/ViewportHostRenderFlowUtils.md) 负责失败回退、基础 request 接线和成功收尾
## 公开类型与函数
@@ -26,44 +33,98 @@
|------|------|
| [SceneViewportGridPassFactory](SceneViewportGridPassFactory.md) | 根据 `InfiniteGridPassData` 生成 grid `RenderPass` 的工厂回调。 |
| [SceneViewportSelectionOutlinePassFactory](SceneViewportSelectionOutlinePassFactory.md) | 根据 object-id SRV、选中对象和样式生成 selection outline `RenderPass` 的工厂回调。 |
| [SceneViewportOverlayPassFactory](SceneViewportOverlayPassFactory.md) | 根据合成后的 overlay frame data 生成 GPU overlay pass 的工厂回调。 |
| [SceneViewportRenderPlanBuildResult](SceneViewportRenderPlanBuildResult.md) | 返回 render plan 与可选警告文案。 |
| [SceneViewportOverlayPassFactory](SceneViewportOverlayPassFactory.md) | 根据合成后的 overlay frame data 生成 editor overlay `RenderPass` 的工厂回调。 |
| [SceneViewportRenderPlanBuildResult](SceneViewportRenderPlanBuildResult.md) | 返回 render plan 与可选 warning 文案。 |
| [HasPostScenePasses](HasPostScenePasses.md) | 判断当前计划是否包含 post-scene pass。 |
| [HasOverlayPasses](HasOverlayPasses.md) | 判断当前计划是否包含 overlay pass。 |
| [BuildSceneViewportRenderPlan](BuildSceneViewportRenderPlan.md) | 根据 targets、overlay 和当前帧 overlay 数据构建 render plan。 |
| [ApplySceneViewportRenderPlan](ApplySceneViewportRenderPlan.md) | 把 render plan 写回 `CameraRenderRequest`。 |
| [BuildSceneViewportRenderPlan](BuildSceneViewportRenderPlan.md) | 按当前 Scene View 状态生成 render plan。 |
| [ApplySceneViewportRenderPlan](ApplySceneViewportRenderPlan.md) | 把 render plan 应用到 `CameraRenderRequest`。 |
## `SceneViewportRenderPlan` 结构本身
当前结构包含:
- `postScenePasses`
- 存放 grid、selection outline 这类“仍属于场景空间,但要附加在主场景之后”的 pass
- `overlayPasses`
- 存放 editor overlay 这类 2D/屏幕叠加语义更强的 pass
- `hasClearColorOverride`
- 默认值是 `true`
- `clearColorOverride`
- 默认值是 `(0.27f, 0.27f, 0.27f, 1.0f)`
这里最容易被忽略的一点是:**默认 plan 就带有 Scene View 背景色覆盖**。这意味着即便本帧没有 grid、没有 selection outline、没有 overlay primitiveScene View 仍然会维持统一的编辑器背景基调,而不是完全依赖场景相机自己的 clear 配置。
这种设计很符合商业引擎编辑器的常见做法Scene View 是编辑工作台,不是直接照搬运行时相机输出的 Game View。
## 当前实现行为
`SceneViewportRenderPlan.h` `tests/editor/test_viewport_render_flow_utils.cpp` 当前实现:
`SceneViewportRenderPlan.h` `tests/Editor/test_viewport_render_flow_utils.cpp` 当前实现:
- `BuildSceneViewportRenderPlan(...)``overlay.valid == false` 时直接返回默认结果。
- grid pass 由 `BuildSceneViewportGridPassData(...)` + `SceneViewportGridPassFactory` 决定是否加入 `plan.postScenePasses`
- selection outline pass 由 `targets.objectIdShaderView``selectedObjectIds``SceneViewportSelectionOutlinePassFactory` 决定是否加入 `plan.postScenePasses`
- 如果选中了对象但缺少 `objectIdShaderView`,且不是 debug mask 模式,则会返回警告文案 `Scene object id shader view is unavailable`
- overlay pass 的输入不是单独一份 editor overlay,而是 `editorOverlayFrameData + transientOverlayFrameData` 合并后的结果
- 只有合成后的 overlay frame data 确实含有 primitive且 factory 非空、factory 返回值也非空时,才会向 `overlayPasses` 里追加 pass
- `ApplySceneViewportRenderPlan(...)` 会继续复用 `ApplySceneViewportRenderRequestSetup(...)` 处理 object-id surface 与 `postScenePasses`,然后再补上 `overlayPasses` 和 clear-color override。
- grid pass 由 [BuildSceneViewportGridPassData](../ViewportHostRenderFlowUtils/BuildSceneViewportGridPassData.md) + [SceneViewportGridPassFactory](SceneViewportGridPassFactory.md) 决定是否加入 `plan.postScenePasses`
- selection outline pass 由 `targets.objectIdShaderView``selectedObjectIds`[SceneViewportSelectionOutlinePassFactory](SceneViewportSelectionOutlinePassFactory.md) 决定是否加入 `plan.postScenePasses`
- 选中了对象但缺少 `objectIdShaderView`,且不是 debug mask 模式,则会返回 warning `Scene object id shader view is unavailable`,但不会终止整个 Scene View 渲染
- overlay pass 只在 `editorOverlayFrameData.HasOverlayPrimitives()` 为真、factory 非空且 factory 返回非空 pass 时才追加到 `overlayPasses`
- [ApplySceneViewportRenderPlan](ApplySceneViewportRenderPlan.md) 会先复用 [ApplySceneViewportRenderRequestSetup](../ViewportHostRenderFlowUtils/ApplySceneViewportRenderRequestSetup.md) 处理 object-id surface 与 `postScenePasses`,再补充 `overlayPasses` 和 clear-color override
## 测试锚点
## 真实调用链
当前至少有两条直接测试覆盖
`ViewportHostService::RenderSceneViewportEntry(...)` 中,当前真实顺序大致是
- `BuildSceneViewportRenderPlanCollectsPostSceneAndOverlayPasses`
- `ApplySceneViewportRenderPlanAttachesPlannedPassesAndClearState`
1. `BuildSceneViewportRenderState(...)`
2. `BuildSceneViewportRenderPlan(...)`
3.`warningStatusText != nullptr`,用 `SetViewportStatusIfEmpty(...)` 尝试保留 warning
4. `SceneRenderer::BuildRenderRequests(...)`
5. `ApplySceneViewportRenderPlan(...)`
6. `SceneRenderer::Render(requests)`
7. 成功后 `MarkSceneViewportRenderSuccess(...)`
这条链很重要,因为它说明 render plan 既不是最上层入口,也不是最终执行器,而是 Scene View 专属附加内容的中间规划层。
## 为什么只有 Scene View 需要它
Game View 的目标是尽量接近运行时相机结果,所以它直接走 `SceneRenderer`,不进入这条 editor pass 规划链。
Scene View 则完全不同:
- 它需要编辑器私有背景
- 需要无限网格辅助空间感
- 需要 object-id 驱动的选中轮廓
- 需要 world icon / gizmo / overlay 叠加
因此 Scene View 需要一份独立 render plan而 Game View 不需要。
## 设计说明
把 Scene View request 组装拆成“构建计划”和“应用计划”两段,有两个现实收益:
### 为什么要拆成“Build + Apply”
- 可以单独测试 plan 的拼装逻辑,而不必把整个 `ViewportHostService` 拉起来
- 后续如果 Scene View 再增加 post-scene pass 或 overlay pass扩写点会集中在这一层 helper而不是继续膨胀 `RenderSceneViewportEntry(...)`
商业引擎里常见的一个成熟做法,是把“决定要画什么”和“把这些东西接到一次具体渲染请求上”拆开
当前这样拆的直接收益有三个:
- `BuildSceneViewportRenderPlan(...)` 可以被单独测试,不必真的跑 `SceneRenderer`
- `ApplySceneViewportRenderPlan(...)` 可以专注于 request 接线,不混入逻辑判断
- `ViewportHostService` 的 Scene View 主路径可以保持接近“收集状态 -> 生成 plan -> 生成 request -> 执行 request”的稳定结构
### 为什么 warning 不直接中断渲染
例如 object-id SRV 缺失时selection outline 画不出来,但网格、主场景和 overlay 仍然可能完全正常。
这里返回 warning 而不是直接失败,体现的是编辑器设计里很重要的“尽量降级、不轻易黑屏”原则。这比把所有问题都当成致命错误更适合日常编辑工作流。
## 测试锚点
- `BuildSceneViewportRenderPlanCollectsPostSceneAndOverlayPasses`
- `BuildSceneViewportRenderPlanWarnsWhenSelectionOutlineCannotAccessObjectIdTexture`
- `ApplySceneViewportRenderPlanAttachesPlannedPassesAndClearState`
## 相关文档
- [Viewport](../Viewport.md)
- [ViewportHostRenderFlowUtils](../ViewportHostRenderFlowUtils/ViewportHostRenderFlowUtils.md)
- [ViewportHostService](../ViewportHostService/ViewportHostService.md)
- [SceneViewportGridPassFactory](SceneViewportGridPassFactory.md)
- [SceneViewportSelectionOutlinePassFactory](SceneViewportSelectionOutlinePassFactory.md)
- [SceneViewportEditorOverlayPass](../Passes/SceneViewportEditorOverlayPass/SceneViewportEditorOverlayPass.md)
- [ViewportHostRenderFlowUtils](../ViewportHostRenderFlowUtils/ViewportHostRenderFlowUtils.md)
- [ApplySceneViewportRenderRequestSetup](../ViewportHostRenderFlowUtils/ApplySceneViewportRenderRequestSetup.md)
- [BuildSceneViewportGridPassData](../ViewportHostRenderFlowUtils/BuildSceneViewportGridPassData.md)
- [BuildSceneViewportSelectionOutlineStyle](../ViewportHostRenderFlowUtils/BuildSceneViewportSelectionOutlineStyle.md)
- [Scene View Render Plan And Failure Flow](../../../../_guides/Editor/Scene-Viewport-Render-Plan-And-Failure-Flow.md)

View File

@@ -27,7 +27,7 @@ EditorViewportFrame RequestViewport(
- `requestedThisFrame`
- `requestedWidth`
- `requestedHeight`
- 同时清空当前帧 Scene View transient transform gizmo overlay 缓存
- 同时清空当前帧 Scene View `SceneViewportTransformGizmoOverlayState`,并标记 editor overlay cache 需要按新状态重建
### `RequestViewport(...)`

View File

@@ -81,7 +81,7 @@
按当前实现Scene View 的主路径大致是:
1. `RequestViewport(Scene, size)` 标记本帧需要 Scene 视口,并尽量复用或重建 render target。
2. `SceneViewPanel` 根据当前 selection、工具模式和鼠标状态刷新 gizmo并先调用 `SetSceneViewTransformGizmoOverlayState(...)`
2. `SceneViewPanel` 根据当前 selection、工具模式和鼠标状态刷新 gizmo并先经由 coordinator 提交 gizmo overlay submission
3. 命中测试前,面板通过 `GetSceneViewEditorOverlayFrameData(...)` 取到一份已经合成好 scene icon、相机/灯光辅助几何和 gizmo handle 的 frame data。
4. `RenderRequestedViewports(...)` 中为 Scene entry 构建 `SceneViewportRenderPlan`
- object-id surface
@@ -134,7 +134,7 @@
### 当前帧 gizmo state
- `SetSceneViewTransformGizmoOverlayState(...)` 只负责写入当前帧 gizmo state。
- `SetSceneViewTransformGizmoOverlayState(...)` 只负责写入当前帧 gizmo state;当前 `SceneViewPanel` 是通过 coordinator helper 间接调用它
- `BeginFrame()` 会清空这份 state并把 overlay cache 标记为 dirty。
- 因此 transform gizmo overlay 当前是逐帧输入,而不是长期持久缓存。
@@ -154,9 +154,9 @@ m_sceneViewportOverlayBuilder.Build(..., &m_sceneViewTransformGizmoOverlayState)
当前面板和宿主服务的配合顺序大致是:
1. 面板先刷新 gizmo draw data调用 `SetSceneViewTransformGizmoOverlayState(...)`
1. 面板先刷新 gizmo draw data通过 coordinator 提交 gizmo overlay submission
2. 面板再通过 `GetSceneViewEditorOverlayFrameData(...)` 拿到 hit-test 需要的合成 frame data。
3. 处理完点击、拖拽和导航后,面板会再次刷新 gizmo并再次调用 `SetSceneViewTransformGizmoOverlayState(...)`
3. 处理完点击、拖拽和导航后,面板会再次刷新 gizmo并再次通过 coordinator 提交 submission
4. 后续真正执行 `RenderRequestedViewports(...)` 时,宿主服务会因为 gizmo state 再次变脏而重建 overlay frame data并把它交给 `SceneViewportEditorOverlayPass`
这种顺序有两个直接收益:
@@ -211,6 +211,8 @@ Game View 更接近运行时逻辑:
## 相关文档
- [IViewportHostService](../IViewportHostService/IViewportHostService.md)
- [ViewportHostRenderFlowUtils](../ViewportHostRenderFlowUtils/ViewportHostRenderFlowUtils.md)
- [SceneViewportRenderPlan](../SceneViewportRenderPlan/SceneViewportRenderPlan.md)
- [SceneViewportCameraController](../SceneViewportCameraController/SceneViewportCameraController.md)
- [SceneViewportOverlayBuilder](../SceneViewportOverlayBuilder/SceneViewportOverlayBuilder.md)
- [SceneViewportOverlayProviders](../SceneViewportOverlayProviders/SceneViewportOverlayProviders.md)
@@ -218,5 +220,6 @@ Game View 更接近运行时逻辑:
- [SceneViewportGridPass](../Passes/SceneViewportGridPass/SceneViewportGridPass.md)
- [SceneViewportSelectionOutlinePass](../Passes/SceneViewportSelectionOutlinePass/SceneViewportSelectionOutlinePass.md)
- [SceneViewportEditorOverlayPass](../Passes/SceneViewportEditorOverlayPass/SceneViewportEditorOverlayPass.md)
- [Scene View Render Plan And Failure Flow](../../../../_guides/Editor/Scene-Viewport-Render-Plan-And-Failure-Flow.md)
- [SceneView Interaction And Gizmo Model](../../../../_guides/Editor/SceneView-Interaction-And-Gizmo-Model.md)
- [SceneViewPanel](../../panels/SceneViewPanel/SceneViewPanel.md)

View File

@@ -1,5 +1,6 @@
# BuildInfiniteGridParameters
根据当前相机姿态推导无限网格的尺度与淡出参数。
```cpp
InfiniteGridParameters BuildInfiniteGridParameters(const InfiniteGridPassData& data);
```
@@ -9,29 +10,31 @@ InfiniteGridParameters BuildInfiniteGridParameters(const InfiniteGridPassData& d
当前实现会:
1. 拒绝 `data.valid == false` 的输入。
2. 相机高度为主,计算目标网格间距
3. 把目标间距吸附到最近的十进制尺度 `10^n`
4. 计算下一档网格过渡时的 `transitionBlend`
5. 结合网格尺度和视线到地面距离生成 `fadeDistance`
2. 基于相机高度与朝向估算视线到地面平面的有效距离
3. 以相机高度的一半作为目标 spacing并把它吸附到最近的十进制尺度 `10^n`
4. 计算下一档网格密度过渡时的 `transitionBlend`
5. 结合基础网格尺度和视线距离生成 `fadeDistance`
## 当前特征
- 水平平移不会改变结果
- 相机高度跨过阈值时,`baseScale` 会从 `1 -> 10 -> 100` 这类十进制级别跳变
- `orbitDistance` 当前不参与参数推导
- `baseScale` 始终落在 `1, 10, 100, ...` 这类十进制尺度上
- `transitionBlend` 范围是 `[0, 1]`,并使用平滑插值而不是硬切换
- 水平方向平移不会影响结果;主导参数的是相机高度和观察方向
- `orbitDistance` 当前不参与推导,即使编辑器控制器的轨道距离过期,也不会改变这份结果。
## 测试覆盖
`tests/Editor/test_scene_viewport_overlay_renderer.cpp` 当前验证了:
- 间距始终落在十进制尺度
- 水平平移不影响参数。
- 相机高度升高会扩大网格尺度和淡出距离
- `transitionBlend` 阈值前平滑过渡
- `orbitDistance` 变化不会影响结果。
- 网格间距始终十进制尺度。
- 水平平移不会改变参数。
- 相机升高会扩大 `baseScale``fadeDistance`
- `transitionBlend` 会在切换阈值前平滑逼近下一档
- `orbitDistance` 变化不会影响同一视角下的结果。
## 相关文档
- [BuiltinInfiniteGridPass](BuiltinInfiniteGridPass.md)
- [InfiniteGridPassData](InfiniteGridPassData.md)
- [InfiniteGridParameters](InfiniteGridParameters.md)
- [Render](Render.md)

View File

@@ -1,28 +1,24 @@
# BuiltinInfiniteGridPass::Destructor
**命名空间**: `XCEngine::Rendering::Passes`
**类型**: `destructor`
**头文件**: `XCEngine/Rendering/Passes/BuiltinInfiniteGridPass.h`
## 签名
销毁 builtin infinite-grid pass 对象。
```cpp
~BuiltinInfiniteGridPass() = default;
```
## 作用
销毁 `BuiltinInfiniteGridPass` 对象本身。
## 当前语义
- 当前是默认析构函数,不会自动代替 [Shutdown](Shutdown.md) 释放内部 RHI 资源。
- 如果这个类被长期持有为 renderer 成员,调用方应在销毁前显式执行 `Shutdown()`
- 析构不会清空或验证 `m_shaderPath`;路径只影响后续初始化,而不是对象生命期终结
- 当前析构函数是默认析构,不会自动代替 [Shutdown](Shutdown.md) 释放内部 GPU 资源。
- 如果这个对象在销毁前已经初始化过 pipeline layout、pipeline state、constant pool 或 shader handle,调用方应在销毁前显式执行 `Shutdown()`
- 析构本身不会清空 `m_shaderPath`路径字符串只是普通成员状态,不参与 GPU 资源回收
## 与其他内建路径的差异
- 这点与 [BuiltinObjectIdPass](../BuiltinObjectIdPass/Destructor.md) 和 [BuiltinForwardPipeline](../../Pipelines/BuiltinForwardPipeline/Destructor.md) 不同。
- 后两者的析构函数都会主动兜底调用 `Shutdown()``BuiltinInfiniteGridPass` 当前没有这层保护。
## 相关文档
- [BuiltinInfiniteGridPass](BuiltinInfiniteGridPass.md)
- [Shutdown](Shutdown.md)
- [SetShaderPath](SetShaderPath.md)

View File

@@ -1,28 +1,30 @@
# BuiltinInfiniteGridPass::GetShaderPath
**命名空间**: `XCEngine::Rendering::Passes`
**类型**: `method`
**头文件**: `XCEngine/Rendering/Passes/BuiltinInfiniteGridPass.h`
## 签名
返回当前记录的 infinite-grid shader 路径。
```cpp
const Containers::String& GetShaderPath() const;
```
## 作用
## 返回值
返回这个 grid pass 当前记录的 shader 路径
- 返回内部 `m_shaderPath` 的常量引用
## 当前语义
- 返回的是内部 `m_shaderPath` 的常量引用
- 构造后或调用 [SetShaderPath](SetShaderPath.md) 后,这里反映的就是下一次初始化将使用的路径
- 当前值允许为空;空路径本身不是非法状态,但后续资源创建会失败
- 这里反映的是“下一次资源初始化会尝试加载哪份 shader”而不是“当前 GPU 上已经绑定的是哪份 shader”
- 构造后或调用 [SetShaderPath](SetShaderPath.md) 后,这里返回的就是当前配置值
- 调用 [Shutdown](Shutdown.md) 不会清空这个路径shutdown 只销毁已创建的 GPU 资源
## 当前实现边界
- 允许返回空路径;空路径本身不会立刻报错。
- 但一旦后续进入 `Render()` 的资源创建路径,`CreateResources()` 会因为缺少注入 shader path 而失败。
- 如果 [SetShaderPath](SetShaderPath.md) 改成新路径,当前已创建的资源会先被销毁,后续再按这里返回的新路径重新初始化。
## 相关文档
- [BuiltinInfiniteGridPass](BuiltinInfiniteGridPass.md)
- [SetShaderPath](SetShaderPath.md)
- [Render](Render.md)
- [Shutdown](Shutdown.md)

View File

@@ -12,16 +12,18 @@
|------|------|
| `valid` | 当前参数是否可用于真正绘制网格。 |
| `baseScale` | 当前十进制主网格间距。 |
| `transitionBlend` | 向下一档网格密度过渡的平滑插值。 |
| `transitionBlend` | 向下一档网格密度平滑过渡的插值。 |
| `fadeDistance` | 当前网格淡出距离。 |
## 当前语义
- `baseScale` 始终是 `10^n`类十进制尺度。
- `transitionBlend` 范围在 `[0, 1]`
- `fadeDistance` 同时考网格尺度和视线到地面平面的距离
- `baseScale` 始终是 `10^n` 这类十进制尺度,而不是连续浮点间距
- `transitionBlend` 设计成 `[0, 1]` 范围内的平滑权重,用于在切换阈值前后混合主/次网格层级
- `fadeDistance` 同时考网格尺度和观察距离,避免高空观察时网格过早消失
## 相关文档
- [BuiltinInfiniteGridPass](BuiltinInfiniteGridPass.md)
- [InfiniteGridPassData](InfiniteGridPassData.md)
- [BuildInfiniteGridParameters](BuildInfiniteGridParameters.md)
- [Render](Render.md)

View File

@@ -18,14 +18,22 @@
| `verticalFovDegrees` | 垂直视场角。 |
| `nearClipPlane` | 近裁剪面。 |
| `farClipPlane` | 远裁剪面。 |
| `orbitDistance` | 当前 orbit 距离;实现里不参与参数推导。 |
| `orbitDistance` | 当前 orbit 距离;当前实现里不参与网格参数推导。 |
## 当前使用位置
## 当前语义
- `editor/src/Viewport/ViewportHostRenderFlowUtils.h` 里的 `BuildSceneViewportGridPassData(...)` 会从 overlay 数据组装它
- [BuildInfiniteGridParameters](BuildInfiniteGridParameters.md) 和 [Render](Render.md) 都消费它。
- 这是 `BuiltinInfiniteGridPass` 的纯输入结构,不拥有任何 GPU 资源
- [BuildInfiniteGridParameters](BuildInfiniteGridParameters.md) 和 [Render](Render.md) 都直接消费它。
- 当前 editor 侧会在 `BuildSceneViewportGridPassData(...)` 路径里把 scene viewport overlay 数据翻译成这份结构。
## 当前实现边界
- `valid` 是总开关;为 `false` 时,参数推导和渲染都会直接失效。
- 相机三个基向量默认提供了一组合理初值,但调用方仍应传入当前真实相机姿态,而不是依赖默认值。
## 相关文档
- [BuiltinInfiniteGridPass](BuiltinInfiniteGridPass.md)
- [InfiniteGridParameters](InfiniteGridParameters.md)
- [BuildInfiniteGridParameters](BuildInfiniteGridParameters.md)
- [Render](Render.md)

View File

@@ -1,37 +1,33 @@
# BuiltinInfiniteGridPass::SetShaderPath
**命名空间**: `XCEngine::Rendering::Passes`
**类型**: `method`
**头文件**: `XCEngine/Rendering/Passes/BuiltinInfiniteGridPass.h`
## 签名
更新后续初始化要加载的 infinite-grid shader 路径。
```cpp
void SetShaderPath(const Containers::String& shaderPath);
```
## 作用
## 参数
更新这个 grid pass 后续初始化要加载的 shader 路径。
- `shaderPath` - 新的 shader 资源路径;允许传入空路径。
## 当前实现行为
## 当前语义
当前实现按下面顺序处理:
- 如果新旧路径完全相同,函数会直接返回,不做任何资源操作。
- 如果路径发生变化,当前实现会先调用内部 `DestroyResources()`,释放当前缓存的 pipeline、descriptor 和 shader handle再把 `m_shaderPath` 更新为新值。
- 这意味着改路径会立刻丢弃现有 GPU 资源,但不会在调用点同步重新加载;真正的重新初始化仍要等到下一次 [Render](Render.md)。
1. 如果新旧路径完全相同,直接返回。
2. 调用 `DestroyResources()`,释放当前缓存的 pipeline、descriptor 和 shader handle。
3.`m_shaderPath` 更新为传入值。
## 当前实现边界
## 关键语义
- 改路径会立刻丢弃当前已创建的 GPU 资源,等待下一次 [Render](Render.md) 重新初始化。
- 允许传入空路径;但之后第一次创建资源会因为缺少注入路径而失败。
- 这个方法只改“后续要加载哪份 shader”不立即触发加载。
- 传入空路径是允许的,但后续首次进入资源创建路径时会因为缺少注入 shader path 而失败并记录日志。
- [Shutdown](Shutdown.md) 不会清空这里设置的路径shutdown 只销毁资源,不撤销配置。
- 因此这组接口的语义是:
- `SetShaderPath()` 改“未来要用哪份 shader”
- `Render()` 在需要时按当前路径懒加载资源
- `Shutdown()` 只释放已创建资源
## 相关文档
- [BuiltinInfiniteGridPass](BuiltinInfiniteGridPass.md)
- [GetShaderPath](GetShaderPath.md)
- [Render](Render.md)
- [Shutdown](Shutdown.md)

View File

@@ -1,40 +1,34 @@
# BuiltinInfiniteGridPass::Shutdown
**命名空间**: `XCEngine::Rendering::Passes`
**类型**: `method`
**头文件**: `XCEngine/Rendering/Passes/BuiltinInfiniteGridPass.h`
## 签名
主动释放当前 grid pass 已创建的 GPU 资源。
```cpp
void Shutdown();
```
## 作用
## 行为说明
释放这个 grid pass 已创建的内部 GPU 资源和当前配置路径对应的 shader handle。
## 当前实现行为
当前实现直接调用 `DestroyResources()`,并按顺序销毁:
当前实现直接调用内部 `DestroyResources()`,并按顺序销毁:
1. `m_pipelineState`
2. `m_constantSet`
3. `m_constantPool`
4. `m_pipelineLayout`
5. `m_builtinInfiniteGridShader`
6. `m_device` / `m_backendType` 等缓存状态
## 关键语义
之后还会把:
- `m_device` 置空
- `m_backendType` 复位到默认值
## 当前语义
- 对尚未初始化过的对象调用 `Shutdown()` 是安全的。
- `Shutdown()` 不会清空 `m_shaderPath`后续仍可重新 [Render](Render.md) 并按当前路径懒创建资源
- 默认析构函数不会自动代替它执行清理
- `Shutdown()` 不会清空 `m_shaderPath`,因此后续仍可在相同路径上重新进入 [Render](Render.md) 并懒初始化
- 当前默认析构函数不会自动替你调用这里,所以长期持有该 pass 的 renderer 需要显式转发 `Shutdown()`
## 相关文档
- [BuiltinInfiniteGridPass](BuiltinInfiniteGridPass.md)
- [Destructor](Destructor.md)
- [Render](Render.md)
- [SetShaderPath](SetShaderPath.md)

View File

@@ -1,24 +1,43 @@
# BuiltinObjectIdPass::BuildInputLayout
返回 builtin object-id pass 当前使用的静态顶点布局。
```cpp
static RHI::InputLayoutDesc BuildInputLayout();
```
## 行为说明
## 当前实现返回值
当前实现只声明一个顶点元素:
当前实现会按 `Resources::StaticMeshVertex` 的字段顺序构造 3 个输入元素:
- `POSITION`
1. `POSITION`
- `semanticIndex = 0`
- `Format::R32G32B32_Float`
- 偏移取自 `Resources::StaticMeshVertex::position`
- `format = R32G32B32_Float`
- `inputSlot = 0`
- `alignedByteOffset = offsetof(Resources::StaticMeshVertex, position)`
2. `NORMAL`
- `semanticIndex = 0`
- `format = R32G32B32_Float`
- `inputSlot = 0`
- `alignedByteOffset = offsetof(Resources::StaticMeshVertex, normal)`
3. `TEXCOORD`
- `semanticIndex = 0`
- `format = R32G32_Float`
- `inputSlot = 0`
- `alignedByteOffset = offsetof(Resources::StaticMeshVertex, uv0)`
## 当前语义
- object-id pass 只依赖顶点位置不读取法线、UV、切线或颜色
-和当前 shader 语义一致,因为它只需要做几何覆盖并输出 object-id 颜色
- 这不是“只包含位置”的极简布局;当前 object-id pass 仍然沿用静态网格常用的 `POSITION / NORMAL / TEXCOORD0` 输入契约
-样构建出来的 pipeline 能直接消费 `RenderResourceCache` 上传的 `StaticMeshVertex` 顶点流,而不需要为 object-id 路径单独准备另一套顶点缓冲描述
- 资源绑定层面上object-id pass 只要求 `PerObject` 常量缓冲;这和顶点布局是两个独立维度。
## 测试覆盖
- `tests/Rendering/unit/test_builtin_forward_pipeline.cpp` 显式验证了这里返回的 3 个输入元素及其 offset。
## 相关文档
- [BuiltinObjectIdPass](BuiltinObjectIdPass.md)
- [Render](Render.md)
- [ObjectIdEncoding](../../ObjectIdEncoding/ObjectIdEncoding.md)

View File

@@ -29,9 +29,10 @@
## 关键实现细节
- 当前 input layout 只声明了 `POSITION`,依赖 mesh 顶点位置即可完成 object-id 绘制
- 当前 input layout 沿用 `Resources::StaticMeshVertex``POSITION / NORMAL / TEXCOORD0` 三元素布局,而不是单独定义一套 object-id 专用顶点流
- 每个 object ID 会缓存一套独立 descriptor set避免重复分配常量绑定。
- `RenderResourceCache` 负责把 `Mesh` 上传或复用成 GPU 资源。
- 资源声明会优先读取 shader pass 自己的 `resources`,若为空则回退到 [BuildLegacyBuiltinObjectIdPassResourceBindings](../../RenderMaterialUtility/BuildLegacyBuiltinObjectIdPassResourceBindings.md),再统一交给 [TryBuildBuiltinPassResourceBindingPlan](../../RenderMaterialUtility/TryBuildBuiltinPassResourceBindingPlan.md) 解析。
- shader pass 解析优先匹配 builtin object-id pass tag其次回退到 `ObjectId` / `EditorObjectId` 命名,最后才退到首个 pass。
## 当前实现边界

View File

@@ -1,20 +1,24 @@
# BuiltinObjectIdPass::~BuiltinObjectIdPass
销毁 builtin object-id pass。
```cpp
~BuiltinObjectIdPass() override;
```
## 行为说明
## 当前语义
当前析构函数只有一个动作:
- 当前析构函数会直接调用 [Shutdown](Shutdown.md)。
- 因此对象销毁前会释放 pipeline state、pipeline layout、per-object descriptor set/pool、builtin shader handle以及内部 [RenderResourceCache](../../RenderResourceCache/RenderResourceCache.md)。
- 之前按 object id 缓存的 descriptor set 也会在这一步一起清掉。
```cpp
Shutdown();
```
## 调用方影响
因此它会在对象销毁前显式释放当前缓存的 pipeline state、pipeline layout、每对象 descriptor set、shader handle 和 `RenderResourceCache`
- 即使调用方忘记先手动 `Shutdown()`object-id pass 在析构时也会补做资源回收
- 任何此前观察到的内部 descriptor set、pipeline state 或缓存 mesh 指针,在析构后都不再有效。
## 相关文档
- [BuiltinObjectIdPass](BuiltinObjectIdPass.md)
- [Shutdown](Shutdown.md)
- [Render](Render.md)

View File

@@ -1,20 +1,36 @@
# BuiltinObjectIdPass::Shutdown
主动销毁当前缓存的 object-id pass GPU 资源。
```cpp
void Shutdown() override;
```
## 行为说明
## 当前语义
当前实现直接转内部 `DestroyResources()`,并释放:
- 当前实现直接转发到内部 `DestroyResources()`
- 它会依次清理:
- 内部 [RenderResourceCache](../../RenderResourceCache/RenderResourceCache.md)
- `m_perObjectSets` 中按 object ID 缓存的 descriptor pool / descriptor set
- `m_pipelineState`
- `m_pipelineLayout`
- `m_builtinObjectIdShader`
- 同时还会把 `m_device``m_backendType``m_perObjectBinding``m_firstDescriptorSet` 等运行时状态复位。
- `RenderResourceCache`
- 每对象 descriptor pool / set
- pipeline state
- pipeline layout
- builtin object-id shader handle
## 调用后效果
- 这是一次“回到未初始化状态”的 teardown。
- 下一次 [Render](Render.md) 再进入时,会重新走 `EnsureInitialized(...) -> CreateResources(...)` 路径。
- 当前实现支持重复调用;资源已经清空后,后续 `Shutdown()` 只会处理空状态。
## 调用方影响
- 任何此前由该 pass 间接缓存的 mesh GPU 副本、pipeline state 或 per-object descriptor set都会在这里失效。
- 这不会销毁 `RenderSurface``RenderSceneData` 或调用方持有的 scene / mesh / material 对象本体。
## 相关文档
- [BuiltinObjectIdPass](BuiltinObjectIdPass.md)
- [Destructor](Destructor.md)
- [Render](Render.md)
- [RenderResourceCache](../../RenderResourceCache/RenderResourceCache.md)