docs: sync viewport render flow and builtin pass docs
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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、descriptor、buffer 与内置 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)
|
||||
|
||||
@@ -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 被调用的路径
|
||||
|
||||
## 设计含义
|
||||
|
||||
|
||||
@@ -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 纹理缺失时返回警告文案
|
||||
|
||||
@@ -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 outline 和 overlay pass 的规划入口已经拆开
|
||||
- overlay frame data 会先合并,再交给 overlay factory
|
||||
- object-id SRV 缺失时会返回警告而不是直接崩掉整条 Scene View 组装链
|
||||
- grid、selection outline、overlay 三条规划入口已经拆开
|
||||
- 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)
|
||||
|
||||
@@ -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 primitive,Scene 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)
|
||||
|
||||
@@ -27,7 +27,7 @@ EditorViewportFrame RequestViewport(
|
||||
- `requestedThisFrame`
|
||||
- `requestedWidth`
|
||||
- `requestedHeight`
|
||||
- 同时清空当前帧 Scene View transient transform gizmo overlay 缓存。
|
||||
- 同时清空当前帧 Scene View 的 `SceneViewportTransformGizmoOverlayState`,并标记 editor overlay cache 需要按新状态重建。
|
||||
|
||||
### `RequestViewport(...)`
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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。
|
||||
|
||||
## 当前实现边界
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user