docs: sync camera renderer docs

This commit is contained in:
2026-04-03 14:25:49 +08:00
parent 608e0bc9d8
commit b882610bbc
3 changed files with 111 additions and 119 deletions

View File

@@ -6,80 +6,90 @@
**头文件**: `XCEngine/Rendering/CameraRenderer.h`
**描述**: 面向单个 `CameraRenderRequest`渲染执行器,负责场景提取、主管线提交、object-id 输出 builtin post-process 串接。
**描述**: 单个 `CameraRenderRequest` 的执行器。它负责在一次相机提交里完成场景提取、主管线渲染、object-id 输出,以及 builtin post-process / overlay pass 的串接。
## 概览
`CameraRenderer` 是当前渲染模块里的“单相机执行层”。它不负责从场景里挑哪些相机,也不负责对多个请求排序;这些工作由 [SceneRenderer](../SceneRenderer/SceneRenderer.md) 处理。它关心的是如何把一份 [CameraRenderRequest](../CameraRenderRequest/CameraRenderRequest.md) 真正跑完
`CameraRenderer` 是当前渲染模块里的“单请求执行层”。 [SceneRenderer](../SceneRenderer/SceneRenderer.md) 的分工是
1. 校验请求和 render area
2.`RenderSceneExtractor` 提取该相机视角下的 `RenderSceneData`
3. 执行主 `RenderPipeline`
4. 按需执行 `ObjectIdPass`
5. 执行调用方注入的 pre / post / overlay pass。
6. 构建并执行 builtin post-process 序列。
- `SceneRenderer` 负责规划和排序 `CameraRenderRequest`
- `CameraRenderer` 负责把一份 request 真正跑完
因此它已经不只是“单纯把场景交给 pipeline”而是当前 camera submission 的主要编排器
因此这里关心的不是“该渲染哪些相机”,而是“这一个相机请求如何被执行”
## 持有的运行时对象
## 当前持有的运行时对象
- `m_sceneExtractor`:负责按相机和 render area 抽取可见物体。
- `m_pipelineAsset`:可选,表示当前管线来自哪份资产工厂
- `m_pipeline`:当前实际执行主场景绘制的管线实例。
- `m_objectIdPass`:主场景之后的 object-id 输出 pass默认是 `Passes::BuiltinObjectIdPass`
- `m_builtinPostProcessBuilder`把无限网格、selection outline、debug mask 组装成 `RenderPassSequence`
## 生命周期与所有权
- 默认构造会回退到内建前向管线资产,并默认创建 builtin object-id pass。
- 手动注入 `RenderPipeline` 时,`CameraRenderer` 通过 `std::unique_ptr` 接管所有权
- 通过 [SetPipelineAsset](SetPipelineAsset.md) 走的是“资产创建实例”路径;通过 [SetPipeline](SetPipeline.md) 走的是“手动注入实例”路径。
- 析构时会依次 `Shutdown()` 当前管线、当前 object-id pass以及 builtin post-process builder。
- `m_sceneExtractor`
使用 `request.surface` 的 render-area 尺寸调用 `ExtractForCamera(...)`,生成这次提交要用的 `RenderSceneData`
- `m_pipelineAsset`
当前主管线的来源工厂;可能为空
- `m_pipeline`
当前实际执行主场景绘制的 runtime [RenderPipeline](../RenderPipeline/RenderPipeline.md)。
- `m_objectIdPass`
主场景之后的 object-id pass默认是 [Passes::BuiltinObjectIdPass](../Passes/BuiltinObjectIdPass/BuiltinObjectIdPass.md)。
- `m_builtinPostProcessBuilder`
把 builtin grid、selection outline、debug mask 请求翻译成临时 `RenderPassSequence`
## 当前执行顺序
对一份有效请求,`Render()` 的顺序是:
对一份有效 request当前 `Render()`顺序是:
1. `preScenePasses`
2. `m_pipeline->Render(...)`
3. `m_objectIdPass->Render(...)`,如果请求了 object-id 输出
4. `postScenePasses`
5. builtin post-process 序列
6. `overlayPasses`
1. 校验 request、自身主管线、render-area、object-id 请求和 builtin post-process 前置条件。
2. `m_sceneExtractor.ExtractForCamera(...)` 生成 `RenderSceneData`
3. 用 request 覆盖 `sceneData.cameraData.clearFlags`,必要时再覆盖 `clearColor`
4. 执行 `preScenePasses`
5. 执行 `m_pipeline->Render(...)`
6. 如请求了 object-id执行 `m_objectIdPass->Render(...)`
7. 执行 `postScenePasses`
8. 如请求了 builtin post-process先由 builder 生成临时 sequence再执行它。
9. 执行 `overlayPasses`
10. 按已初始化的 sequence 逆向 `Shutdown()`
这条顺序 `tests/Rendering/unit/test_camera_scene_renderer.cpp` 里被明确验证过
这条顺序 `tests/Rendering/unit/test_camera_scene_renderer.cpp` 明确覆盖
## 生命周期与回退策略
- 默认构造会使用静态共享的 [BuiltinForwardPipelineAsset](../Pipelines/BuiltinForwardPipelineAsset/BuiltinForwardPipelineAsset.md)。
- `SetPipeline()` 走“手动注入 runtime pipeline”路径并清空当前 `m_pipelineAsset`
- `SetPipelineAsset()` 走“由 asset 创建 runtime pipeline”路径传空时会回退到默认 asset。
- `ResetPipeline()` 会先 `Shutdown()` 旧主管线,再接管新实例;若新实例为空,则再次回退到默认 asset 并创建 builtin forward。
- `SetObjectIdPass()` 同样会先关闭旧 pass传空时回退到 builtin object-id pass。
## 当前验证规则
`Render()` 目前会显式拒绝:
- `request.IsValid()` 为假。
- 当前 `m_pipeline == nullptr`
- `request.surface` 的 render-area 宽或高为 `0`
- 请求了 object-id`request.objectId.IsValid()` 为假。
- 请求了 builtin post-process且提供了 `objectIdTextureView`,但这次 request 并没有真正请求 fresh object-id 输出。
## 当前实现边界
-处理单个相机请求,多相机排序和 camera stack 语义在更上层完成。
- 主场景提取尺寸取自 `surface` 的 render area而不是整张 surface 的宽高
- builtin post-process 当前依赖 object-id SRV、scene viewport grid 数据和 `Passes` 子模块,不是通用 render graph。
- 没有内部锁;替换管线、替换 object-id pass 和执行渲染都假定由拥有明确时序的线程调用。
-执行单个 request多相机排序、stack 顺序和 clear 规则在 `SceneRenderer` / `SceneRenderRequestPlanner` 层完成。
- 不直接决定“默认主管线是什么”,而是通过 pipeline asset seam 解决
- builtin post-process 仍然是顺序执行的 pass sequence,不是 render graph。
## 公开方法
| 方法 | 说明 |
|------|------|
| [Constructor](Constructor.md) | 创建渲染器,并建立默认或注入的主管线 / object-id pass。 |
| [Destructor](Destructor.md) | 关闭当前管线、object-id pass 和 builtin post-process builder。 |
| [SetPipeline](SetPipeline.md) | 手动替换当前主管线实例,并清空当前 pipeline asset 来源。 |
| [SetPipelineAsset](SetPipelineAsset.md) | 通过 `RenderPipelineAsset` 重建主管线实例。 |
| [Constructor](Constructor.md) | 构造 `CameraRenderer`,并建立默认或注入的主管线 / object-id pass。 |
| [Destructor](Destructor.md) | 关闭当前管线、object-id pass 和 builtin post-process builder。 |
| [SetPipeline](SetPipeline.md) | 手动替换当前 runtime pipeline。 |
| [SetPipelineAsset](SetPipelineAsset.md) | 通过 `RenderPipelineAsset` 重建当前 runtime pipeline。 |
| [SetObjectIdPass](SetObjectIdPass.md) | 替换当前 object-id pass。 |
| [GetPipeline](GetPipeline.md) | 读取当前主管线指针。 |
| [GetPipelineAsset](GetPipelineAsset.md) | 读取当前 pipeline asset 指针。 |
| [GetObjectIdPass](GetObjectIdPass.md) | 读取当前 object-id pass 指针。 |
| [Render](Render.md) | 执行一次完整的单相机渲染提交流程。 |
## 真实使用位置
- `SceneRenderer::Render(...)` 会把排序后的 `CameraRenderRequest` 逐个交给它。
- 编辑器 scene viewport 通过 `CameraRenderRequest.objectId``builtinPostProcess` 接到这里。
- `tests/Rendering/unit/test_camera_scene_renderer.cpp` 覆盖了 clear override、render area、注入 pass 顺序、pipeline asset 替换和 object-id 失败回退等关键行为。
| [GetPipeline](GetPipeline.md) | 读取当前主管线的非拥有指针。 |
| [GetPipelineAsset](GetPipelineAsset.md) | 读取当前 pipeline asset 的非拥有指针。 |
| [GetObjectIdPass](GetObjectIdPass.md) | 读取当前 object-id pass 的非拥有指针。 |
| [Render](Render.md) | 执行一次完整的单相机提交。 |
## 相关文档
- [CameraRenderRequest](../CameraRenderRequest/CameraRenderRequest.md)
- [Rendering](../Rendering.md)
- [SceneRenderer](../SceneRenderer/SceneRenderer.md)
- [CameraRenderRequest](../CameraRenderRequest/CameraRenderRequest.md)
- [RenderSceneExtractor](../RenderSceneExtractor/RenderSceneExtractor.md)
- [RenderPipeline](../RenderPipeline/RenderPipeline.md)
- [Passes](../Passes/Passes.md)
- [Scene Extraction And Builtin Forward Pipeline](../../../_guides/Rendering/Scene-Extraction-And-Builtin-Forward-Pipeline.md)

View File

@@ -1,13 +1,5 @@
# CameraRenderer::Constructor
**命名空间**: `XCEngine::Rendering`
**类型**: `constructor`
**头文件**: `XCEngine/Rendering/CameraRenderer.h`
## 签名
```cpp
CameraRenderer();
explicit CameraRenderer(std::unique_ptr<RenderPipeline> pipeline);
@@ -17,39 +9,42 @@ CameraRenderer(
std::unique_ptr<ObjectIdPass> objectIdPass);
```
## 作用
## 行为说明
创建一个能够执行单相机请求的 `CameraRenderer`,并为它准备主管线来源与 object-id pass。
构造函数的核心职责是决定两件事:
## 当前实现行为
- 当前主管线实例从哪里来。
- 当前 object-id pass 是否使用默认 builtin 实现。
## 当前构造路径
### 默认构造
- 通过内部静态 `CreateDefaultPipelineAsset()` 取得 `Pipelines::BuiltinForwardPipelineAsset`
- 再走 pipeline asset 构造路径创建默认主管线
- 同时默认创建 `Passes::BuiltinObjectIdPass`
- 调用内部静态 `CreateDefaultPipelineAsset()`
- 默认 asset 是共享的 [BuiltinForwardPipelineAsset](../Pipelines/BuiltinForwardPipelineAsset/BuiltinForwardPipelineAsset.md)
- 随后走 asset 构造路径生成主管线
### `std::unique_ptr<RenderPipeline>` 重载
- 接管调用方给出的主管线实例
- 如果 `objectIdPass` 没显式传入,则默认补一个 `Passes::BuiltinObjectIdPass`
- 交由 `(pipeline, objectIdPass)` 这个双参重载处理
- 如果未显式提供 object-id pass默认补一个 [Passes::BuiltinObjectIdPass](../Passes/BuiltinObjectIdPass/BuiltinObjectIdPass.md)
### `std::shared_ptr<const RenderPipelineAsset>` 重载
- 保存 asset 指针
- 通过 `SetPipelineAsset()` 立即 asset 创建一个新的主管线实例
- 同时默认创建 `Passes::BuiltinObjectIdPass`
- 保存 asset。
- 再调用 [SetPipelineAsset](SetPipelineAsset.md)立即 asset 创建 runtime pipeline
- 默认同时创建 builtin object-id pass。
### `(pipeline, objectIdPass)` 重载
- 同时接管主管线和 object-id pass。
- 如果传入的 `objectIdPass` 为空,会自动回退成 `Passes::BuiltinObjectIdPass`
- 如果传入 `pipeline` 为空,`ResetPipeline()`进一步回退到默认 pipeline asset 创建的内建前向管线。
- `objectIdPass` 为空,自动回退到 builtin object-id pass。
- 调用内部 `ResetPipeline(std::move(pipeline))`
- 如果传入 `pipeline` 为空,`ResetPipeline()`继续回退到默认 pipeline asset,并创建 builtin forward 主管线。
## 所有权
- `RenderPipeline` `ObjectIdPass` `CameraRenderer` 独占持有。
- `RenderPipelineAsset``shared_ptr` 形式共享持有,作为“如何创建管线实例”的来源。
- `RenderPipeline` `ObjectIdPass``CameraRenderer``std::unique_ptr` 独占持有。
- `RenderPipelineAsset``std::shared_ptr<const ...>` 共享持有,作为 runtime pipeline 的创建来源。
## 相关文档

View File

@@ -1,81 +1,68 @@
# CameraRenderer::Render
**命名空间**: `XCEngine::Rendering`
**类型**: `method`
**头文件**: `XCEngine/Rendering/CameraRenderer.h`
## 签名
```cpp
bool Render(const CameraRenderRequest& request);
```
## 作用
## 行为说明
执行一次完整的单相机渲染提交,包括主场景、object-id 输出、调用方注入 pass 和 builtin 后处理
执行一次完整的单相机提交。当前实现会把主场景、object-id注入 pass 和 builtin post-process 串成一条固定顺序的执行链
## 当前实现流程
## 当前流程
`engine/src/Rendering/CameraRenderer.cpp`,当前流程是:
1. 如果 `request.IsValid()`假,或 `m_pipeline == nullptr`,返回 `false`
2. 如果 `request.surface` 的 render area 宽高为 `0`,返回 `false`
3. 如果请求了 `objectId``objectId.IsValid()` 为假,返回 `false`
4. 如果 builtin post-process 里提供了 `objectIdTextureView`,但这次请求并没有真正请求 `objectId` 输出,返回 `false`
1. 校验 `request.IsValid()`,并确认 `m_pipeline` 非空。
2. 拒绝 render-area 宽高为 `0` 的 surface。
3. 如果请求了 object-id要求 `request.objectId.IsValid()`
4. 如果 builtin post-process 依赖 `objectIdTextureView`,则要求本次 request 真的请求了 fresh object-id 输出
5.`request.surface.GetRenderAreaWidth()` / `GetRenderAreaHeight()` 调用 `m_sceneExtractor.ExtractForCamera(...)`
6. 如果提取结果 `sceneData.HasCamera()` 为假,返回 `false`
7.`request.clearFlags` 覆盖 `sceneData.cameraData.clearFlags`;如有需要,再用 `clearColorOverride` 覆盖 `sceneData.cameraData.clearColor`
8. 依次执行:
6. `sceneData.HasCamera()` 为假,返回 `false`
7. 用 request 覆盖 `sceneData.cameraData.clearFlags`;如果 request 提供了 clear-color override,则继续覆盖 `sceneData.cameraData.clearColor`
8. 依次初始化并执行:
- `preScenePasses`
- `m_pipeline->Render(...)`
- `m_objectIdPass->Render(...)`,如果请求了 object-id
- `m_pipeline->Render(...)`
- `m_objectIdPass->Render(...)`
- `postScenePasses`
- builtin post-process 序列
- builtin post-process 临时 sequence
- `overlayPasses`
9. 每个阶段失败时,按已经初始化pass 序列倒序 `Shutdown()` 并返回 `false`
9. 按已经成功初始化的 sequence 做逆向 `Shutdown()`
## builtin post-process 接入点
如果 `request.builtinPostProcess.IsRequested()` 为真`Render()` 会:
`request.builtinPostProcess.IsRequested()` 为真时,当前实现会:
1. 调用 `m_builtinPostProcessBuilder.Build(...)` 生成一临时 `RenderPassSequence`
2. 对这个序列执行 `Initialize(context)`
1. 调用 `m_builtinPostProcessBuilder.Build(...)` 生成一临时 `RenderPassSequence`
2. 对这条临时 sequence 调用 `Initialize(context)`
3.`postScenePasses` 之后、`overlayPasses` 之前执行它。
这意味着 scene viewport 的无限网格、selection outline 和 debug mask 都是主场景绘制完成之后叠加的。
这意味着 scene viewport 的 builtin grid、selection outline 和 debug mask 都是主场景之后叠加的。
## 失败与清理语义
- 任一验证失败会直接返回 `false`
- 任一 sequence 初始化失败会立即执行对应 `Shutdown()` 回滚。
- 主主管线、object-id pass、post-process 或 overlay 任一阶段失败,都会按已经初始化过的 sequence 做清理再返回 `false`
## 参数
| 参数 | 说明 |
|------|------|
| `request` | 本次单相机渲染的完整输入。 |
- `request` - 本次单相机渲染的完整输入。
## 返回值
- 返回 `true`:主流程和所有已请求的附加阶段都成功执行
- 返回 `false`:请求校验失败、场景提取失败、主管线失败,或任意一个附加 pass 阶段失败
## 关键语义
- 相机视口尺寸来自 `surface` 的 render area而不是整张 surface 的宽高。
- object-id pass 位于主场景之后、`postScenePasses` 之前。
- builtin post-process 位于 `postScenePasses` 之后、`overlayPasses` 之前。
- builder 负责决定 selection outline / debug mask 的具体回退策略,`CameraRenderer` 只负责执行 builder 给出的结果。
- 整条提交链成功执行时返回 `true`
- request 校验失败、场景提取失败、主管线失败,或任一附加阶段失败时返回 `false`
## 测试覆盖
`tests/Rendering/unit/test_camera_scene_renderer.cpp` 当前验证了:
- render area 会影响提取到的相机视口尺寸
- `clearFlags` clear color override 会写回 `sceneData.cameraData`
- pre / post / object-id pass 的执行顺序
- object-id pass 失败和 post-pass 初始化失败时的清理路径
- builtin post-process 在缺少 fresh object-id 数据时会被拒绝
- render-area 会影响提取到的相机 viewport 尺寸
- clear-flags clear-color override 会写回 `sceneData.cameraData`
- pre / pipeline / object-id / post / builtin / overlay 的执行顺序
- object-id 失败、post-pass 初始化失败和 builtin post-process 验证失败时的回滚路径
## 相关文档
- [CameraRenderer](CameraRenderer.md)
- [CameraRenderRequest](../CameraRenderRequest/CameraRenderRequest.md)
- [RenderSceneExtractor](../RenderSceneExtractor/RenderSceneExtractor.md)
- [RenderPipeline::Render](../RenderPipeline/Render.md)