diff --git a/docs/api/XCEngine/Rendering/ObjectIdEncoding/ObjectIdEncoding.md b/docs/api/XCEngine/Rendering/ObjectIdEncoding/ObjectIdEncoding.md new file mode 100644 index 00000000..9d28e44e --- /dev/null +++ b/docs/api/XCEngine/Rendering/ObjectIdEncoding/ObjectIdEncoding.md @@ -0,0 +1,57 @@ +# ObjectIdEncoding + +**命名空间**: `XCEngine::Rendering` + +**类型**: `utility header` + +**头文件**: `XCEngine/Rendering/ObjectIdEncoding.h` + +**描述**: 提供对象 ID 和颜色缓冲之间的轻量编解码 helper,供 object-id 渲染与拾取链路共享。 + +## 概览 + +`ObjectIdEncoding.h` 把“对象 ID 写进颜色缓冲,再从颜色缓冲读回来”的协议固定成了三段小函数。 + +当前这套协议主要服务于: + +- [BuiltinObjectIdPass](../Passes/BuiltinObjectIdPass/BuiltinObjectIdPass.md) 把对象 ID 编码到 object-id 纹理 +- [BuiltinObjectIdOutlinePass](../Passes/BuiltinObjectIdOutlinePass/BuiltinObjectIdOutlinePass.md) 生成选中轮廓时复用同样的颜色表示 +- editor viewport 的 object picker 从像素颜色反解回 `entityId` + +## 编码规则 + +### `EncodeObjectIdToUInt32()` + +把传入的 `uint64_t objectId` 截断成低 `32` 位。 + +### `EncodeObjectIdToColor()` + +把编码后的 `uint32` 拆成四个 `8-bit` 通道,并按 `0..255 -> 0..1` 归一化为 `Vector4`: + +- `r` 对应最低 8 位 +- `g` 对应第 8-15 位 +- `b` 对应第 16-23 位 +- `a` 对应第 24-31 位 + +### `DecodeObjectIdFromColor()` + +按同样的通道顺序把 `r/g/b/a` 重新拼回 `uint32_t`。 + +## 当前实现边界 + +- 高于 `32` 位的对象身份当前会被截断,无法通过 object-id 颜色缓冲完整保真。 +- 这里的 helper 只定义字节打包协议,不处理颜色空间、纹理格式选择或 GPU 读回流程。 +- `DecodeObjectIdFromColor()` 返回 `uint32_t`,调用方如果内部仍使用 `uint64_t`,需要自己做扩展或约定。 + +## 真实使用位置 + +- `engine/src/Rendering/Passes/BuiltinObjectIdPass.cpp` 用它把对象 ID 写进 shader 常量。 +- `engine/src/Rendering/Passes/BuiltinObjectIdOutlinePass.cpp` 用它构建选中对象颜色列表。 +- `editor/src/Viewport/ViewportObjectIdPicker.h` 用它把像素颜色解码成拾取结果。 + +## 相关文档 + +- [当前模块](../Rendering.md) +- [ObjectIdPass](../ObjectIdPass/ObjectIdPass.md) +- [BuiltinObjectIdPass](../Passes/BuiltinObjectIdPass/BuiltinObjectIdPass.md) +- [BuiltinObjectIdOutlinePass](../Passes/BuiltinObjectIdOutlinePass/BuiltinObjectIdOutlinePass.md) diff --git a/docs/api/XCEngine/Rendering/Pipelines/BuiltinForwardPipelineAsset/BuiltinForwardPipelineAsset.md b/docs/api/XCEngine/Rendering/Pipelines/BuiltinForwardPipelineAsset/BuiltinForwardPipelineAsset.md index 07bbf77d..2f4fd32b 100644 --- a/docs/api/XCEngine/Rendering/Pipelines/BuiltinForwardPipelineAsset/BuiltinForwardPipelineAsset.md +++ b/docs/api/XCEngine/Rendering/Pipelines/BuiltinForwardPipelineAsset/BuiltinForwardPipelineAsset.md @@ -10,16 +10,17 @@ ## 概览 -`BuiltinForwardPipelineAsset` 是当前渲染模块里唯一公开的 concrete pipeline asset。它的职责很简单: +`BuiltinForwardPipelineAsset` 是当前渲染模块里唯一公开的 concrete pipeline asset。 +它的职责很窄: - 作为默认主管线工厂存在 - 在需要时返回一条新的 `BuiltinForwardPipeline` 按 `engine/src/Rendering/CameraRenderer.cpp` 的当前接线: -- `CameraRenderer` 的默认构造路径会使用静态共享的 `BuiltinForwardPipelineAsset` -- `SetPipelineAsset()` 也会通过这类 asset 重建当前主管线实例 -- 如果外部传入空 asset,当前仍会回退到默认 `BuiltinForwardPipelineAsset` +- `CameraRenderer` 默认构造会使用静态共享的 `BuiltinForwardPipelineAsset` +- [SetPipelineAsset](../../CameraRenderer/SetPipelineAsset.md) 也可以显式切回这条 asset 路径 +- 如果外部把 asset 传空,回退到默认 `BuiltinForwardPipelineAsset` 的逻辑发生在 `CameraRenderer`,不是这个类内部 ## 生命周期与所有权 @@ -27,13 +28,11 @@ - 它创建出来的 pipeline 以 `std::unique_ptr` 返回 - runtime pipeline 的生命周期最终由 `CameraRenderer` 或调用方接管,而不是由 asset 自己保留 -这就是“共享工厂对象 + 独占运行时实例”的典型渲染系统分层。 - ## 当前实现边界 -- 当前没有任何可配置字段 -- 不能通过它选择不同 shader、不同 pass 序列或不同渲染路径 -- 它还不是项目资源数据库里的可序列化 renderer asset,只是 C++ 工厂对象 +- 当前没有任何可配置字段。 +- 不能通过它切换不同 shader、不同 pass 序列或不同渲染路径。 +- 它仍然不是项目资源数据库里的 renderer asset,只是一个 C++ 工厂对象。 ## 公开方法 diff --git a/docs/api/XCEngine/Rendering/Pipelines/BuiltinForwardPipelineAsset/CreatePipeline.md b/docs/api/XCEngine/Rendering/Pipelines/BuiltinForwardPipelineAsset/CreatePipeline.md index 0f2b0e9b..b4fff26e 100644 --- a/docs/api/XCEngine/Rendering/Pipelines/BuiltinForwardPipelineAsset/CreatePipeline.md +++ b/docs/api/XCEngine/Rendering/Pipelines/BuiltinForwardPipelineAsset/CreatePipeline.md @@ -24,17 +24,18 @@ std::make_unique() - 每次调用都会生成一条新的 `BuiltinForwardPipeline` - 当前不会复用已有 runtime pipeline -- 当前也不会返回 `nullptr` +- 当前这个方法本身不会做额外 fallback 分支 -## 当前调用位置 +## 与外层 fallback 的边界 `CameraRenderer` 通过内部 `CreatePipelineFromAsset()` 使用这个方法: -1. 若当前有 `pipelineAsset`,先执行 `asset->CreatePipeline()` -2. 若拿到有效实例,就接管这条新管线 -3. 若 asset 为空或返回空指针,再回退到直接 `std::make_unique()` +1. 先尝试 `asset->CreatePipeline()` +2. 如果拿到有效实例,就接管这条新管线 +3. 如果 asset 为空或返回空指针,再由 `CameraRenderer` 回退到直接 `std::make_unique()` -对 `BuiltinForwardPipelineAsset` 来说,第 3 步当前基本不会触发。 +对 `BuiltinForwardPipelineAsset` 来说,第 3 步是调用方策略,不是这里的方法体逻辑。 +按当前实现,这个方法自身也不会返回 `nullptr`。 ## 返回值 diff --git a/docs/api/XCEngine/Rendering/RenderCameraData/RenderCameraData.md b/docs/api/XCEngine/Rendering/RenderCameraData/RenderCameraData.md index cf6906ff..af025b37 100644 --- a/docs/api/XCEngine/Rendering/RenderCameraData/RenderCameraData.md +++ b/docs/api/XCEngine/Rendering/RenderCameraData/RenderCameraData.md @@ -6,20 +6,31 @@ **头文件**: `XCEngine/Rendering/RenderCameraData.h` -**描述**: 保存渲染阶段实际使用的相机矩阵、清屏色和视口尺寸。 +**描述**: 保存渲染阶段实际使用的相机矩阵、清屏参数和视口尺寸。 -## 概述 +## 概览 -`RenderCameraData` 是“场景组件层的相机”向“渲染层可直接消费的数据块”之间的桥接结构。 +`RenderCameraData` 是“组件层的相机”到“渲染层可直接消费的数据块”之间的桥接结构。 +当前主链路里: -这种拆分很有价值,因为渲染层通常不应该直接依赖完整 `CameraComponent` 行为,而是应该消费一份已经拍平的渲染数据: +- [RenderSceneUtility](../RenderSceneUtility/RenderSceneUtility.md) 的 `BuildRenderCameraData()` 负责先构建矩阵、世界位置和默认清屏色。 +- [RenderSceneExtractor](../RenderSceneExtractor/RenderSceneExtractor.md) 把它装进 `RenderSceneData`。 +- [CameraRenderer](../CameraRenderer/CameraRenderer.md) 会在真正提交前再按 request 覆盖 `clearFlags`,必要时覆盖 `clearColor`。 -- 视图矩阵 -- 投影矩阵 -- 组合矩阵 -- 相机世界位置 -- 清屏色 -- 视口尺寸 +因此它不是“纯相机组件快照”,而是一次渲染提交最终会消费的相机数据槽位。 + +## `RenderClearFlags` + +同一个头文件里还定义了当前使用的清屏位标志: + +| 枚举值 | 说明 | +|------|------| +| `None` | 不清任何内容。 | +| `Color` | 只清颜色。 | +| `Depth` | 只清深度。 | +| `All` | 同时清颜色和深度。 | + +当前还提供了按位 `|`、`&` 运算,以及 `HasRenderClearFlag(flags, flag)` helper,供 [BuiltinForwardPipeline](../Pipelines/BuiltinForwardPipeline/BuiltinForwardPipeline.md) 判断本次主场景是否需要清颜色/深度。 ## 字段 @@ -29,18 +40,22 @@ | `projection` | `Math::Matrix4x4` | 投影矩阵。 | | `viewProjection` | `Math::Matrix4x4` | `projection * view` 组合矩阵。 | | `worldPosition` | `Math::Vector3` | 相机世界坐标。 | -| `clearColor` | `Math::Color` | 默认清屏色。 | +| `clearColor` | `Math::Color` | 当前提交使用的清屏色。 | +| `clearFlags` | `RenderClearFlags` | 当前提交使用的清屏标志;默认值是 `All`。 | | `viewportWidth` | `uint32_t` | 当前视口宽度。 | | `viewportHeight` | `uint32_t` | 当前视口高度。 | ## 当前实现说明 -- 这组矩阵由 [RenderSceneExtractor](../RenderSceneExtractor/RenderSceneExtractor.md) 构造。 -- 当前 extractor 会在写入这里之前对 `view`、`projection` 和 `viewProjection` 做转置。 -- 这说明当前渲染路径是按“尽量让 shader 直接消费统一矩阵布局”的思路设计的。 +- `BuildRenderCameraData()` 当前会写入 `view`、`projection`、`viewProjection`、`worldPosition`、`clearColor` 和 viewport 尺寸。 +- 该函数不会根据 `CameraComponent::GetClearMode()` 推导 `clearFlags`;`RenderCameraData` 此时保留 struct 默认值 `RenderClearFlags::All`。 +- 真正的 per-request clear 语义在 `CameraRenderer::Render()` 里由 `request.clearFlags` 覆盖写回 `sceneData.cameraData.clearFlags`。 +- 当前 extractor 会在写入矩阵前对 `view`、`projection` 和 `viewProjection` 做转置,以适配现有 shader 常量布局。 ## 相关文档 -- [当前模块](../Rendering.md) +- [Rendering](../Rendering.md) +- [RenderSceneUtility](../RenderSceneUtility/RenderSceneUtility.md) - [RenderSceneExtractor](../RenderSceneExtractor/RenderSceneExtractor.md) -- [VisibleRenderObject](../VisibleRenderObject/VisibleRenderObject.md) +- [CameraRenderer](../CameraRenderer/CameraRenderer.md) +- [CameraRenderRequest](../CameraRenderRequest/CameraRenderRequest.md) diff --git a/docs/api/XCEngine/Rendering/RenderMaterialUtility/BuildBuiltinForwardMaterialData.md b/docs/api/XCEngine/Rendering/RenderMaterialUtility/BuildBuiltinForwardMaterialData.md new file mode 100644 index 00000000..4ef89c95 --- /dev/null +++ b/docs/api/XCEngine/Rendering/RenderMaterialUtility/BuildBuiltinForwardMaterialData.md @@ -0,0 +1,44 @@ +# BuildBuiltinForwardMaterialData + +**命名空间**: `XCEngine::Rendering` + +**类型**: `function` + +**头文件**: `XCEngine/Rendering/RenderMaterialUtility.h` + +## 签名 + +```cpp +BuiltinForwardMaterialData BuildBuiltinForwardMaterialData(const Resources::Material* material); +``` + +## 作用 + +把 builtin forward 当前真正消费的材质常量打包成 `BuiltinForwardMaterialData`。 + +## 当前实现行为 + +当前实现非常窄,只做一件事: + +1. 构造默认的 `BuiltinForwardMaterialData` +2. 用 [ResolveBuiltinBaseColorFactor](ResolveBuiltinBaseColorFactor.md) 填充 `baseColorFactor` +3. 返回结果 + +也就是说,当前 builtin forward 材质常量块里只公开收口了颜色因子,没有把纹理、采样器或其它材质属性打进这个 struct。 + +## 当前语义边界 + +- 这是 builtin forward 私有契约的一部分,不是通用材质序列化格式。 +- 贴图绑定不在这里返回;调用方仍需单独用 [ResolveBuiltinBaseColorTexture](ResolveBuiltinBaseColorTexture.md) 解析。 +- 如果未来 builtin forward 的 per-material 常量扩展,这个 helper 和 `BuiltinForwardMaterialData` 也会一起扩展。 + +## 测试覆盖 + +`tests/Rendering/unit/test_render_scene_extractor.cpp` 当前验证了它会按 canonical 名称和别名路径正确写入 `baseColorFactor`。 + +## 相关文档 + +- [ResolveBuiltinBaseColorFactor](ResolveBuiltinBaseColorFactor.md) +- [ResolveBuiltinBaseColorTexture](ResolveBuiltinBaseColorTexture.md) +- [BuiltinForwardPipeline](../Pipelines/BuiltinForwardPipeline/BuiltinForwardPipeline.md) +- [RenderMaterialUtility](RenderMaterialUtility.md) diff --git a/docs/api/XCEngine/Rendering/RenderMaterialUtility/RenderMaterialUtility.md b/docs/api/XCEngine/Rendering/RenderMaterialUtility/RenderMaterialUtility.md index 7ea728b5..638dee97 100644 --- a/docs/api/XCEngine/Rendering/RenderMaterialUtility/RenderMaterialUtility.md +++ b/docs/api/XCEngine/Rendering/RenderMaterialUtility/RenderMaterialUtility.md @@ -6,19 +6,20 @@ **头文件**: `XCEngine/Rendering/RenderMaterialUtility.h` -**描述**: 把 `Material` 的 pass 元数据、render queue 和 render state 解释成渲染提取与图形管线可直接使用的规则。 +**描述**: 把 `Material` 的 pass 元数据、builtin forward 材质契约、render queue 和 render state 解释成渲染提取与图形管线可直接使用的规则。 ## 概览 -`RenderMaterialUtility.h` 不是运行时对象,而是一组内联规则函数。它当前承担三类工作: +`RenderMaterialUtility.h` 不是运行时对象,而是一组内联规则函数。它当前承担四类工作: 1. 解析“这次绘制真正要用哪份材质”。 2. 判断该材质是否匹配某个 builtin pass。 -3. 把材质里的 `MaterialRenderState` 翻译成 `RHI::GraphicsPipelineDesc` 需要的状态结构。 +3. 解析 builtin forward 路径要消费的 base-color 因子与贴图。 +4. 把材质里的 `MaterialRenderState` 翻译成 `RHI::GraphicsPipelineDesc` 需要的状态结构。 -这组函数位于 [RenderSceneExtractor](../RenderSceneExtractor/RenderSceneExtractor.md)、builtin forward pipeline 和 object-id 相关 pass 之间,是当前材质语义进入渲染路径的关键翻译层。 +它位于 [RenderSceneExtractor](../RenderSceneExtractor/RenderSceneExtractor.md)、[BuiltinForwardPipeline](../Pipelines/BuiltinForwardPipeline/BuiltinForwardPipeline.md) 和 object-id 相关 pass 之间,是当前材质语义进入渲染链路的关键翻译层。 -## BuiltinMaterialPass +## `BuiltinMaterialPass` 当前公开的 builtin pass 枚举包括: @@ -26,8 +27,8 @@ |------|------| | `ForwardLit` | 默认前向绘制路径。 | | `Unlit` | 非受光绘制路径。 | -| `DepthOnly` | 深度预写 / depth-only 类通道。 | -| `ShadowCaster` | 阴影投射类通道。 | +| `DepthOnly` | 深度预写 / depth-only 通道。 | +| `ShadowCaster` | 阴影投射通道。 | | `ObjectId` | object-id 输出通道。 | | `Forward` | `ForwardLit` 的别名。 | @@ -39,7 +40,7 @@ 2. 如果材质没写显式 pass 元数据,再看材质引用 shader 里的 pass 名称和 `LightMode` tag。 3. 如果材质和 shader 都没写显式 builtin metadata,则把它隐式视为 `ForwardLit`。 -因此 `RenderMaterialUtility` 实际上把 [MaterialLoader](../../Resources/Material/MaterialLoader/MaterialLoader.md) 解析出来的: +因此这里实际把 [MaterialLoader](../../Resources/Material/MaterialLoader/MaterialLoader.md) 解析出的: - `shaderPass` - `tags.LightMode` @@ -48,6 +49,25 @@ 全部接进了渲染路径。 +## builtin forward 材质契约 + +同一个头文件里还公开了 `BuiltinForwardMaterialData`: + +| 字段 | 类型 | 说明 | +|------|------|------| +| `baseColorFactor` | `Math::Vector4` | builtin forward 当前消费的颜色因子。 | + +对应 helper 的当前职责是: + +- [ResolveBuiltinBaseColorFactor](ResolveBuiltinBaseColorFactor.md) + 解析 base color 因子,优先走 shader semantic,再回退到常见别名属性名,最后可只从 opacity/alpha 补 `w` 分量。 +- [ResolveBuiltinBaseColorTexture](ResolveBuiltinBaseColorTexture.md) + 解析 base color 贴图,优先走 shader semantic,再回退到 `_MainTex`、`baseColorTexture` 等常见别名。 +- [BuildBuiltinForwardMaterialData](BuildBuiltinForwardMaterialData.md) + 把当前 builtin forward 真正要消费的材质常量打包出来。 + +这组 helper 当前直接被 `BuiltinForwardPipeline` 用来填充 per-material 常量和纹理绑定。 + ## render state 映射 `BuildRasterizerState()`、`BuildBlendState()` 和 `BuildDepthStencilState()` 会把 `MaterialRenderState` 映射成 RHI 状态,再由 [ApplyMaterialRenderState](ApplyMaterialRenderState.md) 一次性写入 `GraphicsPipelineDesc`。 @@ -61,9 +81,10 @@ ## 当前实现边界 -- 它只处理 pass 归类、render queue 和固定渲染状态,不负责 shader variant、keyword 或多 pass 编排。 +- 它只处理 pass 归类、builtin forward 材质契约、render queue 和固定渲染状态,不负责 shader variant、keyword 或多 pass 编排。 - 没有显式元数据的材质会默认进入 `ForwardLit`,这是一种“先让基础路径可用”的保守回退。 -- `MatchesBuiltinPass(nullptr, pass)` 只有在 `pass == ForwardLit` 时才返回 `true`,而不是对所有 pass 都放行。 +- `MatchesBuiltinPass(nullptr, pass)` 只有在 `pass == ForwardLit` 时才返回 `true`。 +- `BuildBuiltinForwardMaterialData()` 当前只打包 `baseColorFactor`;贴图仍由调用方单独通过 [ResolveBuiltinBaseColorTexture](ResolveBuiltinBaseColorTexture.md) 解析。 ## 公开函数 @@ -73,6 +94,9 @@ | [ResolveMaterialRenderQueue](ResolveMaterialRenderQueue.md) | 读取材质 render queue,空材质时回退到 `Geometry`。 | | [IsTransparentRenderQueue](IsTransparentRenderQueue.md) | 判断 queue 是否处于透明区间。 | | [MatchesBuiltinPass](MatchesBuiltinPass.md) | 判断材质是否匹配某个 builtin pass。 | +| [ResolveBuiltinBaseColorFactor](ResolveBuiltinBaseColorFactor.md) | 解析 builtin forward 使用的 base color 因子。 | +| [ResolveBuiltinBaseColorTexture](ResolveBuiltinBaseColorTexture.md) | 解析 builtin forward 使用的 base color 贴图。 | +| [BuildBuiltinForwardMaterialData](BuildBuiltinForwardMaterialData.md) | 打包 builtin forward 当前消费的材质常量。 | | [BuildRasterizerState](BuildRasterizerState.md) | 构建栅格化状态。 | | [BuildBlendState](BuildBlendState.md) | 构建混合状态。 | | [BuildDepthStencilState](BuildDepthStencilState.md) | 构建深度状态。 | diff --git a/docs/api/XCEngine/Rendering/RenderMaterialUtility/ResolveBuiltinBaseColorFactor.md b/docs/api/XCEngine/Rendering/RenderMaterialUtility/ResolveBuiltinBaseColorFactor.md new file mode 100644 index 00000000..d874584a --- /dev/null +++ b/docs/api/XCEngine/Rendering/RenderMaterialUtility/ResolveBuiltinBaseColorFactor.md @@ -0,0 +1,55 @@ +# ResolveBuiltinBaseColorFactor + +**命名空间**: `XCEngine::Rendering` + +**类型**: `function` + +**头文件**: `XCEngine/Rendering/RenderMaterialUtility.h` + +## 签名 + +```cpp +Math::Vector4 ResolveBuiltinBaseColorFactor(const Resources::Material* material); +``` + +## 作用 + +解析 builtin forward 当前使用的 base color 因子。 + +## 当前实现行为 + +当前按以下顺序解析: + +1. 如果 `material == nullptr`,直接返回 `Math::Vector4::One()`。 +2. 优先根据 shader property semantic `BaseColor` 查找属性。 +3. 如果 semantic 路径没命中,再回退到常见属性名: + - `baseColor` + - `_BaseColor` + - `color` + - `_Color` +4. 如果仍然没有 base color,则先以 `(1, 1, 1, 1)` 为默认值,再尝试只从这些属性补 alpha: + - `opacity` + - `_Opacity` + - `alpha` + - `_Alpha` + +## 当前语义要点 + +- semantic 元数据优先级高于约定别名。 +- 如果没有颜色因子但有 opacity/alpha,当前会只改 `w` 分量,RGB 仍保持 `1`。 +- 这条 helper 只解析颜色因子,不解析纹理;纹理由 [ResolveBuiltinBaseColorTexture](ResolveBuiltinBaseColorTexture.md) 负责。 + +## 测试覆盖 + +`tests/Rendering/unit/test_render_scene_extractor.cpp` 当前验证了: + +- canonical 名称 `baseColor` +- 别名 `_BaseColor` +- shader semantic `BaseColor` +- 只有 opacity 时的 alpha-only fallback + +## 相关文档 + +- [ResolveBuiltinBaseColorTexture](ResolveBuiltinBaseColorTexture.md) +- [BuildBuiltinForwardMaterialData](BuildBuiltinForwardMaterialData.md) +- [RenderMaterialUtility](RenderMaterialUtility.md) diff --git a/docs/api/XCEngine/Rendering/RenderMaterialUtility/ResolveBuiltinBaseColorTexture.md b/docs/api/XCEngine/Rendering/RenderMaterialUtility/ResolveBuiltinBaseColorTexture.md new file mode 100644 index 00000000..e17f79ca --- /dev/null +++ b/docs/api/XCEngine/Rendering/RenderMaterialUtility/ResolveBuiltinBaseColorTexture.md @@ -0,0 +1,52 @@ +# ResolveBuiltinBaseColorTexture + +**命名空间**: `XCEngine::Rendering` + +**类型**: `function` + +**头文件**: `XCEngine/Rendering/RenderMaterialUtility.h` + +## 签名 + +```cpp +const Resources::Texture* ResolveBuiltinBaseColorTexture(const Resources::Material* material); +``` + +## 作用 + +解析 builtin forward 当前使用的 base color 贴图。 + +## 当前实现行为 + +当前按以下顺序解析: + +1. 如果 `material == nullptr`,直接返回 `nullptr`。 +2. 优先根据 shader property semantic `BaseColorTexture` 查找属性。 +3. 如果 semantic 路径没命中,再回退到常见纹理名: + - `baseColorTexture` + - `_BaseColorTexture` + - `_MainTex` + - `albedoTexture` + - `mainTexture` + - `texture` +4. 只有当 `ResourceHandle` 非空且 `IsValid()` 为真时,才返回底层 `Texture*`。 + +## 当前语义要点 + +- semantic 元数据优先级高于约定别名。 +- 这条 helper 只返回当前应绑定的贴图资源,不负责上传 GPU 纹理或创建 SRV;那部分由 [RenderResourceCache](../RenderResourceCache/RenderResourceCache.md) 处理。 +- 如果所有路径都没命中,返回 `nullptr`,再由调用方决定是否使用 fallback 纹理。 + +## 测试覆盖 + +`tests/Rendering/unit/test_render_scene_extractor.cpp` 当前验证了: + +- 别名 `_BaseColorTexture` +- shader semantic `BaseColorTexture` + +## 相关文档 + +- [ResolveBuiltinBaseColorFactor](ResolveBuiltinBaseColorFactor.md) +- [BuildBuiltinForwardMaterialData](BuildBuiltinForwardMaterialData.md) +- [BuiltinForwardPipeline](../Pipelines/BuiltinForwardPipeline/BuiltinForwardPipeline.md) +- [RenderMaterialUtility](RenderMaterialUtility.md) diff --git a/docs/api/XCEngine/Rendering/RenderPass/RenderPass.md b/docs/api/XCEngine/Rendering/RenderPass/RenderPass.md new file mode 100644 index 00000000..4e65461d --- /dev/null +++ b/docs/api/XCEngine/Rendering/RenderPass/RenderPass.md @@ -0,0 +1,81 @@ +# RenderPass + +**命名空间**: `XCEngine::Rendering` + +**类型**: `header-overview` + +**头文件**: `XCEngine/Rendering/RenderPass.h` + +**描述**: 定义轻量通用 pass 抽象 `RenderPass`、执行上下文 `RenderPassContext` 以及顺序执行容器 `RenderPassSequence`。 + +## 概览 + +`RenderPass.h` 是当前渲染基础设施里最通用的一层 pass 协议。 + +它统一回答三件事: + +- pass 执行时能拿到什么上下文 +- 一个 pass 最少需要实现哪些生命周期函数 +- 多个 pass 如何按顺序组成一个小型执行序列 + +## 当前定义 + +### `RenderPassContext` + +`RenderPassContext` 只是三个引用的聚合: + +- `renderContext` +- `surface` +- `sceneData` + +### `RenderPass` + +抽象基类包含四个核心成员: + +| 成员 | 当前语义 | +|------|------| +| `GetName()` | 返回 pass 的人类可读名称。 | +| `Initialize()` | 默认返回 `true`,需要时准备一次性资源。 | +| `Execute()` | 纯虚函数,执行真正的 pass 逻辑。 | +| `Shutdown()` | 默认空实现,释放 pass 资源。 | + +### `RenderPassSequence` + +`RenderPassSequence` 是一个拥有型容器,内部以 `std::unique_ptr` 顺序保存 pass。 + +当前行为是: + +- `AddPass()` 会忽略空指针 +- `GetPassCount()` 返回当前持有的 pass 数 +- `Initialize()` 按插入顺序调用每个 pass 的 `Initialize()` +- `Execute()` 按插入顺序调用每个 pass 的 `Execute()` +- `Shutdown()` 按逆序调用每个 pass 的 `Shutdown()` + +## 失败与回滚语义 + +- `Initialize()` 遇到失败会立即返回 `false` +- `Execute()` 遇到失败也会立即停止后续 pass +- `RenderPassSequence` 自身不会在 `Initialize()` 失败时自动回滚已经初始化过的 pass + +当前更高层调用方,例如 `CameraRenderer`,会额外包一层 helper:若 sequence 初始化失败,就主动执行一次 `Shutdown()` 回滚。 + +## 测试验证的真实行为 + +`tests/Rendering/unit/test_render_pass.cpp` 已覆盖: + +- 初始化和执行按插入顺序发生 +- `Shutdown()` 按逆序发生 +- 中间某个 pass 执行失败时,后续 pass 不再执行 + +## 当前实现边界 + +- 这套协议仍然是线性顺序执行,不是 render graph,也没有显式资源依赖建模。 +- `RenderPassSequence` 只管理 pass 对象,不管理共享资源或跨 pass 的状态同步。 +- `RenderPassContext` 暂时只暴露一个目标表面和一份 `RenderSceneData`,不适合表达更复杂的多目标或多阶段图结构。 + +## 相关文档 + +- [当前模块](../Rendering.md) +- [CameraRenderRequest](../CameraRenderRequest/CameraRenderRequest.md) +- [CameraRenderer](../CameraRenderer/CameraRenderer.md) +- [Passes](../Passes/Passes.md) diff --git a/docs/api/XCEngine/Rendering/RenderPipelineAsset/CreatePipeline.md b/docs/api/XCEngine/Rendering/RenderPipelineAsset/CreatePipeline.md index 6f7994c3..27cc6123 100644 --- a/docs/api/XCEngine/Rendering/RenderPipelineAsset/CreatePipeline.md +++ b/docs/api/XCEngine/Rendering/RenderPipelineAsset/CreatePipeline.md @@ -14,28 +14,29 @@ virtual std::unique_ptr CreatePipeline() const = 0; ## 接口契约 -从接口形状上,调用方可以依赖这几点: +从接口形状上,调用方可以依赖这些事实: - 返回值拥有独占所有权 - 返回对象是 `RenderPipeline` 派生实例 -- 这是一个 `const` 工厂方法,asset 自己不需要暴露可变运行时状态 +- 这是一个 `const` 工厂方法;asset 自己不需要暴露可变运行时状态 ## 当前调用链 -当前最主要的消费方是 `CameraRenderer` 内部的 `CreatePipelineFromAsset()`: +当前最主要的消费者是 `CameraRenderer` 内部的 `CreatePipelineFromAsset()`: 1. 若存在 `pipelineAsset`,先调用 `asset->CreatePipeline()` -2. 若拿到有效实例,就把它作为当前主管线 -3. 若 asset 为空或返回空指针,再回退到 `BuiltinForwardPipeline` +2. 若拿到有效实例,就把它接成当前主管线 +3. 若 asset 为空或返回空指针,再由 `CameraRenderer` 的调用路径回退到 builtin forward -因此派生类最好遵守一个明确的工程约定: +要点是: -- 返回一条新的、可独立 `Shutdown()` / `Render()` 的 runtime pipeline -- 不要把某条活动中的共享 pipeline 实例直接借给调用方 +- “创建 runtime pipeline”是这个接口的职责 +- “创建失败后如何回退”是调用方的职责,不是接口本身的内建语义 ## 返回值 -- `std::unique_ptr` - 新创建的运行时管线;允许派生类返回 `nullptr`,但当前默认调用方会把这视为失败并继续走 fallback +- `std::unique_ptr` - 新创建的运行时管线 +- 允许派生类返回 `nullptr`;但这会被当前调用方视为“创建失败”,并走自己的 fallback 路径 ## 当前公开实现示例 @@ -43,14 +44,8 @@ virtual std::unique_ptr CreatePipeline() const = 0; ## 设计说明 -这里使用 `std::unique_ptr` 很关键,因为 runtime pipeline 往往持有: - -- 设备指针 -- pipeline state -- descriptor set -- 缓存和临时 GPU 资源 - -这类对象通常应当具备清晰的唯一生命周期,而不是被多处共享。 +这里使用 `std::unique_ptr` 很关键,因为 runtime pipeline 往往持有设备指针、pipeline state、descriptor set、缓存和临时 GPU 资源。 +这类对象通常应当有清晰的唯一生命周期,而不是被多处共享。 ## 相关文档 diff --git a/docs/api/XCEngine/Rendering/RenderPipelineAsset/RenderPipelineAsset.md b/docs/api/XCEngine/Rendering/RenderPipelineAsset/RenderPipelineAsset.md index 24c7d9fa..d4e58c2b 100644 --- a/docs/api/XCEngine/Rendering/RenderPipelineAsset/RenderPipelineAsset.md +++ b/docs/api/XCEngine/Rendering/RenderPipelineAsset/RenderPipelineAsset.md @@ -6,51 +6,42 @@ **头文件**: `XCEngine/Rendering/RenderPipelineAsset.h` -**描述**: 渲染管线工厂接口,用于按需创建新的 runtime [RenderPipeline](../RenderPipeline/RenderPipeline.md) 实例。 +**描述**: 主管线工厂接口,用于按需创建新的 runtime [RenderPipeline](../RenderPipeline/RenderPipeline.md) 实例。 ## 概览 -`RenderPipelineAsset` 的职责不是自己渲染,而是回答一个更高层的问题: +`RenderPipelineAsset` 不负责自己绘制场景,而是回答一个更高层的问题: -- 当前这台 `CameraRenderer` 应该创建哪一种主管线实例? +- 当前这台 [CameraRenderer](../CameraRenderer/CameraRenderer.md) 应该创建哪一种主场景 runtime 管线? -这和商业引擎里常见的 `RenderPipelineAsset -> RenderPipeline` 分层很接近。好处是: +这层抽象把“选择哪条主管线”和“真正执行主场景绘制”拆开: -- 上层编排器只依赖抽象接口,不直接硬编码具体管线类型 -- runtime pipeline 可以被重建、替换或按不同入口注入 -- 工厂对象和运行时实例可以采用不同所有权模型 +- asset 负责创建 runtime pipeline +- runtime pipeline 负责执行主场景绘制 ## 当前真实接线 -当前最直接的消费方是 [CameraRenderer](../CameraRenderer/CameraRenderer.md): +当前最直接的消费者是 [CameraRenderer](../CameraRenderer/CameraRenderer.md): -- 默认构造时会拿到一份默认 pipeline asset -- [SetPipelineAsset](../CameraRenderer/SetPipelineAsset.md) 会通过 asset 重建主管线 -- `GetPipelineAsset()` 返回的是当前工厂对象,而不是 runtime pipeline +- 默认构造路径会持有一份默认 asset +- [SetPipelineAsset](../CameraRenderer/SetPipelineAsset.md) 会通过 asset 重建当前 runtime pipeline +- [GetPipelineAsset](../CameraRenderer/GetPipelineAsset.md) 返回的是工厂对象,不是 runtime pipeline 实例 -按当前源码,默认 concrete asset 是 [Pipelines::BuiltinForwardPipelineAsset](../Pipelines/BuiltinForwardPipelineAsset/BuiltinForwardPipelineAsset.md)。 - -## 当前公开实现 - -当前公开的 concrete 实现有: - -- [BuiltinForwardPipelineAsset](../Pipelines/BuiltinForwardPipelineAsset/BuiltinForwardPipelineAsset.md) - -它会创建 [BuiltinForwardPipeline](../Pipelines/BuiltinForwardPipeline/BuiltinForwardPipeline.md)。 +按当前源码,默认 concrete asset 是 [BuiltinForwardPipelineAsset](../Pipelines/BuiltinForwardPipelineAsset/BuiltinForwardPipelineAsset.md)。 ## 生命周期与所有权 -- `RenderPipelineAsset` 通常以 `std::shared_ptr` 共享持有 +- asset 通常以 `std::shared_ptr` 共享持有 - [CreatePipeline](CreatePipeline.md) 返回新的 `std::unique_ptr` - asset 不保留运行时实例;实例生命周期由 `CameraRenderer` 或调用方接管 -这种“共享工厂 + 独占运行体”的组合很适合渲染系统,因为 runtime pipeline 往往持有设备、pipeline state 和 descriptor set,不适合被多方共享所有权。 +这是一种“共享工厂对象 + 独占运行时实例”的分层。 ## 当前实现边界 -- 当前它仍然只是纯 C++ 工厂接口,不是项目资源数据库里的可序列化资产类型 -- 还没有 renderer asset inspector、热重载或多 profile 配置 -- 当前 fallback 策略很保守,目标是“即使 asset 路径出问题,也尽量总有 builtin pipeline 可跑” +- 这里仍然只是纯 C++ 工厂接口,不是项目资源数据库里的可序列化 renderer asset。 +- “空 asset”或“asset 返回空指针”之后如何回退,不属于这个接口本身的职责;当前 fallback 逻辑发生在 `CameraRenderer` 的 `CreatePipelineFromAsset()` 调用路径里。 +- 当前公开的 concrete asset 仍只有 builtin forward 一条。 ## 公开方法 @@ -61,11 +52,8 @@ ## 设计说明 -这一层的重要性,不在于“多包一层接口”,而在于把“选择哪种主管线”和“真正执行绘制”分开: - -- `CameraRenderer` 不需要知道 builtin forward 的内部细节 -- 不同 asset 后续可以创建完全不同的 runtime pipeline 类型 -- 如果未来要把主管线选择接入项目设置或 viewport 模式,不必重写 camera submission 主流程 +这一层的重要性不在于“多包一层接口”,而在于把“选哪种主管线”从 [CameraRenderer](../CameraRenderer/CameraRenderer.md) 的执行逻辑里抽出来。 +这样后续即便增加新的 concrete pipeline,也不需要改动单 request 执行主链路。 ## 相关文档 diff --git a/docs/api/XCEngine/Rendering/RenderSceneUtility/RenderSceneUtility.md b/docs/api/XCEngine/Rendering/RenderSceneUtility/RenderSceneUtility.md new file mode 100644 index 00000000..66207b40 --- /dev/null +++ b/docs/api/XCEngine/Rendering/RenderSceneUtility/RenderSceneUtility.md @@ -0,0 +1,73 @@ +# RenderSceneUtility + +**命名空间**: `XCEngine::Rendering` + +**类型**: `utility header` + +**头文件**: `XCEngine/Rendering/RenderSceneUtility.h` + +**描述**: 提供把相机和场景对象翻译成 `RenderCameraData` 与 `VisibleRenderItem` 的基础 helper。 + +## 概览 + +`RenderSceneUtility.h` 位于 [RenderSceneExtractor](../RenderSceneExtractor/RenderSceneExtractor.md) 的下层,负责两类最基础的转换: + +1. 把 `CameraComponent` 的参数整理成渲染侧消费的 [RenderCameraData](../RenderCameraData/RenderCameraData.md) +2. 把 `GameObject + MeshFilter + MeshRenderer` 组合展开成可绘制的 `VisibleRenderItem` + +## 公开函数 + +### `BuildRenderCameraData()` + +根据相机组件和目标视口大小构建 [RenderCameraData](../RenderCameraData/RenderCameraData.md): + +- 复制 `viewportWidth` / `viewportHeight` +- 读取相机世界位置和 `clearColor` +- 根据投影模式构建 perspective 或 orthographic 投影矩阵 +- 把 `view`、`projection`、`viewProjection` 以转置后的矩阵形式写入结果 + +当前还要注意一个边界: + +- 这里不会根据 `CameraComponent::GetClearMode()` 推导 `clearFlags` +- 返回结果里的 `clearFlags` 仍保留 [RenderCameraData](../RenderCameraData/RenderCameraData.md) 的默认值 `RenderClearFlags::All` +- 真正的 per-request clear 规则是在 [SceneRenderRequestUtils](../SceneRenderRequestUtils/SceneRenderRequestUtils.md) 先解析成 `CameraRenderRequest::clearFlags`,再由 [CameraRenderer](../CameraRenderer/CameraRenderer.md) 写回 `sceneData.cameraData.clearFlags` + +### `AppendRenderItemsForGameObject()` + +把单个 `GameObject` 追加成一个或多个 `VisibleRenderItem`。 +当前筛选规则是: + +- 非激活对象直接跳过 +- 缺少 `MeshFilterComponent` 或 `MeshRendererComponent` 直接跳过 +- 任一组件被禁用时跳过 +- `mesh == nullptr` 或 `mesh->IsValid() == false` 时跳过 + +若 mesh 存在 section,则每个 section 生成一个 `VisibleRenderItem`;否则退化成单个无 section 的 item。 + +### `CollectRenderItemsForEntityIds()` + +按给定 `entityIds` 收集可绘制对象,当前会: + +- 跳过 `0` +- 去重重复实体 ID +- 忽略找不到的对象 +- 复用 `AppendRenderItemsForGameObject()` 展开 section + +## 真实使用位置 + +- `engine/src/Rendering/RenderSceneExtractor.cpp` 用它构建相机数据和可见物体列表。 +- `tests/Rendering/unit/test_render_scene_utility.cpp` 覆盖了相机矩阵约定、实体过滤和 section 展开。 + +## 当前实现边界 + +- 当前没有做 frustum culling、LOD、遮挡剔除或 batching。 +- `cameraDistanceSq` 只按对象变换平移量估算,不考虑 bounds 中心或 section 级差异。 +- 这些函数直接操作场景对象和组件引用,还不是完全解耦的 render proxy 阶段。 + +## 相关文档 + +- [Rendering](../Rendering.md) +- [RenderCameraData](../RenderCameraData/RenderCameraData.md) +- [RenderSceneExtractor](../RenderSceneExtractor/RenderSceneExtractor.md) +- [VisibleRenderObject](../VisibleRenderObject/VisibleRenderObject.md) +- [RenderMaterialUtility](../RenderMaterialUtility/RenderMaterialUtility.md) diff --git a/docs/api/XCEngine/Rendering/Rendering.md b/docs/api/XCEngine/Rendering/Rendering.md index 782a3551..936a39e1 100644 --- a/docs/api/XCEngine/Rendering/Rendering.md +++ b/docs/api/XCEngine/Rendering/Rendering.md @@ -4,65 +4,70 @@ **类型**: `module` -**描述**: 提供场景提取、相机渲染请求、主管线执行、object-id 辅助输出和 builtin post-process 叠加的当前渲染主链路。 +**描述**: 当前场景渲染主链路所在模块,覆盖 request 规划、场景提取、主管线执行、object-id 输出,以及调用方注入的 post / overlay pass。 ## 概览 -当前 `XCEngine::Rendering` 可以按一条更完整的链路理解: +当前 `Rendering` 模块已经不是简单的“scene -> pipeline”两段式结构,而是一条更完整的提交链: -1. [SceneRenderer](SceneRenderer/SceneRenderer.md) 负责组织和排序多个相机请求。 -2. [CameraRenderRequest](CameraRenderRequest/CameraRenderRequest.md) 把单次提交的主表面、object-id 输出和 builtin 后处理需求打包起来。 -3. [CameraRenderer](CameraRenderer/CameraRenderer.md) 执行单个请求。 -4. [RenderSceneExtractor](RenderSceneExtractor/RenderSceneExtractor.md) 依据相机和 render area 提取 `RenderSceneData`。 -5. [RenderPipelineAsset](RenderPipelineAsset/RenderPipelineAsset.md) 决定创建哪条 runtime 主场景管线;默认实现是 [Pipelines::BuiltinForwardPipelineAsset](Pipelines/BuiltinForwardPipelineAsset/BuiltinForwardPipelineAsset.md)。 -6. [RenderPipeline](RenderPipeline/RenderPipeline.md) 负责主场景绘制;当前默认 runtime 实现是 [Pipelines::BuiltinForwardPipeline](Pipelines/BuiltinForwardPipeline/BuiltinForwardPipeline.md)。 -7. `ObjectIdPass` 与 [Passes](Passes/Passes.md) 子模块在主场景之后补上 object-id、grid 和 selection outline 等额外结果。 -8. [RenderMaterialUtility](RenderMaterialUtility/RenderMaterialUtility.md) 把材质元数据与 render state 翻译成这条链路能消费的规则。 +1. [SceneRenderer](SceneRenderer/SceneRenderer.md) 规划并排序 `CameraRenderRequest`。 +2. [CameraRenderer](CameraRenderer/CameraRenderer.md) 执行单个 request。 +3. [RenderSceneExtractor](RenderSceneExtractor/RenderSceneExtractor.md) 生成 `RenderSceneData`。 +4. [RenderPipelineAsset](RenderPipelineAsset/RenderPipelineAsset.md) 决定当前主管线实例如何创建。 +5. [RenderPipeline](RenderPipeline/RenderPipeline.md) 执行主场景绘制。 +6. [ObjectIdPass](ObjectIdPass/ObjectIdPass.md) 与 [Passes](Passes/Passes.md) 子模块补上 object-id、grid、outline 等附加阶段。 -这意味着当前渲染模块已经不只是“scene -> pipeline”两段式结构,而是包含了主场景、辅助缓冲和 builtin post-process 的完整相机提交流程。 +默认主链路当前是: -更底层的基础协议则由 [SceneRenderRequestPlanner](SceneRenderRequestPlanner/SceneRenderRequestPlanner.md)、[SceneRenderRequestUtils](SceneRenderRequestUtils/SceneRenderRequestUtils.md)、[RenderSceneUtility](RenderSceneUtility/RenderSceneUtility.md)、[RenderPass](RenderPass/RenderPass.md)、[ObjectIdPass](ObjectIdPass/ObjectIdPass.md) 和 [ObjectIdEncoding](ObjectIdEncoding/ObjectIdEncoding.md) 补齐。它们分别负责请求规划、排序规则、场景提取 helper、通用 pass 生命周期以及 object-id 编解码约定。 +- [BuiltinForwardPipelineAsset](Pipelines/BuiltinForwardPipelineAsset/BuiltinForwardPipelineAsset.md) +- [BuiltinForwardPipeline](Pipelines/BuiltinForwardPipeline/BuiltinForwardPipeline.md) ## 当前主流程 -对一台相机,当前主流程大致是: +对一台相机的大致流程是: -1. `SceneRenderer` 生成并排序 `CameraRenderRequest` -2. `CameraRenderer` 校验请求 -3. `RenderSceneExtractor` 提取可见物体与相机数据 -4. 通过 `RenderPipelineAsset` 创建或替换主管线实例 -5. 主 `RenderPipeline` 绘制主颜色目标 -6. 如有需要,执行 object-id pass,生成辅助 object-id 纹理 -7. 执行调用方注入的 post pass、builtin post-process 和 overlay pass +1. `SceneRenderer` 生成 `CameraRenderRequest`。 +2. `CameraRenderer` 校验 request 与 render-area。 +3. `RenderSceneExtractor` 基于相机和 render-area 提取 `RenderSceneData`。 +4. `RenderPipeline` 绘制主颜色目标。 +5. 如有需要,执行 object-id pass。 +6. 执行 `postScenePasses` 与 `overlayPasses`。 -scene viewport 的无限网格和选中轮廓,就是通过这条 object-id + builtin post-process 链路接入的。 +Scene View 里的无限网格、选中轮廓和编辑器 overlay,当前都不是 `CameraRenderer` 内部动态规划出来的,而是先在 Editor 层组装成 request plan,再通过 `postScenePasses` / `overlayPasses` 接入这条主链。 -## 材质语义如何进入渲染路径 +## 材质与 shader 语义如何进入主链路 -[RenderMaterialUtility](RenderMaterialUtility/RenderMaterialUtility.md) 当前负责消费材质里的: +[RenderMaterialUtility](RenderMaterialUtility/RenderMaterialUtility.md) 当前负责把材质里的: - `shaderPass` - `LightMode` - `renderQueue` - `renderState` -这些元数据可能来自普通材质文件,也可能来自 `MaterialLoader` 读取的 `.xcmat` artifact。它们最终会影响: +翻译成渲染链路可消费的规则。 -- 某个可见物体属于哪个 builtin pass -- 不透明 / 透明排序语义 -- 剔除、混合和深度状态如何写进图形管线描述 +在默认 builtin forward 路径里,shader pass 的 `resources` 声明还会进一步参与 `PassResourceLayout` 构建,因为 [BuiltinForwardPipeline](Pipelines/BuiltinForwardPipeline/BuiltinForwardPipeline.md) 已经开始按资源契约生成 descriptor set layout。 -在当前默认 builtin forward 路径里,shader pass 的 `resources` 声明还会进一步参与 `PassResourceLayout` 构建,因为 `BuiltinForwardPipeline` 已经开始按资源契约生成 descriptor set layout。 +## 当前基础设施分层 + +更底层的基础协议由这些页面补齐: + +- [SceneRenderRequestPlanner](SceneRenderRequestPlanner/SceneRenderRequestPlanner.md) +- [SceneRenderRequestUtils](SceneRenderRequestUtils/SceneRenderRequestUtils.md) +- [RenderSceneUtility](RenderSceneUtility/RenderSceneUtility.md) +- [RenderPass](RenderPass/RenderPass.md) +- [ObjectIdEncoding](ObjectIdEncoding/ObjectIdEncoding.md) + +它们分别负责 request 规划、排序规则、scene helper、通用 pass 生命周期和 object-id 编解码约定。 ## 当前实现边界 -- 当前默认路径仍然是内建前向渲染,而不是完整 SRP / render graph。 -- `RenderPipelineAsset` 已经接入默认主链路,但当前还不是项目资源系统里的完整 renderer asset。 -- object-id 和 builtin post-process 主要服务于编辑器视口与调试链路。 -- builtin selection outline 当前依赖单独的 object-id SRV,而不是从主颜色结果反推。 -- 多相机排序由 `SceneRenderer` 处理,`CameraRenderer` 本身只执行单请求。 +- 默认主路径仍然是 builtin forward,不是完整 SRP 或 render graph。 +- `RenderPipelineAsset` 已经接入默认主链路,但当前还不是项目资源数据库里的完整 renderer asset。 +- 多相机排序由 `SceneRenderer` 处理,`CameraRenderer` 只执行单个 request。 +- 编辑器特有的 grid / outline / overlay 组装逻辑不在 `Rendering` 模块里完成,而是在 Editor 层先转成 `RenderPassSequence`。 -## 头文件 +## 头文件索引 - [CameraRenderRequest](CameraRenderRequest/CameraRenderRequest.md) - `CameraRenderRequest.h` - [CameraRenderer](CameraRenderer/CameraRenderer.md) - `CameraRenderer.h` @@ -93,5 +98,5 @@ scene viewport 的无限网格和选中轮廓,就是通过这条 object-id + b - [Components](../Components/Components.md) - [RHI](../RHI/RHI.md) -- [上级目录](../XCEngine.md) -- [API 总索引](../../main.md) +- [XCEngine](../XCEngine.md) +- [API 索引](../../main.md) diff --git a/docs/api/_guides/Rendering/Scene-Extraction-And-Builtin-Forward-Pipeline.md b/docs/api/_guides/Rendering/Scene-Extraction-And-Builtin-Forward-Pipeline.md index 2499edc7..ddb9d3b9 100644 --- a/docs/api/_guides/Rendering/Scene-Extraction-And-Builtin-Forward-Pipeline.md +++ b/docs/api/_guides/Rendering/Scene-Extraction-And-Builtin-Forward-Pipeline.md @@ -1,149 +1,146 @@ # Scene Extraction And Builtin Forward Pipeline -## 先理解这套渲染架构在做什么 +## 这条链路现在怎么工作 -当前 XCEngine 的渲染链路,不是“场景对象自己直接调用 RHI 去画”,而是先做一次轻量的场景提取,再交给具体渲染管线执行: +当前 XCEngine 的主场景渲染链路可以按下面的顺序理解: -1. `Scene` 和 `GameObject` 维护对象层级与组件。 -2. `MeshFilterComponent` 提供几何数据。 -3. `MeshRendererComponent` 提供材质槽和渲染标志。 -4. `RenderSceneExtractor` 把这些信息拍平为 `RenderSceneData`。 -5. `SceneRenderer` 把提取结果交给 `BuiltinForwardPipeline`。 -6. `BuiltinForwardPipeline` 通过 RHI 发出真正 draw call。 +1. `SceneRenderer` 负责组织相机请求和执行顺序。 +2. `CameraRenderer` 选择主渲染管线;默认情况下,它通过 `BuiltinForwardPipelineAsset` 创建 `BuiltinForwardPipeline`。 +3. `RenderSceneExtractor` 把 scene/game-object/component 结构压平成 `RenderSceneData`。 +4. `BuiltinForwardPipeline` 把 `RenderSceneData` 绘制到 `RenderSurface`。 -这条链路和很多商业引擎的基本思路是一致的。真正成熟的区别,不在“有没有 scene extraction 这个词”,而在于提取阶段做得有多深。 +这里的关键点不是“有没有前向渲染”,而是场景数据和绘制数据已经被拆成两层: -## 为什么要把 Mesh 和 Renderer 分开 +- 提取阶段负责从场景组织里收集相机、光照和可绘制项。 +- pipeline 阶段只消费已经整理好的 `RenderSceneData`。 -`MeshFilterComponent + MeshRendererComponent` 这种拆分,和 Unity 的老思路非常接近。它背后的设计理由很实用: +不过这里讲的只是主场景绘制槽位,不是整次相机提交的完整尾段。按 `engine/src/Rendering/CameraRenderer.cpp` 的当前实现,`BuiltinForwardPipeline` 前后还可能包着: -- 几何数据和材质配置是两种不同维度的信息。 -- 同一个 mesh 可能被不同材质配置复用。 -- 渲染系统提取时,可以分别读取 geometry source 和 material state。 +- `preScenePasses` +- object-id pass +- `postScenePasses` +- `overlayPasses` -如果把这两层全部混在一个组件里,短期写起来更省事,但长期会让复用、序列化和编辑器展示都更别扭。 +Scene View 的网格、选中描边和 editor overlay,当前就是先在 Editor 层组装成这些 request 级序列,再交给 `CameraRenderer` 执行。 -## 为什么需要 Scene Extraction +## `RenderSceneData` 现在包含什么 -对游戏对象系统来说,最自然的数据组织方式是树状层级和组件组合;但对渲染来说,最自然的数据组织方式通常是: +`RenderSceneExtractor` 当前产出的核心数据有三块: -- 一台相机 -- 一组可见对象 -- 每个对象对应的变换、mesh 和材质 +- `camera` 与 `cameraData` +- `lighting` +- `visibleItems` -所以提取阶段的意义,就是把“适合编辑和运行时逻辑”的数据形状,转换成“适合绘制”的数据形状。 +其中 `visibleItems` 的元素类型是 `VisibleRenderItem`。头文件里仍保留 `VisibleRenderObject = VisibleRenderItem` 的兼容别名,但当前实现和新文档都应以 `visibleItems` 为准,而不是旧说法 `visibleObjects`。 -当前 `RenderSceneExtractor` 做的是这条路线中最基础的一版: +每个 `VisibleRenderItem` 除了 mesh 和变换,还已经携带: -- 选相机 -- 算矩阵 -- 遍历层级 -- 收集 mesh 对象 +- `material` +- `materialIndex` +- `sectionIndex` +- `hasSection` +- `renderQueue` +- `cameraDistanceSq` -这和商业引擎的真正可见性阶段相比还很早期,但方向没有问题。 +这让后续 pipeline 不需要回到场景层重新做组件查询。 -## 当前 extractor 做了什么,没做什么 +## 为什么还要保留 scene extraction -已经做的: +游戏对象系统天然偏向层级、组件和编辑器语义;渲染系统天然偏向“当前相机要画哪些项”。`RenderSceneExtractor` 的价值就是把这两种数据形状解耦。 -- 覆盖相机优先。 -- 没有覆盖相机时,优先选择 `IsPrimary()` 且 `depth` 更高的相机。 -- 只收集激活层级中的对象。 -- 只收集同时拥有 `MeshFilterComponent` 和 `MeshRendererComponent` 的对象。 +当前 extractor 已经做的事情包括: -还没做的: +- 选择相机并生成 `RenderCameraData` +- 提取主方向光数据 +- 递归收集满足基础绘制条件的可见项 +- 产出 `visibleItems` 并带上 material / section / distance 等渲染侧字段 -- 视锥裁剪。 -- 遮挡裁剪。 -- 透明排序。 -- render layer 过滤。 -- 阴影 caster / receiver 分类。 -- instancing / batching。 +它还没有做完整的商业级可见性系统,例如: -所以当前 `visibleObjects` 更准确地说是“当前场景里满足基础绘制条件的对象集合”,而不是严格意义上的最终可见集。 +- 视锥裁剪 +- 遮挡裁剪 +- instancing / batching +- 透明排序主路径 -## RenderSurface 为什么重要 +## `BuiltinForwardPipeline` 的当前定位 -很多小型引擎一开始会把“渲染目标”写死成 swap chain back buffer,但这条路很快就会卡住: +`BuiltinForwardPipeline` 现在是默认主渲染路径,但它内部已经不是旧的固定绑定模型,而是三层缓存: -- 离屏渲染怎么办? -- 编辑器预览窗口怎么办? -- 反射探针、后处理链路怎么办? +- 按 `(shader*, passName)` 缓存 `PassResourceLayout` +- 按 `(shader*, passName, render state)` 缓存 `RHIPipelineState` +- 按 `(passLayout, setIndex, objectId, material)` 缓存动态 descriptor set -`RenderSurface` 的作用,就是把这些目标抽象出来。当前它虽然还很轻量,但已经能描述: +此外它已经接入 [RenderPassSequence](../../XCEngine/Rendering/RenderPass/RenderPass.md): + +- 构造时注册 `BuiltinForwardOpaquePass` +- `Initialize()` 走 sequence 生命周期 +- `Render()` 先构造 `RenderPassContext`,再执行 sequence +- `Shutdown()` 也走 sequence,再由 opaque pass 回调资源清理 + +所以当前 builtin forward 更像“一条默认可运行的 pass-sequence 管线”,而不是过去那种把所有逻辑揉在一个固定 layout 里的实现。 + +## Shader pass 资源契约 + +当前 builtin forward 对 shader pass 的资源声明有明确白名单。可识别语义只有: + +- `PerObject`:必需,单个 CBV +- `Material`:可选,单个 CBV +- `BaseColorTexture`:可选,单个 `Texture2D` 或 `TextureCube` +- `LinearClampSampler`:可选,单个 sampler + +如果 shader pass 没有声明 `resources`,则会回退到 legacy builtin forward 绑定: + +- `set 1 binding 0` -> `PerObject` +- `set 2 binding 0` -> `Material` +- `set 3 binding 0` -> `BaseColorTexture` +- `set 4 binding 0` -> `LinearClampSampler` + +如果声明不合法,例如未知语义、同 set 混用 sampler 和非 sampler、重复 binding 或缺少 `PerObject`,pipeline 会拒绝为该 pass 创建布局。 + +测试 `tests/Rendering/unit/test_builtin_forward_pipeline.cpp` 还明确校验了 builtin shader `ForwardLit` pass 的这组资源契约,以及 `BuildInputLayout()` 现在使用 `POSITION=float3`。 + +## 单个可见项如何被画出来 + +当 `BuiltinForwardOpaquePass` 遍历 `RenderSceneData::visibleItems` 时,每个物体大致会经历以下步骤: + +1. 根据材质解析真正要用的 shader/pass;没有合适 pass 时回退到 builtin forward shader。 +2. 取得 mesh 的 GPU 资源缓存。 +3. 生成 `PerObjectConstants` 和 `PerMaterialConstants`。 +4. 获取或创建当前 shader pass 的 `PassResourceLayout`。 +5. 逐 set 绑定 descriptor: + - 含 `PerObject / Material / Texture` 的 set 走动态缓存。 + - 只含 sampler 的 set 走静态缓存。 +6. 按 section 或整 mesh 发出 draw call。 + +`BaseColorTexture` 如果解析不到,会回退到初始化阶段创建的 1x1 白色纹理 SRV。 + +## `RenderSurface` 在这里的作用 + +`RenderSurface` 不是单纯的附件容器,而是当前这一帧输出目标的完整描述。builtin forward 会消费它的: -- 尺寸 - 颜色附件 - 深度附件 -- 清屏色覆盖 -- 渲染前后颜色资源状态 +- render area +- clear color override +- 自动状态切换开关 +- `colorStateBefore` / `colorStateAfter` -这一步非常关键,因为它让 pipeline 不再只服务于窗口表面。 +因此这条主渲染路径既能服务于窗口 back buffer,也能服务于 editor viewport、离屏 RT 或其它自定义输出目标。 -## BuiltinForwardPipeline 的定位 +## 当前限制 -`BuiltinForwardPipeline` 当前的定位,不是“最终渲染架构”,而是“默认可用的第一条内建管线”。 - -它现在主要解决的是: - -- 把 mesh 上传成 vertex/index buffer -- 把 texture 上传成 shader resource -- 创建一套最基本的 pipeline state -- 对每个对象写常量、绑纹理、发 draw - -这和很多商业引擎早期 builtin pipeline 的定位很像:先确保有一条完整闭环,再逐步扩展能力。 - -## 为什么要有 RenderResourceCache - -场景对象和资源系统不应该直接持有具体 RHI 对象,否则很快会把层级关系搞乱: - -- 资源层会被具体后端污染。 -- 不同 backend 的资源生命周期会混到游戏对象逻辑里。 - -`RenderResourceCache` 把“CPU 资源 -> GPU 资源”的转换收口到渲染层,这是对的。 - -但当前它还只是基础版: - -- 以裸指针做 cache key。 -- 没有资源变更失效。 -- 没有线程安全。 -- 格式支持有限。 - -所以它更像“运行时上传缓存”,还不是完整的 render resource system。 - -## 当前这套设计和商业引擎相比差什么 - -如果拿商业级游戏引擎的渲染系统作参照,当前最明显的缺口包括: - -1. 没有真正的 visibility / culling pipeline。 -2. 没有 render queue、pass 分类和排序系统。 -3. 没有 lighting、shadow、post-processing 等完整渲染特性。 -4. 没有 render graph 或更强的 target dependency 管理。 -5. `RenderPipelineAsset` 还没有真正驱动运行时 pipeline 创建。 - -但从架构骨架看,当前已经把最核心的几个边界切开了: - -- scene data -- render data -- render target -- pipeline implementation -- GPU resource upload - -这恰恰是后续能继续演进的前提。 - -## 当前阶段的推荐用法 - -- 需要渲染场景时,优先通过 `SceneRenderer` 作为统一入口。 -- 几何数据放在 `MeshFilterComponent`,材质槽和渲染标志放在 `MeshRendererComponent`。 -- 把 `RenderSurface` 当作“这一帧的输出目标描述”,而不是只当附件容器。 -- 当前把 `BuiltinForwardPipeline` 看作默认可运行路径,而不是最终渲染架构。 +- 主场景默认只有 builtin forward opaque pass。 +- 透明、阴影、延迟渲染和更复杂的资源依赖管理还不在这条链路里。 +- `RenderPassSequence` 目前只提供顺序执行,不是 render graph。 ## 相关 API - [Rendering](../../XCEngine/Rendering/Rendering.md) - [RenderSceneExtractor](../../XCEngine/Rendering/RenderSceneExtractor/RenderSceneExtractor.md) - [RenderSurface](../../XCEngine/Rendering/RenderSurface/RenderSurface.md) +- [RenderPass](../../XCEngine/Rendering/RenderPass/RenderPass.md) - [SceneRenderer](../../XCEngine/Rendering/SceneRenderer/SceneRenderer.md) - [BuiltinForwardPipeline](../../XCEngine/Rendering/Pipelines/BuiltinForwardPipeline/BuiltinForwardPipeline.md) +- [BuiltinForwardPipelineAsset](../../XCEngine/Rendering/Pipelines/BuiltinForwardPipelineAsset/BuiltinForwardPipelineAsset.md) - [MeshFilterComponent](../../XCEngine/Components/MeshFilterComponent/MeshFilterComponent.md) - [MeshRendererComponent](../../XCEngine/Components/MeshRendererComponent/MeshRendererComponent.md) diff --git a/docs/api/_meta/rebuild-status.md b/docs/api/_meta/rebuild-status.md index 256d877d..cbaf81ba 100644 --- a/docs/api/_meta/rebuild-status.md +++ b/docs/api/_meta/rebuild-status.md @@ -1,12 +1,12 @@ # API 文档重构状态 -**生成时间**: `2026-04-03 15:07:08` +**生成时间**: `2026-04-03 15:30:08` **来源**: `docs/api/_tools/audit_api_docs.py` ## 摘要 -- Markdown 页面数(全部): `3327` +- Markdown 页面数(全部): `3324` - Markdown 页面数(canonical): `3298` - Public headers 数: `244` - Editor source headers 数: `124` @@ -74,8 +74,8 @@ | 字段 | 页面数 | |------|--------| -| `命名空间` | `891` | -| `类型` | `891` | +| `命名空间` | `941` | +| `类型` | `941` | | `描述` | `417` | -| `头文件` | `502` | +| `头文件` | `552` | | `源文件` | `348` | diff --git a/docs/api/main.md b/docs/api/main.md index 849f6444..4308dee9 100644 --- a/docs/api/main.md +++ b/docs/api/main.md @@ -4,17 +4,21 @@ **类型**: `index` -**描述**: 指向 `docs/api/XCEngine` 平行目录树的唯一 canonical API 文档入口。 +**描述**: 指向 `docs/api/XCEngine` 平行目录树与审计状态页的统一 API 文档入口。 ## 概览 -`docs/api/XCEngine/**` 是唯一正式 API 文档树,其层级与 `engine/include/XCEngine/**` 保持平行。 -模块总览页、子模块总览页、类型总览页和方法页都应从这棵目录树进入,不再保留第二套正式入口。 +`docs/api/XCEngine/**` 是当前唯一正式的 canonical API 文档树,其层级与 `engine/include/XCEngine/**` 保持平行。 + +根索引负责两件事: + +- 给出所有主要模块的入口导航。 +- 指向最新的文档审计状态,方便确认覆盖率、断链和遗留缺口。 ## Canonical 入口 - [XCEngine/XCEngine.md](XCEngine/XCEngine.md) - 与 `engine/include/XCEngine` 平行的文档根目录 -- [_meta/rebuild-status.md](_meta/rebuild-status.md) - 当前覆盖率与审计状态 +- [_meta/rebuild-status.md](_meta/rebuild-status.md) - 当前覆盖率、链接检查和审计状态 ## 模块导航 @@ -24,12 +28,15 @@ | `Components` | [XCEngine/Components/Components.md](XCEngine/Components/Components.md) | `XCEngine/Components/` | | `Core` | [XCEngine/Core/Core.md](XCEngine/Core/Core.md) | `XCEngine/Core/` | | `Debug` | [XCEngine/Debug/Debug.md](XCEngine/Debug/Debug.md) | `XCEngine/Debug/` | +| `Editor` | [XCEngine/Editor/Editor.md](XCEngine/Editor/Editor.md) | `editor/src/` | | `Input` | [XCEngine/Input/Input.md](XCEngine/Input/Input.md) | `XCEngine/Input/` | | `Memory` | [XCEngine/Memory/Memory.md](XCEngine/Memory/Memory.md) | `XCEngine/Memory/` | | `Platform` | [XCEngine/Platform/Platform.md](XCEngine/Platform/Platform.md) | `XCEngine/Platform/` | +| `Rendering` | [XCEngine/Rendering/Rendering.md](XCEngine/Rendering/Rendering.md) | `XCEngine/Rendering/` | | `Resources` | [XCEngine/Resources/Resources.md](XCEngine/Resources/Resources.md) | `XCEngine/Resources/` | | `RHI` | [XCEngine/RHI/RHI.md](XCEngine/RHI/RHI.md) | `XCEngine/RHI/` | | `Scene` | [XCEngine/Scene/Scene.md](XCEngine/Scene/Scene.md) | `XCEngine/Scene/` | +| `Scripting` | [XCEngine/Scripting/Scripting.md](XCEngine/Scripting/Scripting.md) | `XCEngine/Scripting/` | | `Threading` | [XCEngine/Threading/Threading.md](XCEngine/Threading/Threading.md) | `XCEngine/Threading/` | ## 关键子模块 @@ -40,6 +47,8 @@ | `Core/Containers` | [XCEngine/Core/Containers/Containers.md](XCEngine/Core/Containers/Containers.md) | `XCEngine/Core/Containers/` | | `Core/IO` | [XCEngine/Core/IO/IO.md](XCEngine/Core/IO/IO.md) | `XCEngine/Core/IO/` | | `Core/Math` | [XCEngine/Core/Math/Math.md](XCEngine/Core/Math/Math.md) | `XCEngine/Core/Math/` | +| `Editor/Viewport` | [XCEngine/Editor/Viewport/Viewport.md](XCEngine/Editor/Viewport/Viewport.md) | `editor/src/Viewport/` | +| `Rendering/Passes` | [XCEngine/Rendering/Passes/Passes.md](XCEngine/Rendering/Passes/Passes.md) | `XCEngine/Rendering/Passes/` | | `Platform/Windows` | [XCEngine/Platform/Windows/Windows.md](XCEngine/Platform/Windows/Windows.md) | `XCEngine/Platform/Windows/` | | `Resources/Mesh` | [XCEngine/Resources/Mesh/Mesh.md](XCEngine/Resources/Mesh/Mesh.md) | `XCEngine/Resources/Mesh/` | | `Resources/Texture` | [XCEngine/Resources/Texture/Texture.md](XCEngine/Resources/Texture/Texture.md) | `XCEngine/Resources/Texture/` | @@ -50,4 +59,4 @@ - [XCEngine 平行目录根](XCEngine/XCEngine.md) - [API 文档重构状态](_meta/rebuild-status.md) -- [XCEngine 架构设计](../plan/XCEngine渲染引擎架构设计.md) +- [XCEngine 架构设计](../used/XCEngine渲染引擎架构设计.md)