docs: add scene viewport pass docs

This commit is contained in:
2026-04-03 15:53:16 +08:00
parent aaeb885566
commit c7eb9857cb
20 changed files with 1041 additions and 0 deletions

View File

@@ -0,0 +1,55 @@
# Passes
**命名空间**: `XCEngine::Editor`
**类型**: `submodule`
**源目录**: `editor/src/Viewport/Passes/`
**描述**: Scene View 专用 GPU pass 子模块,负责把 editor-owned 的网格、选中轮廓和世界 overlay 注入场景渲染请求。
## 概述
这个子目录当前包含三类 Scene View 专用 pass
- [SceneViewportGridPass](SceneViewportGridPass/SceneViewportGridPass.md)
- Editor 自己拥有的 post-scene 网格 pass内部包装 [BuiltinInfiniteGridPass](../../../Rendering/Passes/BuiltinInfiniteGridPass/BuiltinInfiniteGridPass.md)。
- [SceneViewportSelectionOutlinePass](SceneViewportSelectionOutlinePass/SceneViewportSelectionOutlinePass.md)
- Editor 自己拥有的 post-scene 选中轮廓 pass内部包装 [BuiltinObjectIdOutlinePass](../../../Rendering/Passes/BuiltinObjectIdOutlinePass/BuiltinObjectIdOutlinePass.md)。
- [SceneViewportEditorOverlayPass](SceneViewportEditorOverlayPass/SceneViewportEditorOverlayPass.md)
- Scene View 世界 overlay pass负责画世界线段、图标 sprite 和屏幕三角形批次。
当前 Scene View 的 GPU 注入链路已经拆成两段:
- `postScenePasses`
- `SceneViewportGridPass`
- `SceneViewportSelectionOutlinePass`
- `overlayPasses`
- `SceneViewportEditorOverlayPass`
它们的职责都不是替代 `SceneViewPanel` 上的 ImGui 交互 overlay而是把“真正属于 3D 场景空间或 Scene View 渲染阶段”的辅助内容接到 `SceneRenderer` 请求里。
这种分层很合理:
- 需要在主场景之后、overlay 之前补一层编辑器效果的内容,放进 post-scene pass。
- 需要和场景深度关系一致的世界 overlay放进 overlay pass。
- 需要响应鼠标命中、直接叠在 ImGui 纹理表面的 HUD / 前端控件,保留在 draw list。
## 当前实现限制
- 当前这些 pass 只在 `D3D12` 后端返回成功。
- `SceneViewportGridPass` / `SceneViewportSelectionOutlinePass` 目前是 Editor 对 runtime builtin pass 的包装层,不是新的 runtime 公共语义。
- overlay sprite 贴图来源仍是编辑器资源目录中的 PNG 文件,不是材质系统通用资源。
- 这组 pass 由 [ViewportHostService](../ViewportHostService/ViewportHostService.md) 在 Scene View 渲染时按需注入,不是通用渲染管线公共 pass。
## 页面
- [SceneViewportGridPass](SceneViewportGridPass/SceneViewportGridPass.md) - `SceneViewportGridPass.h`
- [SceneViewportSelectionOutlinePass](SceneViewportSelectionOutlinePass/SceneViewportSelectionOutlinePass.md) - `SceneViewportSelectionOutlinePass.h`
- [SceneViewportEditorOverlayPass](SceneViewportEditorOverlayPass/SceneViewportEditorOverlayPass.md) - `SceneViewportEditorOverlayPass.h`
## 相关文档
- [Viewport](../Viewport.md)
- [SceneViewportRenderPlan](../SceneViewportRenderPlan/SceneViewportRenderPlan.md)
- [SceneViewportOverlayBuilder](../SceneViewportOverlayBuilder/SceneViewportOverlayBuilder.md)

View File

@@ -0,0 +1,51 @@
# CreateSceneViewportEditorOverlayPass
**命名空间**: `XCEngine::Editor`
**类型**: `factory-function`
**源文件**: `editor/src/Viewport/Passes/SceneViewportEditorOverlayPass.h`
## 签名
```cpp
std::unique_ptr<Rendering::RenderPass> CreateSceneViewportEditorOverlayPass(
SceneViewportEditorOverlayPassRenderer& renderer,
const SceneViewportOverlayFrameData& frameData);
```
## 作用
创建一帧使用的 Scene View editor overlay pass并把当前 `frameData` 绑定进去。
## 当前实现行为
当前工厂函数会返回一个内部 `SceneViewportEditorOverlayPass` 实例。这个 pass
- 持有对 `renderer` 的引用
- 持有一份按值拷贝/移动进来的 `frameData`
- `GetName()` 固定返回 `"SceneViewportEditorOverlay"`
- `Execute(...)` 时调用 `renderer.Render(context.renderContext, context.surface, m_frameData)`
因此它本质上是一个很薄的 `RenderPass` 适配层,用来把 Editor overlay renderer 接到 `SceneRenderer` 的 overlay pass 序列里。
## 所有权与生命周期
- 返回值拥有 pass 对象本身
- `renderer` 不被 pass 拥有,调用方必须保证它在 pass 执行期间仍然有效
- `frameData` 会进入 pass 对象内部,因此可以安全跨过当前调用栈,等到真正渲染时再消费
## 当前使用位置
典型调用方是 [ViewportHostService](../../ViewportHostService/ViewportHostService.md)
1. 先合成 cached editor overlay 和 transient gizmo overlay
2. 再调用 `CreateSceneViewportEditorOverlayPass(...)`
3. 把结果挂进 `requests[0].overlayPasses`
## 相关文档
- [SceneViewportEditorOverlayPass](SceneViewportEditorOverlayPass.md)
- [Render](Render.md)
- [Shutdown](Shutdown.md)
- [ViewportHostService](../../ViewportHostService/ViewportHostService.md)

View File

@@ -0,0 +1,98 @@
# SceneViewportEditorOverlayPassRenderer::Render
**命名空间**: `XCEngine::Editor`
**类型**: `method`
**源文件**: `editor/src/Viewport/Passes/SceneViewportEditorOverlayPass.h`
## 签名
```cpp
bool Render(
const Rendering::RenderContext& renderContext,
const Rendering::RenderSurface& surface,
const SceneViewportOverlayFrameData& frameData);
```
## 作用
把当前帧 Scene View 世界 overlay 变成 GPU draw call并绘制到给定 `RenderSurface` 的颜色目标上。
## 当前实现行为
### 1. 早退与初始化
- `frameData` 没有任何 overlay primitive 时,直接返回 `true`
- `renderContext` 无效或 `commandList` 为空时,也直接返回 `true`
- 真正开始绘制前会调用 `EnsureInitialized(renderContext)`,只支持 `D3D12`
这意味着它把“当前帧没有 overlay 可画”视为成功路径,而不是异常。
### 2. 拆分三类批次
当前会先把 `frameData` 拆成三条绘制数据流:
- `worldLines`
- `screenTriangles`
- `worldSprites`
并且每一类都会再按 `SceneViewportOverlayDepthMode` 分成:
- `DepthTested`
- `AlwaysOnTop`
sprite 还会按 `sortDepth` 做 back-to-front 排序,以保证透明图标混合顺序稳定。
### 3. 准备动态 buffer
按当前顶点总数,会分别调用:
- `EnsureLineBufferCapacity(...)`
- `EnsureScreenTriangleBufferCapacity(...)`
- `EnsureSpriteBufferCapacity(...)`
只要当前帧存在 sprite还会调用 `EnsureIconTexturesLoaded()`,按需加载:
- `camera_gizmo.png`
- `main_light_gizmo.png`
### 4. 上传常量与切换 render target
当前会把下面这些数据写入常量缓冲:
- view-projection matrix
- viewport 宽高
- 宽高倒数
然后把 Scene 视口颜色目标从 `surface.GetColorStateAfter()` 切到 `RenderTarget`,绘制结束后再切回原状态。
### 5. 依次绘制 line / sprite / screen triangle
当前 draw 顺序是:
1. line
2. sprite
3. screen triangle
每一类内部都先画 `DepthTested`,再画 `AlwaysOnTop`,并切换到对应 pipeline state。
这让世界空间辅助线、图标和部分屏幕三角形 overlay 可以共享同一套 pass但仍保留不同的深度语义。
## 返回值语义
- 资源初始化、buffer 准备、纹理加载和绘制都成功时,返回 `true`
- 初始化失败、buffer 扩容失败、icon 纹理加载失败或 render target 无效时,返回 `false`
## 当前限制
- 只支持 `D3D12`
- sprite 贴图集合固定,不是开放式资源注册系统
- 这条渲染路径只服务于 Editor Scene View overlay不是通用 runtime pass
## 相关文档
- [SceneViewportEditorOverlayPass](SceneViewportEditorOverlayPass.md)
- [Shutdown](Shutdown.md)
- [CreateSceneViewportEditorOverlayPass](CreateSceneViewportEditorOverlayPass.md)
- [SceneViewportEditorOverlayData](../../SceneViewportEditorOverlayData/SceneViewportEditorOverlayData.md)

View File

@@ -0,0 +1,82 @@
# SceneViewportEditorOverlayPass
**命名空间**: `XCEngine::Editor`
**类型**: `renderer class + pass factory`
**源文件**: `editor/src/Viewport/Passes/SceneViewportEditorOverlayPass.h`
**描述**: Scene View 世界 overlay 的 GPU 渲染器与 pass 工厂,负责把 overlay 线段和图标批次画进场景颜色目标。
## 概述
`SceneViewportEditorOverlayPass` 这套代码解决的是“如何把 Scene View 的世界辅助元素真正画进 render target”。和 [SceneViewportOverlayRenderer](../../SceneViewportOverlayRenderer/SceneViewportOverlayRenderer.md) 不同,它不是 ImGui 前端 helper而是 `RenderPass` 级别能力。
当前入口包括两部分:
- `SceneViewportEditorOverlayPassRenderer`
- `CreateSceneViewportEditorOverlayPass(...)`
## 生命周期与公开入口
- [Render](Render.md)
把当前帧 `worldLines / screenTriangles / worldSprites` 转成 GPU draw call并画进 Scene 视口颜色目标。
- [Shutdown](Shutdown.md)
释放 pipeline、descriptor set、动态图元 buffer 和内置 icon 纹理。
- [CreateSceneViewportEditorOverlayPass](CreateSceneViewportEditorOverlayPass.md)
生成一帧使用的 `RenderPass` 包装对象,把 `frameData` 绑定到当前 renderer。
## 当前实现行为
`SceneViewportEditorOverlayPass.cpp` 的实现:
- `Render(...)` 只在有效 `RenderContext` 且后端类型为 `D3D12` 时可成功初始化。
- 会分别维护:
- line pipeline
- sprite pipeline
- depth-tested / always-on-top 两套状态
- 会按需扩容动态 line vertex buffer 与 sprite vertex buffer。
- sprite 贴图当前只加载两张内置 PNG
- `resources/Icons/camera_gizmo.png`
- `resources/Icons/main_light_gizmo.png`
## 数据来源
这个 pass 消费的是 [SceneViewportOverlayFrameData](../../SceneViewportEditorOverlayData/SceneViewportEditorOverlayData.md)
- `worldLines` -> 线段批次
- `worldSprites` -> 图标 sprite 批次
通常由 [ViewportHostService](../../ViewportHostService/ViewportHostService.md) 在 Scene View 渲染请求里注入。
## 设计说明
为什么这部分要走 GPU pass而不是和 gizmo 一样直接画在 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` 包装对象,不拥有长期资源。
## 当前限制
- 当前只支持 `D3D12`
- 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)
- [ViewportHostService](../../ViewportHostService/ViewportHostService.md)

View File

@@ -0,0 +1,56 @@
# SceneViewportEditorOverlayPassRenderer::Shutdown
**命名空间**: `XCEngine::Editor`
**类型**: `method`
**源文件**: `editor/src/Viewport/Passes/SceneViewportEditorOverlayPass.h`
## 签名
```cpp
void Shutdown();
```
## 作用
释放 `SceneViewportEditorOverlayPassRenderer` 持有的 GPU 资源,并把 renderer 复位到未初始化状态。
## 当前实现行为
`Shutdown()` 当前本身非常薄,只做一件事:
```cpp
DestroyResources();
```
`DestroyResources()` 会按资源类型依次释放:
- line / screen-triangle / sprite 三类 vertex buffer 及 view
- camera / light 两张 overlay sprite 纹理、SRV 和 descriptor set
- depth-tested / always-on-top 两套 line、screen-triangle、sprite pipeline state
- sampler / constant / texture descriptor pool 与 descriptor set
- pipeline layout
释放完成后还会把这些内部状态全部清空:
- 各类指针置空
- buffer capacity 置零
- `m_device = nullptr`
- `m_backendType` 回到默认 `D3D12`
## 设计含义
这个 API 的职责不是“结束一帧 pass”而是“销毁长期缓存的 renderer 资源”。因此它通常出现在:
- 编辑器关闭
- 设备重建
- 宿主 service shutdown
而不是每帧调用。
## 相关文档
- [SceneViewportEditorOverlayPass](SceneViewportEditorOverlayPass.md)
- [Render](Render.md)
- [CreateSceneViewportEditorOverlayPass](CreateSceneViewportEditorOverlayPass.md)

View File

@@ -0,0 +1,51 @@
# CreateSceneViewportGridPass
**命名空间**: `XCEngine::Editor`
**类型**: `factory-function`
**源文件**: `editor/src/Viewport/Passes/SceneViewportGridPass.h`
## 签名
```cpp
std::unique_ptr<Rendering::RenderPass> CreateSceneViewportGridPass(
SceneViewportGridPassRenderer& renderer,
const Rendering::Passes::InfiniteGridPassData& data);
```
## 作用
创建一个本帧使用的 Scene View 网格 `RenderPass`,把 `InfiniteGridPassData` 绑定到给定 renderer。
## 当前实现行为
当前工厂函数返回内部类 `SceneViewportGridPass` 的实例。这个 pass
- 持有对 `renderer` 的引用
- 按值保存 `data`
- `GetName()` 固定返回 `"SceneViewportGrid"`
- `Execute(...)` 时调用 `renderer.Render(context.renderContext, context.surface, m_data)`
因此它本质上是一个很薄的适配层,用来把 `SceneViewportGridPassRenderer` 接进 `RenderPassSequence`
## 所有权与生命周期
- 返回值拥有 pass 对象本身
- `renderer` 不被 pass 拥有,调用方必须保证 renderer 在 pass 执行前不会失效
- `data` 会被复制进 pass 内部,因此可以安全跨过当前调用栈,等到真正渲染时再消费
## 当前使用位置
典型调用点是 [ViewportHostService](../../ViewportHostService/ViewportHostService.md)
1. 先通过 `BuildSceneViewportGridPassData(...)` 组装 `InfiniteGridPassData`
2. 再经由 [SceneViewportRenderPlan](../../SceneViewportRenderPlan/SceneViewportRenderPlan.md) 的 `SceneViewportGridPassFactory`
3. 最终把结果挂进 `plan.postScenePasses`
## 相关文档
- [SceneViewportGridPass](SceneViewportGridPass.md)
- [Render](Render.md)
- [Shutdown](Shutdown.md)
- [SceneViewportRenderPlan](../../SceneViewportRenderPlan/SceneViewportRenderPlan.md)

View File

@@ -0,0 +1,46 @@
# SceneViewportGridPassRenderer::Render
**命名空间**: `XCEngine::Editor`
**类型**: `method`
**源文件**: `editor/src/Viewport/Passes/SceneViewportGridPass.h`
## 签名
```cpp
bool Render(
const Rendering::RenderContext& renderContext,
const Rendering::RenderSurface& surface,
const Rendering::Passes::InfiniteGridPassData& data);
```
## 作用
执行 Scene View 无限网格绘制,把一份 `InfiniteGridPassData` 转交给底层 `BuiltinInfiniteGridPass`
## 当前实现行为
当前实现本身没有额外逻辑,函数体就是:
```cpp
return m_gridPass.Render(renderContext, surface, data);
```
因此它的语义边界非常明确:
- Editor 层不在这里修改网格参数
- Editor 层不在这里补充 render target 或 clear 行为
- 真正的初始化、shader 选择、绘制和失败条件都由 [BuiltinInfiniteGridPass](../../../../Rendering/Passes/BuiltinInfiniteGridPass/BuiltinInfiniteGridPass.md) 决定
## 返回值语义
- 当底层 `m_gridPass.Render(...)` 成功时,返回 `true`
- 当底层 pass 因上下文、资源或后端条件失败时,返回 `false`
## 相关文档
- [SceneViewportGridPass](SceneViewportGridPass.md)
- [Shutdown](Shutdown.md)
- [CreateSceneViewportGridPass](CreateSceneViewportGridPass.md)
- [BuiltinInfiniteGridPass](../../../../Rendering/Passes/BuiltinInfiniteGridPass/BuiltinInfiniteGridPass.md)

View File

@@ -0,0 +1,57 @@
# SceneViewportGridPass
**命名空间**: `XCEngine::Editor`
**类型**: `renderer class + pass factory`
**源文件**: `editor/src/Viewport/Passes/SceneViewportGridPass.h`
**描述**: Scene View 无限网格的 Editor 侧 `RenderPass` 适配层,把 Rendering 模块里的 `BuiltinInfiniteGridPass` 接到 viewport 的 `postScenePasses` 序列。
## 概览
`SceneViewportGridPass.h` 没有重新实现网格算法,而是把 Runtime 侧现成的 [BuiltinInfiniteGridPass](../../../../Rendering/Passes/BuiltinInfiniteGridPass/BuiltinInfiniteGridPass.md) 包了一层 Editor 适配:
- `SceneViewportGridPassRenderer`
- `CreateSceneViewportGridPass(...)`
这样 `ViewportHostService` 在组装 [SceneViewportRenderPlan](../../SceneViewportRenderPlan/SceneViewportRenderPlan.md) 时,可以直接把 Scene View 相机姿态推导出的 `InfiniteGridPassData` 变成一个标准 `RenderPass`
## 当前实现行为
`SceneViewportGridPass.cpp` 的当前实现:
- `SceneViewportGridPassRenderer` 内部只持有一个 `BuiltinInfiniteGridPass m_gridPass`
- [Render](Render.md) 只是把 `renderContext``surface``InfiniteGridPassData` 原样转发给 `m_gridPass.Render(...)`
- [Shutdown](Shutdown.md) 只是转发到 `m_gridPass.Shutdown()`
- [CreateSceneViewportGridPass](CreateSceneViewportGridPass.md) 会创建一个内部 `SceneViewportGridPass` 对象:
- 持有对 `renderer` 的引用
- 按值保存本帧的 `InfiniteGridPassData`
- `GetName()` 固定返回 `"SceneViewportGrid"`
## 当前使用位置
- [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 被调用的路径
## 设计含义
`BuiltinInfiniteGridPass` 再包一层 Editor 侧 `RenderPass`,收益在于:
- `SceneViewportRenderPlan` 可以只依赖抽象的 pass factory而不用直接耦合具体 renderer 成员
- 网格 pass 可以作为 Scene View 的普通 `postScenePass` 插到同一条计划链路里
- 网格算法的实现仍然统一留在 Rendering 模块
## 当前限制
- 这个头文件本身只提供薄适配层,不暴露任何额外的 editor-specific 网格样式配置
- 返回的 `RenderPass` 不拥有 `renderer`,调用方必须保证 renderer 在 pass 执行期间仍然有效
## 相关文档
- [Passes](../Passes.md)
- [Render](Render.md)
- [Shutdown](Shutdown.md)
- [CreateSceneViewportGridPass](CreateSceneViewportGridPass.md)
- [SceneViewportRenderPlan](../../SceneViewportRenderPlan/SceneViewportRenderPlan.md)
- [BuiltinInfiniteGridPass](../../../../Rendering/Passes/BuiltinInfiniteGridPass/BuiltinInfiniteGridPass.md)

View File

@@ -0,0 +1,39 @@
# SceneViewportGridPassRenderer::Shutdown
**命名空间**: `XCEngine::Editor`
**类型**: `method`
**源文件**: `editor/src/Viewport/Passes/SceneViewportGridPass.h`
## 签名
```cpp
void Shutdown();
```
## 作用
释放 `SceneViewportGridPassRenderer` 内部持有的底层无限网格 pass 资源。
## 当前实现行为
当前实现只有一行:
```cpp
m_gridPass.Shutdown();
```
也就是说,`SceneViewportGridPassRenderer` 自己并不管理额外的 Editor 私有资源;它只是把关闭动作透传给底层 `BuiltinInfiniteGridPass`
## 使用时机
- [ViewportHostService](../../ViewportHostService/ViewportHostService.md) 在自身 `Shutdown()` 中调用它
- 不需要每帧调用;它属于 renderer 生命周期收尾的一部分
## 相关文档
- [SceneViewportGridPass](SceneViewportGridPass.md)
- [Render](Render.md)
- [CreateSceneViewportGridPass](CreateSceneViewportGridPass.md)
- [BuiltinInfiniteGridPass](../../../../Rendering/Passes/BuiltinInfiniteGridPass/BuiltinInfiniteGridPass.md)

View File

@@ -0,0 +1,55 @@
# CreateSceneViewportSelectionOutlinePass
**命名空间**: `XCEngine::Editor`
**类型**: `factory-function`
**源文件**: `editor/src/Viewport/Passes/SceneViewportSelectionOutlinePass.h`
## 签名
```cpp
std::unique_ptr<Rendering::RenderPass> CreateSceneViewportSelectionOutlinePass(
SceneViewportSelectionOutlinePassRenderer& renderer,
RHI::RHIResourceView* objectIdTextureView,
const std::vector<uint64_t>& selectedObjectIds,
const Rendering::Passes::ObjectIdOutlineStyle& style);
```
## 作用
创建一个本帧使用的 Scene View 选中轮廓 `RenderPass`,把 object-id 纹理、选中对象列表和样式绑定到给定 renderer。
## 当前实现行为
当前工厂函数返回内部类 `SceneViewportSelectionOutlinePass` 的实例。这个 pass
- 持有对 `renderer` 的引用
- 保存 `objectIdTextureView` 指针
- 按值复制 `selectedObjectIds`
- 按值复制 `style`
- `GetName()` 固定返回 `"SceneViewportSelectionOutline"`
- `Execute(...)` 时调用 `renderer.Render(...)`
## 所有权与生命周期
- 返回值拥有 pass 对象本身
- `renderer` 不被 pass 拥有,必须在 pass 执行期间保持有效
- `objectIdTextureView` 只是借用指针,不会被 pass 接管所有权
- `selectedObjectIds``style` 会复制进 pass 内部,因此可以跨过当前调用栈延后执行
## 当前使用位置
典型调用路径是:
1. [BuildSceneViewportRenderPlan](../../SceneViewportRenderPlan/BuildSceneViewportRenderPlan.md) 检查 `selectedObjectIds` 非空
2. 要求 `targets.objectIdShaderView` 可用,并用 `BuildSceneViewportSelectionOutlineStyle(...)` 生成样式
3. 通过这个工厂把结果加入 `plan.postScenePasses`
## 相关文档
- [SceneViewportSelectionOutlinePass](SceneViewportSelectionOutlinePass.md)
- [Render](Render.md)
- [Shutdown](Shutdown.md)
- [SceneViewportRenderPlan](../../SceneViewportRenderPlan/SceneViewportRenderPlan.md)
- [ObjectIdOutlineStyle](../../../../Rendering/Passes/ObjectIdOutlineStyle/ObjectIdOutlineStyle.md)

View File

@@ -0,0 +1,52 @@
# SceneViewportSelectionOutlinePassRenderer::Render
**命名空间**: `XCEngine::Editor`
**类型**: `method`
**源文件**: `editor/src/Viewport/Passes/SceneViewportSelectionOutlinePass.h`
## 签名
```cpp
bool Render(
const Rendering::RenderContext& renderContext,
const Rendering::RenderSurface& surface,
RHI::RHIResourceView* objectIdTextureView,
const std::vector<uint64_t>& selectedObjectIds,
const Rendering::Passes::ObjectIdOutlineStyle& style);
```
## 作用
执行 Scene View 的选中轮廓绘制,把 object-id 纹理、选中对象列表和轮廓样式转交给底层 outline pass。
## 当前实现行为
当前实现没有额外包装逻辑,直接调用:
```cpp
return m_outlinePass.Render(
renderContext,
surface,
objectIdTextureView,
selectedObjectIds,
style);
```
因此:
- Editor 层不会在这里重新编码 object-id 或调整 outline 样式
- 资源初始化、shader 选择、绘制与失败条件都由 [BuiltinObjectIdOutlinePass](../../../../Rendering/Passes/BuiltinObjectIdOutlinePass/BuiltinObjectIdOutlinePass.md) 决定
## 返回值语义
- 底层 outline pass 执行成功时返回 `true`
- 当 object-id 视图、上下文或后端条件不满足时,可能返回 `false`
## 相关文档
- [SceneViewportSelectionOutlinePass](SceneViewportSelectionOutlinePass.md)
- [Shutdown](Shutdown.md)
- [CreateSceneViewportSelectionOutlinePass](CreateSceneViewportSelectionOutlinePass.md)
- [BuiltinObjectIdOutlinePass](../../../../Rendering/Passes/BuiltinObjectIdOutlinePass/BuiltinObjectIdOutlinePass.md)

View File

@@ -0,0 +1,68 @@
# SceneViewportSelectionOutlinePass
**命名空间**: `XCEngine::Editor`
**类型**: `renderer class + pass factory`
**源文件**: `editor/src/Viewport/Passes/SceneViewportSelectionOutlinePass.h`
**描述**: Scene View 选中轮廓的 Editor 侧 `RenderPass` 适配层,把基于 object-id 的 outline 绘制接入 viewport 的 `postScenePasses`
## 概览
`SceneViewportSelectionOutlinePass.h` 同样不是轮廓算法本体,而是对 [BuiltinObjectIdOutlinePass](../../../../Rendering/Passes/BuiltinObjectIdOutlinePass/BuiltinObjectIdOutlinePass.md) 的 Editor 封装:
- `SceneViewportSelectionOutlinePassRenderer`
- `CreateSceneViewportSelectionOutlinePass(...)`
它让 [SceneViewportRenderPlan](../../SceneViewportRenderPlan/SceneViewportRenderPlan.md) 可以把:
- `objectIdTextureView`
- `selectedObjectIds`
- `ObjectIdOutlineStyle`
组装成一个标准 `RenderPass`,随后插到 Scene View 的主场景绘制之后执行。
## 当前实现行为
`SceneViewportSelectionOutlinePass.cpp` 的当前实现:
- renderer 内部只持有一个 `BuiltinObjectIdOutlinePass m_outlinePass`
- [Render](Render.md) 原样转发 `renderContext``surface``objectIdTextureView``selectedObjectIds``style`
- [Shutdown](Shutdown.md) 只调用 `m_outlinePass.Shutdown()`
- [CreateSceneViewportSelectionOutlinePass](CreateSceneViewportSelectionOutlinePass.md) 会创建内部 `SceneViewportSelectionOutlinePass`
- 持有对 `renderer` 的引用
- 保存 `objectIdTextureView` 指针
- 按值保存 `selectedObjectIds``style`
- `GetName()` 固定返回 `"SceneViewportSelectionOutline"`
## 当前使用位置
- [SceneViewportRenderPlan](../../SceneViewportRenderPlan/SceneViewportRenderPlan.md) 的 `SceneViewportSelectionOutlinePassFactory` 会在“有选中对象且 `objectIdShaderView` 可用”时创建这个 pass
- [ViewportHostService](../../ViewportHostService/ViewportHostService.md) 当前把该 factory 绑定到 `CreateSceneViewportSelectionOutlinePass(m_sceneViewportSelectionOutlineRenderer, ...)`
- `tests/editor/test_viewport_render_flow_utils.cpp` 覆盖了:
- 选中对象存在时 factory 被调用
- `outlineWidthPixels == 2.0f`
- object-id 纹理缺失时返回警告文案
## 设计含义
这样拆层的好处是:
- object-id 轮廓的真正 GPU 实现仍留在 Rendering 模块
- Editor 侧只负责把 Scene View 的 object-id 纹理和选中列表接到正确的 pass 序列
- `SceneViewportRenderPlan` 可以统一控制 grid、selection-outline 与 overlay 三条附加渲染链路
## 当前限制
- 返回的 pass 不拥有 `renderer`,也不拥有 `objectIdTextureView` 指向的资源
- 选中轮廓能否成功执行,仍取决于 `objectIdTextureView` 生命周期与底层 `BuiltinObjectIdOutlinePass` 的约束
## 相关文档
- [Passes](../Passes.md)
- [Render](Render.md)
- [Shutdown](Shutdown.md)
- [CreateSceneViewportSelectionOutlinePass](CreateSceneViewportSelectionOutlinePass.md)
- [SceneViewportRenderPlan](../../SceneViewportRenderPlan/SceneViewportRenderPlan.md)
- [BuiltinObjectIdOutlinePass](../../../../Rendering/Passes/BuiltinObjectIdOutlinePass/BuiltinObjectIdOutlinePass.md)
- [ObjectIdOutlineStyle](../../../../Rendering/Passes/ObjectIdOutlineStyle/ObjectIdOutlineStyle.md)

View File

@@ -0,0 +1,39 @@
# SceneViewportSelectionOutlinePassRenderer::Shutdown
**命名空间**: `XCEngine::Editor`
**类型**: `method`
**源文件**: `editor/src/Viewport/Passes/SceneViewportSelectionOutlinePass.h`
## 签名
```cpp
void Shutdown();
```
## 作用
释放 `SceneViewportSelectionOutlinePassRenderer` 内部持有的底层 outline pass 资源。
## 当前实现行为
当前实现只有一行:
```cpp
m_outlinePass.Shutdown();
```
这说明 `SceneViewportSelectionOutlinePassRenderer` 自己并不维护额外的 editor-only GPU 状态;生命周期管理完全委托给 `BuiltinObjectIdOutlinePass`
## 使用时机
- [ViewportHostService](../../ViewportHostService/ViewportHostService.md) 在整体 shutdown 路径中调用它
- 不需要每帧调用;它属于 Scene View renderer 的长期资源回收步骤
## 相关文档
- [SceneViewportSelectionOutlinePass](SceneViewportSelectionOutlinePass.md)
- [Render](Render.md)
- [CreateSceneViewportSelectionOutlinePass](CreateSceneViewportSelectionOutlinePass.md)
- [BuiltinObjectIdOutlinePass](../../../../Rendering/Passes/BuiltinObjectIdOutlinePass/BuiltinObjectIdOutlinePass.md)

View File

@@ -0,0 +1,31 @@
# Detail::BuildSceneViewportShaderPath
把 Scene View shader 相对路径拼成 repo 内绝对资源路径字符串。
```cpp
inline Containers::String BuildSceneViewportShaderPath(const std::filesystem::path& relativePath);
```
## 行为说明
当前实现会拼接:
```text
{repo root}/editor/resources/shaders/scene-viewport/{relativePath}
```
然后再调用 [NormalizeSceneViewportShaderPath](NormalizeSceneViewportShaderPath.md) 输出规范化结果。
## 参数
- `relativePath` - `scene-viewport` 目录下的相对 shader 路径。
## 返回值
- `Containers::String` - 规范化后的完整资源路径。
## 相关文档
- [SceneViewportShaderPaths](SceneViewportShaderPaths.md)
- [GetSceneViewportShaderRepoRootPath](GetSceneViewportShaderRepoRootPath.md)
- [NormalizeSceneViewportShaderPath](NormalizeSceneViewportShaderPath.md)

View File

@@ -0,0 +1,31 @@
# GetSceneViewportInfiniteGridShaderPath
返回 Scene View 无限网格 shader 的资源路径。
```cpp
inline Containers::String GetSceneViewportInfiniteGridShaderPath();
```
## 行为说明
当前实现把相对路径:
```text
infinite-grid/infinite-grid.shader
```
交给 [BuildSceneViewportShaderPath](BuildSceneViewportShaderPath.md),最终得到 repo 内 `editor/resources/shaders/scene-viewport/infinite-grid/infinite-grid.shader` 的规范化字符串路径。
## 当前使用位置
- `SceneViewportGridPassRenderer` 构造时把这个路径交给 Runtime 侧 `BuiltinInfiniteGridPass`
## 返回值
- `Containers::String` - 无限网格 shader 路径。
## 相关文档
- [SceneViewportShaderPaths](SceneViewportShaderPaths.md)
- [BuildSceneViewportShaderPath](BuildSceneViewportShaderPath.md)
- [SceneViewportGridPass](../Passes/SceneViewportGridPass/SceneViewportGridPass.md)

View File

@@ -0,0 +1,31 @@
# GetSceneViewportObjectIdOutlineShaderPath
返回 Scene View object-id outline shader 的资源路径。
```cpp
inline Containers::String GetSceneViewportObjectIdOutlineShaderPath();
```
## 行为说明
当前实现把相对路径:
```text
object-id-outline/object-id-outline.shader
```
交给 [BuildSceneViewportShaderPath](BuildSceneViewportShaderPath.md),最终得到 repo 内 `editor/resources/shaders/scene-viewport/object-id-outline/object-id-outline.shader` 的规范化字符串路径。
## 当前使用位置
- `SceneViewportSelectionOutlinePassRenderer` 构造时把这个路径交给 Runtime 侧 `BuiltinObjectIdOutlinePass`
## 返回值
- `Containers::String` - object-id outline shader 路径。
## 相关文档
- [SceneViewportShaderPaths](SceneViewportShaderPaths.md)
- [BuildSceneViewportShaderPath](BuildSceneViewportShaderPath.md)
- [SceneViewportSelectionOutlinePass](../Passes/SceneViewportSelectionOutlinePass/SceneViewportSelectionOutlinePass.md)

View File

@@ -0,0 +1,27 @@
# Detail::GetSceneViewportShaderRepoRootPath
返回当前 Scene View shader 路径拼接所使用的 repo root。
```cpp
inline std::filesystem::path GetSceneViewportShaderRepoRootPath();
```
## 行为说明
当前实现有两条路径:
- 如果定义了 `XCENGINE_EDITOR_REPO_ROOT`
- 直接把这个编译时宏转成 `std::filesystem::path`
- 否则
- 以当前头文件 `__FILE__` 为起点,连续 `parent_path()` 三次回退到 repo root
这让编辑器既可以在已知 repo root 的构建环境下直接使用固定路径,也可以在本地源码树里按相对位置回推。
## 返回值
- `std::filesystem::path` - 当前推导出的 repo root。
## 相关文档
- [SceneViewportShaderPaths](SceneViewportShaderPaths.md)
- [BuildSceneViewportShaderPath](BuildSceneViewportShaderPath.md)

View File

@@ -0,0 +1,34 @@
# Detail::NormalizeSceneViewportShaderPath
`std::filesystem::path` 规范化并转成 `Containers::String`
```cpp
inline Containers::String NormalizeSceneViewportShaderPath(const std::filesystem::path& path);
```
## 行为说明
当前实现等价于:
```cpp
return Containers::String(path.lexically_normal().generic_string().c_str());
```
这意味着:
- 会先做 `lexically_normal()`
- 输出统一使用 `/` 分隔的 generic path
- 返回类型是 Editor / Rendering 侧常用的 `Containers::String`
## 参数
- `path` - 待规范化的文件系统路径。
## 返回值
- `Containers::String` - 规范化后的字符串路径。
## 相关文档
- [SceneViewportShaderPaths](SceneViewportShaderPaths.md)
- [BuildSceneViewportShaderPath](BuildSceneViewportShaderPath.md)

View File

@@ -0,0 +1,55 @@
# SceneViewportShaderPaths
**命名空间**: `XCEngine::Editor`
**类型**: `inline helper header`
**源文件**: `editor/src/Viewport/SceneViewportShaderPaths.h`
**描述**: 为 Scene View 的 editor-owned GPU pass 生成 repo 内 shader 资源路径。
## 概览
`SceneViewportShaderPaths.h` 是一个纯 inline helper 头文件。它不负责加载 shader也不触碰 `AssetDatabase`;当前职责只是把 repo 根目录和 Scene View shader 相对路径拼成稳定的 `Containers::String`
这组 helper 当前服务于两条 editor-owned pass 路径:
- [SceneViewportGridPass](../Passes/SceneViewportGridPass/SceneViewportGridPass.md)
- [SceneViewportSelectionOutlinePass](../Passes/SceneViewportSelectionOutlinePass/SceneViewportSelectionOutlinePass.md)
## 当前实现行为
- [GetSceneViewportShaderRepoRootPath](GetSceneViewportShaderRepoRootPath.md)
- 优先使用编译宏 `XCENGINE_EDITOR_REPO_ROOT`
- 否则回退到基于 `__FILE__` 的相对路径推导
- [BuildSceneViewportShaderPath](BuildSceneViewportShaderPath.md)
- 会把 repo root、`editor/resources/shaders/scene-viewport/` 和传入相对路径拼接起来
- [NormalizeSceneViewportShaderPath](NormalizeSceneViewportShaderPath.md)
-`std::filesystem::path` 规范化成 `Containers::String`
- [GetSceneViewportInfiniteGridShaderPath](GetSceneViewportInfiniteGridShaderPath.md)
- 返回无限网格 shader 路径
- [GetSceneViewportObjectIdOutlineShaderPath](GetSceneViewportObjectIdOutlineShaderPath.md)
- 返回 object-id outline shader 路径
## 当前使用位置
- `editor/src/Viewport/Passes/SceneViewportGridPass.cpp`
- `SceneViewportGridPassRenderer` 构造时调用 `GetSceneViewportInfiniteGridShaderPath()`
- `editor/src/Viewport/Passes/SceneViewportSelectionOutlinePass.cpp`
- `SceneViewportSelectionOutlinePassRenderer` 构造时调用 `GetSceneViewportObjectIdOutlineShaderPath()`
## 当前限制
- 这里只负责拼路径,不验证目标文件是否存在
- 路径策略当前写死在 repo 内 `editor/resources/shaders/scene-viewport/`
- Detail 命名空间下的 helper 也是 header 内直接暴露的 inline 实现,不是独立编译单元
## 相关文档
- [NormalizeSceneViewportShaderPath](NormalizeSceneViewportShaderPath.md)
- [GetSceneViewportShaderRepoRootPath](GetSceneViewportShaderRepoRootPath.md)
- [BuildSceneViewportShaderPath](BuildSceneViewportShaderPath.md)
- [GetSceneViewportInfiniteGridShaderPath](GetSceneViewportInfiniteGridShaderPath.md)
- [GetSceneViewportObjectIdOutlineShaderPath](GetSceneViewportObjectIdOutlineShaderPath.md)
- [SceneViewportGridPass](../Passes/SceneViewportGridPass/SceneViewportGridPass.md)
- [SceneViewportSelectionOutlinePass](../Passes/SceneViewportSelectionOutlinePass/SceneViewportSelectionOutlinePass.md)

View File

@@ -0,0 +1,83 @@
# Viewport
**命名空间**: `XCEngine::Editor`
**类型**: `module`
**源目录**: `editor/src/Viewport/`
**描述**: 编辑器视口基础设施模块,负责 Scene / Game 视口请求、隐藏编辑器相机、对象选择、overlay 构建与 gizmo 交互底层。
## 概述
`Viewport` 是当前 Editor 里最接近“场景视图内核”的一层。`SceneViewPanel``GameViewPanel` 都不直接管理渲染目标、场景相机请求或对象 ID 读回,而是通过这层完成:
- 视口纹理请求与尺寸管理。
- Scene View 专用编辑器相机控制。
- Scene View 的对象 ID picking。
- 场景图标、相机视锥、方向光辅助线等 overlay 数据构建。
- Move / Rotate / Scale gizmo 的命中、拖拽和绘制数据生成。
- Scene View GPU pass 注入。
从设计上看这层相当于“Editor 视口宿主服务 + 交互 helper”的组合而不是单一类。
## 设计要点
- `SceneViewPanel` 只负责 UI、快捷键和交互编排真正的视口资源管理放在 [ViewportHostService](ViewportHostService/ViewportHostService.md)。
- Scene View 不直接复用场景内相机,而是维护一台隐藏的编辑器相机,这和 Unity Scene View 的思路一致,能把编辑视角与游戏相机解耦。
- 当前 Scene View 的可视化链路已经拆成三段:
- editor-owned post-scene pass: [SceneViewportGridPass](Passes/SceneViewportGridPass/SceneViewportGridPass.md) 与 [SceneViewportSelectionOutlinePass](Passes/SceneViewportSelectionOutlinePass/SceneViewportSelectionOutlinePass.md)
- GPU 世界 overlay pass: [SceneViewportEditorOverlayPass](Passes/SceneViewportEditorOverlayPass/SceneViewportEditorOverlayPass.md)
- ImGui 前端 HUD / 交互 overlay: [SceneViewportOverlayRenderer](SceneViewportOverlayRenderer/SceneViewportOverlayRenderer.md)
- 宿主服务内部还把 Scene View overlay 再拆成:
- 可缓存的基础 editor overlay
- hit test 用的 interaction overlay
- 渲染阶段追加的 transient gizmo overlay
- gizmo 的“可视几何构建”和“鼠标命中”当前已经拆成 [SceneViewportOverlayHandleBuilder](SceneViewportOverlayHandleBuilder/SceneViewportOverlayHandleBuilder.md) 与 [SceneViewportOverlayHitTester](SceneViewportOverlayHitTester/SceneViewportOverlayHitTester.md) 两层。
- 当前 `SceneViewPanel` 的点击选取主路径是对象 ID 读回,不是 CPU mesh 射线拾取;后者目前保留在 [SceneViewportPicker](SceneViewportPicker/SceneViewportPicker.md) 里作为独立 helper。
## 当前实现边界
- `Viewport``editor/src` 下的 Editor 私有模块,不是 `engine/include/XCEngine/**` 那种 Runtime 公共 API。
- 当前 Scene View 的 GPU pass 只在 `D3D12` 后端上真正可渲染。
- `SceneViewportCameraController` 具备 orbit 输入能力,但当前 `SceneViewPanel` 主要驱动的是 look / pan / fly / focus selection。
## 目录结构
| 页面 | 说明 |
|------|------|
| [IViewportHostService](IViewportHostService/IViewportHostService.md) | Scene / Game 视口宿主服务抽象,以及共享输入/输出数据结构。 |
| [SceneViewportCameraController](SceneViewportCameraController/SceneViewportCameraController.md) | 隐藏编辑器相机的轨道/飞行控制器。 |
| [SceneViewportEditorOverlayData](SceneViewportEditorOverlayData/SceneViewportEditorOverlayData.md) | 世界 overlay 基元与帧缓存数据。 |
| [SceneViewportMath](SceneViewportMath/SceneViewportMath.md) | 视口投影、拖拽平面、屏幕方向等数学 helper。 |
| [SceneViewportMoveGizmo](SceneViewportMoveGizmo/SceneViewportMoveGizmo.md) | 位移 gizmo。 |
| [SceneViewportOrientationGizmo](SceneViewportOrientationGizmo/SceneViewportOrientationGizmo.md) | 右上角朝向立方体与点击对齐 helper。 |
| [SceneViewportOverlayHandleBuilder](SceneViewportOverlayHandleBuilder/SceneViewportOverlayHandleBuilder.md) | 把 gizmo draw data 转成屏幕三角形和 handle 记录。 |
| [SceneViewportOverlayHitTester](SceneViewportOverlayHitTester/SceneViewportOverlayHitTester.md) | 基于 handle 记录做鼠标命中选择。 |
| [SceneViewportOverlayBuilder](SceneViewportOverlayBuilder/SceneViewportOverlayBuilder.md) | 构建 Scene View 世界 overlay 帧数据。 |
| [SceneViewportOverlayRenderer](SceneViewportOverlayRenderer/SceneViewportOverlayRenderer.md) | 在 ImGui draw list 上绘制 gizmo 与前端 overlay。 |
| [SceneViewportRenderPlan](SceneViewportRenderPlan/SceneViewportRenderPlan.md) | Scene View 渲染前的 post-scene passes、overlay pass 与 clear-color override 计划对象。 |
| [SceneViewportShaderPaths](SceneViewportShaderPaths/SceneViewportShaderPaths.md) | Scene View 专用 shader 资源路径 helper。 |
| [SceneViewportPicker](SceneViewportPicker/SceneViewportPicker.md) | CPU 射线拾取 helper。 |
| [SceneViewportRotateGizmo](SceneViewportRotateGizmo/SceneViewportRotateGizmo.md) | 旋转 gizmo。 |
| [SceneViewportScaleGizmo](SceneViewportScaleGizmo/SceneViewportScaleGizmo.md) | 缩放 gizmo。 |
| [SceneViewportTransformGizmoFrameBuilder](SceneViewportTransformGizmoFrameBuilder/SceneViewportTransformGizmoFrameBuilder.md) | 组装每帧 transform gizmo 选择状态、pivot 和三类 gizmo context。 |
| [ViewportHostRenderFlowUtils](ViewportHostRenderFlowUtils/ViewportHostRenderFlowUtils.md) | Scene / Game 视口渲染流程辅助函数。 |
| [ViewportHostRenderTargets](ViewportHostRenderTargets/ViewportHostRenderTargets.md) | 视口颜色 / 深度 / object-id 目标创建与销毁。 |
| [ViewportHostService](ViewportHostService/ViewportHostService.md) | `IViewportHostService` 的当前实现。 |
| [ViewportHostSurfaceUtils](ViewportHostSurfaceUtils/ViewportHostSurfaceUtils.md) | render surface、重用判断和像素坐标工具。 |
| [ViewportObjectIdPicker](ViewportObjectIdPicker/ViewportObjectIdPicker.md) | object-id 读回与颜色解码 helper。 |
| [Passes](Passes/Passes.md) | Scene View editor-owned post-scene / overlay pass 子目录。 |
## 与上层面板的关系
- [SceneViewPanel](../panels/SceneViewPanel/SceneViewPanel.md) 是当前 `Viewport` 模块最主要的调用方。
- `SceneViewPanel` 通过 [ViewportPanelContent](../panels/ViewportPanelContent/ViewportPanelContent.md) 统一请求纹理并建立交互表面。
- `GameViewPanel` 也会复用 `IViewportHostService::RequestViewport(...)` 这条链路,但不会进入 Scene gizmo / picking 流程。
## 相关文档
- [Editor](../Editor.md)
- [SceneViewPanel](../panels/SceneViewPanel/SceneViewPanel.md)
- [SceneView Interaction And Gizmo Model](../../../_guides/Editor/SceneView-Interaction-And-Gizmo-Model.md)
- [ViewportPanelContent](../panels/ViewportPanelContent/ViewportPanelContent.md)