docs: archive old plans
This commit is contained in:
@@ -1,245 +0,0 @@
|
||||
# 3DGS-D3D12 最小可行系统计划
|
||||
|
||||
日期:2026-04-12
|
||||
|
||||
## 1. 文档定位
|
||||
|
||||
这份计划用于指导 `D:\Xuanchi\Main\XCEngine\mvs\3DGS-D3D12` 的最小可行系统落地。
|
||||
|
||||
当前任务边界已经明确:
|
||||
|
||||
1. 只允许在 `mvs/3DGS-D3D12` 目录内开发与新增文件。
|
||||
2. `engine` 代码只能引用,禁止修改。
|
||||
3. 图形抽象层只能使用现有 `engine` 提供的 `RHI` 接口。
|
||||
4. 本轮目标是先把 3DGS 的最小可行系统跑通,而不是把它正式并入引擎主线。
|
||||
5. 本轮明确不引入 `chunk` 机制。
|
||||
|
||||
因此,这份计划不是“继续修补引擎内已有的 GaussianSplat 路径”,而是“在 MVS 目录内重新搭一条干净的、可验证的、无 chunk 的 3DGS-D3D12 最小链路”。
|
||||
|
||||
## 2. 参考实现与职责拆分
|
||||
|
||||
本轮只参考两条现有实现,各自承担不同职责:
|
||||
|
||||
### 2.1 `mvs/3DGS Unity Renderer`
|
||||
|
||||
用途:
|
||||
|
||||
1. 参考 `.ply` 的读取方式。
|
||||
2. 参考如何从 PLY 属性中提取 3DGS 所需原始数据。
|
||||
3. 参考资源准备阶段的数据布局与字段含义。
|
||||
|
||||
注意:
|
||||
|
||||
1. 这里只借鉴导入与数据准备思路。
|
||||
2. 不照搬 Unity Editor 资产工作流。
|
||||
3. 不引入 chunk。
|
||||
|
||||
### 2.2 `mvs/3DGS-Unity`
|
||||
|
||||
用途:
|
||||
|
||||
1. 参考“干净的无 chunk 渲染路径”。
|
||||
2. 参考 `prepare -> sort -> draw -> composite` 的最小闭环。
|
||||
3. 参考 3DGS 在屏幕空间椭圆展开、混合与合成时的核心着色器语义。
|
||||
|
||||
注意:
|
||||
|
||||
1. 这里重点参考渲染过程,而不是 Unity 的宿主框架。
|
||||
2. 不把 Unity 的 `ScriptableRenderPass`、资产导入器、Inspector 等编辑器逻辑带入本轮实现。
|
||||
|
||||
## 3. 首轮目标
|
||||
|
||||
首轮只完成以下闭环:
|
||||
|
||||
1. 在 `mvs/3DGS-D3D12` 内部加载 `room.ply`。
|
||||
2. 将 PLY 中的高斯数据转换为无 chunk 的运行时缓冲。
|
||||
3. 通过现有 `RHI` 完成 D3D12 路径下的最小渲染。
|
||||
4. 输出一张稳定可观察的结果图,证明房间场景已经被正确绘制。
|
||||
|
||||
首轮验收标准:
|
||||
|
||||
1. 程序能独立编译与运行。
|
||||
2. 不依赖修改 `engine` 才能成立。
|
||||
3. 渲染结果不再是纯黑、纯白或明显错误的撕裂图。
|
||||
4. 渲染链路中不存在任何 chunk 数据结构、chunk 缓冲或 chunk 可见性阶段。
|
||||
|
||||
## 4. 非目标
|
||||
|
||||
本轮明确不做:
|
||||
|
||||
1. 不并入 editor。
|
||||
2. 不接入引擎现有 Renderer 主线。
|
||||
3. 不做 OpenGL / Vulkan 多后端对齐。
|
||||
4. 不做正式资源缓存格式。
|
||||
5. 不做 chunk、cluster、LOD、streaming 等优化层。
|
||||
6. 不做 compute 之外的额外架构扩展。
|
||||
7. 不为迎合当前 MVS 去修改 `engine` 的 `RHI`、Renderer、Resources。
|
||||
|
||||
## 5. 约束与执行原则
|
||||
|
||||
### 5.1 目录约束
|
||||
|
||||
本轮新增内容应尽量收敛在 `mvs/3DGS-D3D12` 内,例如:
|
||||
|
||||
1. `src/`:程序入口、渲染器、相机、数据上传。
|
||||
2. `include/`:本地头文件。
|
||||
3. `shaders/`:本地 HLSL 或中间 shader 资源。
|
||||
4. `assets/`:本地测试资源或生成物描述。
|
||||
5. `third_party/`:仅当 MVS 自己确实需要额外小型依赖时使用。
|
||||
|
||||
### 5.2 RHI 使用原则
|
||||
|
||||
1. 只调用现有 `engine` 的 `RHI` 公共接口。
|
||||
2. 如果发现最小系统缺失某项能力,优先在 MVS 内通过更简单的组织方式规避。
|
||||
3. 若确实被 `RHI` 能力边界阻塞,先记录问题并汇报,不允许直接改 `engine`。
|
||||
|
||||
### 5.3 数据路径原则
|
||||
|
||||
1. 整个系统只保留 positions、other、color、SH 等无 chunk 基础数据。
|
||||
2. 不生成 chunk header。
|
||||
3. 不上传 chunk buffer。
|
||||
4. 不做 visible chunk 标记。
|
||||
5. 不保留任何为了兼容旧 chunk 方案而加的临时分支。
|
||||
|
||||
## 6. 技术路线
|
||||
|
||||
### Phase 1:梳理 3DGS-D3D12 的骨架与构建入口
|
||||
|
||||
目标:
|
||||
|
||||
1. 确认 `mvs/3DGS-D3D12` 当前是否只有 `room.ply`。
|
||||
2. 建立最小的可执行工程骨架。
|
||||
3. 打通对 `engine` 中 `RHI` 的引用与链接。
|
||||
|
||||
任务:
|
||||
|
||||
1. 规划 `CMakeLists.txt` 与目录结构。
|
||||
2. 建立窗口、设备、交换链、命令提交、离屏或在屏渲染的最小入口。
|
||||
3. 跑通一个“清屏可显示”的基础版本。
|
||||
|
||||
验收:
|
||||
|
||||
1. `3DGS-D3D12` 可独立编译。
|
||||
2. 程序能启动并输出基础画面。
|
||||
|
||||
### Phase 2:实现无 chunk 的 PLY 读取与运行时数据打包
|
||||
|
||||
目标:
|
||||
|
||||
1. 参考 `mvs/3DGS Unity Renderer`,在 MVS 内部完成 PLY 读取。
|
||||
2. 输出适合渲染阶段直接上传的高斯原始数组。
|
||||
|
||||
任务:
|
||||
|
||||
1. 解析 PLY header 与顶点属性。
|
||||
2. 提取 position、rotation、scale、opacity、color/SH 等字段。
|
||||
3. 明确字段的排列顺序、类型与归一化方式。
|
||||
4. 生成 MVS 本地 `GaussianSplatSceneData`。
|
||||
|
||||
验收:
|
||||
|
||||
1. `room.ply` 可被成功读取。
|
||||
2. 点数量、字段长度、边界盒等基础统计合理。
|
||||
3. 整条导入链中完全没有 chunk 概念。
|
||||
|
||||
### Phase 3:对齐无 chunk 的 GPU 数据布局与上传
|
||||
|
||||
目标:
|
||||
|
||||
1. 把导入结果上传到 GPU。
|
||||
2. 数据布局尽量贴近 `mvs/3DGS-Unity` 的渲染输入。
|
||||
|
||||
任务:
|
||||
|
||||
1. 设计 positions / other / color / SH 的 GPU buffer。
|
||||
2. 建立与着色器绑定一致的 SRV/UAV 视图。
|
||||
3. 为排序与绘制准备 index、distance、view-data 等工作缓冲。
|
||||
|
||||
验收:
|
||||
|
||||
1. GPU 侧所有关键缓冲都能正确创建。
|
||||
2. 每个绑定槽位与 shader 语义一一对应。
|
||||
3. 不包含 chunk buffer / visible chunk buffer。
|
||||
|
||||
### Phase 4:先打通 prepare 与 sort
|
||||
|
||||
目标:
|
||||
|
||||
1. 先验证“高斯数据被相机看到并被正确排序”。
|
||||
2. 在 draw 之前把中间结果可视化或可检查化。
|
||||
|
||||
任务:
|
||||
|
||||
1. 参考 `mvs/3DGS-Unity` 的 prepare 语义,计算每个 splat 的 view-space 信息。
|
||||
2. 生成排序距离。
|
||||
3. 跑通最小排序路径。
|
||||
4. 必要时增加调试输出,用于检查 order / distance / 计数是否异常。
|
||||
|
||||
验收:
|
||||
|
||||
1. prepare 结果不是全零或明显错误。
|
||||
2. sort 输出索引顺序稳定。
|
||||
|
||||
### Phase 5:对齐 draw 与 composite
|
||||
|
||||
目标:
|
||||
|
||||
1. 参考 `mvs/3DGS-Unity` 的“干净无 chunk 渲染路径”把核心画面先画出来。
|
||||
|
||||
任务:
|
||||
|
||||
1. 对齐 Gaussian splat draw shader 的主要输入输出语义。
|
||||
2. 对齐椭圆展开、覆盖范围与透明混合约定。
|
||||
3. 建立 accumulation target。
|
||||
4. 建立 composite pass,把 accumulation 结果合回最终颜色。
|
||||
|
||||
验收:
|
||||
|
||||
1. 输出图中能看出 `room.ply` 对应的房间结构。
|
||||
2. 不出现整屏纯黑、纯白、随机撕裂。
|
||||
|
||||
### Phase 6:收口与验证
|
||||
|
||||
目标:
|
||||
|
||||
1. 固化最小系统结果,形成稳定基线。
|
||||
|
||||
任务:
|
||||
|
||||
1. 规范运行命令与资源路径。
|
||||
2. 输出一张固定命名的结果图作为检查基线。
|
||||
3. 清理调试残留与临时分支。
|
||||
4. 补一份 MVS 内局部说明文档。
|
||||
|
||||
验收:
|
||||
|
||||
1. 代码、资源、着色器都收敛在 `mvs/3DGS-D3D12`。
|
||||
2. 运行方式清晰。
|
||||
3. 基线截图稳定。
|
||||
|
||||
## 7. 关键风险
|
||||
|
||||
### 7.1 PLY 属性语义与当前样例不一致
|
||||
|
||||
如果 `room.ply` 的字段命名、顺序或编码方式与参考加载器假设不一致,最先要修的是导入器映射,不是渲染器。
|
||||
|
||||
### 7.2 RHI 能力与参考实现存在接口差
|
||||
|
||||
如果 Unity 参考依赖的某些资源绑定或 compute 流程不能直接一比一照搬,本轮优先在 `mvs/3DGS-D3D12` 内部重排执行方式,而不是去动 `engine`。
|
||||
|
||||
### 7.3 排序与混合契约不一致
|
||||
|
||||
3DGS 最容易出错的不是“有没有画出来”,而是排序方向、alpha 累积与 composite 契约是否一致。本轮必须把这三者当成同一个问题处理,禁止分开打补丁。
|
||||
|
||||
## 8. 本轮完成后的下一步
|
||||
|
||||
当 `mvs/3DGS-D3D12` 的无 chunk 最小系统跑通后,下一步才有意义讨论:
|
||||
|
||||
1. 是否把这条路径收编进引擎正式 Renderer。
|
||||
2. 是否把 PLY 导入升级成正式资源导入器。
|
||||
3. 是否在引擎层补 structured buffer / compute / renderer pass 抽象。
|
||||
4. 是否接入 editor 与资产缓存。
|
||||
|
||||
在这之前,所有工作都应服务于一个目标:
|
||||
|
||||
先在 `mvs/3DGS-D3D12` 内证明“无 chunk 的 3DGS-D3D12 + 现有 RHI”这条路是通的。
|
||||
@@ -1,75 +0,0 @@
|
||||
# API文档增量回归并行任务板(2026-04-10,晚间)
|
||||
|
||||
## 当前基线
|
||||
|
||||
- 截至 `2026-04-10` 晚间,`python -B docs/api/_tools/audit_api_docs.py` 已恢复全绿:
|
||||
- `Invalid header refs = 0`
|
||||
- `Invalid source refs = 0`
|
||||
- `Broken .md links = 0`
|
||||
- `Missing directory index pages = 0`
|
||||
- 最近已经收口并推送的高频变动区包括:
|
||||
- `RHI`:`CreateBuffer(...)` 初始数据重载、`SetSampleQuality`
|
||||
- `Rendering`:`RenderSurface`、`RenderPassContext`、`BuiltinFinalColorPass`、`BuiltinColorScalePostProcessPass`、`BuiltinInfiniteGridPass`
|
||||
- `Rendering/Passes`:`BuiltinObjectIdPass`、`BuiltinObjectIdOutlinePass`、`BuiltinSelectionOutlinePass`、`BuiltinVolumetricPass`
|
||||
- `UI/Resources`:`UISelectionModel`、`Resources.h` umbrella 页
|
||||
- 当前主问题已经从“大面积补缺页”转成“增量语义回归 + 历史空目录清理 + 任务板状态同步”。
|
||||
|
||||
## 并行认领规则
|
||||
|
||||
- 一个任务块只允许一个会话认领。
|
||||
- 每个任务块必须同时处理:
|
||||
- 目标页
|
||||
- 所属模块索引页
|
||||
- 相关交叉链接
|
||||
- 删除任何目录或历史页前,先执行:
|
||||
- `rg -n "<名称>" docs/api docs/plan docs/used`
|
||||
- 每完成一个任务块后都要执行:
|
||||
- `python -B docs/api/_tools/audit_api_docs.py`
|
||||
- 每完成一个阶段都要立即:
|
||||
- `git commit`
|
||||
- `git push`
|
||||
|
||||
## 当前并发热点
|
||||
|
||||
以下代码区域仍在持续波动,认领相关文档时默认按 `high-risk` 处理:
|
||||
|
||||
- `editor/src/Viewport/**`
|
||||
- `engine/include/XCEngine/Rendering/Passes/**`
|
||||
- `engine/include/XCEngine/Rendering/Planning/**`
|
||||
- `engine/src/Rendering/Caches/**`
|
||||
- `new_editor/include/XCEditor/**`
|
||||
|
||||
## 并行任务块
|
||||
|
||||
| ID | 范围 | 目标改动 | 主要路径 | 风险 | 状态 | 备注 |
|
||||
|----|------|----------|----------|------|------|------|
|
||||
| `N1` | Canonical 历史空目录清理 | 复核并清理已确认无源码对应、且无文档反向引用的历史空目录 / 空入口 | `docs/api/XCEngine/**` | `medium` | `pending` | 优先接旧任务板里的 `S9 / G1` 收尾 |
|
||||
| `N2` | Rendering / Planning & Caches 增量回归 | 对齐 `CameraRenderRequest`、`SceneRenderer`、`FullscreenPassSurfaceCache`、`RenderResourceCache` 在 `sourceSurface` / `sourceColorState` / sample desc 上的新语义 | `docs/api/XCEngine/Rendering/Planning/**`, `docs/api/XCEngine/Rendering/Caches/**` | `high-risk` | `pending` | 适合拆成 1 个小提交 |
|
||||
| `N3` | Editor / Viewport 增量回归 | 对齐 `SceneViewportSelectionOutlinePass`、overlay builder / hit tester / resource paths 等近期重构后的 API 说明 | `docs/api/XCEngine/Editor/Viewport/**`, `editor/src/Viewport/**` | `high-risk` | `pending` | 当前最容易和别的会话冲突 |
|
||||
| `N4` | XCEditor / new_editor 壳层回归 | 检查 `Collections`、`Shell` 下近期重构的 dock host / panel frame / viewport slot / tab strip 文档是否仍匹配真实接口 | `docs/api/XCEditor/**`, `new_editor/include/XCEditor/**` | `high-risk` | `pending` | 适合单独开一个高上下文会话 |
|
||||
| `N5` | Core/Asset 与 Resources 入口复核 | 复核 `AssetDatabase`、`ResourceManager`、`Resources`、`Model`、`GaussianSplat`、`Volume` 入口页的模块级口径是否一致 | `docs/api/XCEngine/Core/Asset/**`, `docs/api/XCEngine/Resources/**` | `medium` | `pending` | 低冲突,适合并行 |
|
||||
| `N6` | 最终状态回写 | 在本轮增量收口后更新 `rebuild-status`、任务板状态和必要的归档链接 | `docs/api/_meta/rebuild-status.md`, `docs/plan/**`, `docs/used/**` | `low` | `pending` | 必须最后做 |
|
||||
|
||||
## 推荐顺序
|
||||
|
||||
1. `N2`
|
||||
2. `N5`
|
||||
3. `N4`
|
||||
4. `N3`
|
||||
5. `N1`
|
||||
6. `N6`
|
||||
|
||||
## 验收口径
|
||||
|
||||
- 文档描述必须以当前工作树源码为准,不沿用旧目录结构或旧后端限定说法。
|
||||
- 不允许把“补充说明”叠在已经过时的主体段落上;发现旧段落和新行为冲突时,应直接重写主体页。
|
||||
- 新增或改写后的页要优先保证:
|
||||
- 公开签名正确
|
||||
- 生命周期 / 状态切换语义正确
|
||||
- 真实调用链或测试锚点可追溯
|
||||
- 最终仍需保持审计全绿。
|
||||
|
||||
## 备注
|
||||
|
||||
- 旧任务板可继续作为历史依据参考,但新的增量认领统一以本文件为准。
|
||||
- 如果执行过程中又有别的会话提前提交了同一批文档,先检查 `git log --oneline -n 6`,确认是否已经收口,再决定是否继续接下一块。
|
||||
@@ -1,101 +0,0 @@
|
||||
# API 文档目录结构第二轮并行任务板(2026-04-09)
|
||||
|
||||
## 使用规则
|
||||
|
||||
- 每个任务块只允许一个会话领取。
|
||||
- 每个任务块必须同时处理:主页面、所属索引页、交叉链接。
|
||||
- 每完成一个任务块所在阶段,都要先审计,再提交推送。
|
||||
- 如果任务路径命中当前并发热点,先不要直接改。
|
||||
|
||||
## 当前并发热点
|
||||
|
||||
以下源码区域当前已有并发修改,相关文档任务默认标记为 `high-risk`:
|
||||
|
||||
- `editor/src/Viewport/**`
|
||||
- `engine/include/XCEngine/RHI/**`
|
||||
- `engine/include/XCEngine/Rendering/Passes/**`
|
||||
- `engine/include/XCEngine/Rendering/Materials/RenderMaterialResolve.h`
|
||||
- `engine/include/XCEngine/UI/Widgets/UISelectionModel.h`
|
||||
- `engine/include/XCEngine/UI/Widgets/UIDragDropInteraction.h`
|
||||
|
||||
## 任务块
|
||||
|
||||
| ID | 范围 | 目标改动 | 主要路径 | 风险 | 状态 | 领取人 |
|
||||
|----|------|----------|----------|------|------|--------|
|
||||
| `R1` | Rendering / 重复目录归位 | 把旧顶层 `CameraRenderer`、`SceneRenderer`、`CameraRenderRequest`、`SceneRenderRequestPlanner`、`SceneRenderRequestUtils`、`RenderCameraData`、`RenderResourceCache`、`RenderSceneExtractor`、`RenderSceneUtility` 合并到真实子模块位置 | `docs/api/XCEngine/Rendering/**` | `medium` | `completed` | 当前会话 |
|
||||
| `R2` | Rendering / 旧命名残留审计 | 处理 `ObjectIdEncoding`、`ObjectIdPass`、`RenderMaterialUtility`、`VisibleRenderObject`,判定迁移到哪里或删除 | `docs/api/XCEngine/Rendering/**` | `medium` | `completed` | 当前会话 |
|
||||
| `E1` | Editor / 历史失效页清理 | 移除 `XCUIDemoPanel` canonical 页面,修正 `panels.md`、`ImGuiTransitionBackend.md` 等反向链接 | `docs/api/XCEngine/Editor/panels/**` | `low` | `completed` | 当前会话 |
|
||||
| `V1` | Resources / Volume | 建立 `Volume.md`、`VolumeField.md`、`VolumeFieldLoader.md`,同步 `Resources.md` | `docs/api/XCEngine/Resources/Volume/**` | `low` | `completed` | 当前会话 |
|
||||
| `V2` | Components / Volume | 建立 `VolumeRendererComponent.md`,同步 `Components.md` | `docs/api/XCEngine/Components/VolumeRendererComponent/**` | `low` | `completed` | 当前会话 |
|
||||
| `V3` | Rendering / Volume FrameData | 建立 `VisibleVolumeItem.md`,同步 `FrameData.md` | `docs/api/XCEngine/Rendering/FrameData/**` | `low` | `completed` | 当前会话 |
|
||||
| `V4` | Rendering / Volume & Selection Passes | 建立 `BuiltinSelectionMaskPass.md`、`BuiltinSelectionOutlinePass.md`、`BuiltinVolumetricPass.md`,同步 `Passes.md` | `docs/api/XCEngine/Rendering/Passes/**` | `high-risk` | `completed` | 当前会话 |
|
||||
| `U1` | UI / Widgets Helpers | 建立 `UIDragDropInteraction.md`、`UIScrollModel.md`,同步 `Widgets.md` | `docs/api/XCEngine/UI/Widgets/**` | `high-risk` | `completed` | 当前会话 |
|
||||
| `ED1` | Editor / ComponentEditors | 建立 `VolumeRendererComponentEditor.md`,同步 `ComponentEditors.md` | `docs/api/XCEngine/Editor/ComponentEditors/**` | `low` | `completed` | 当前会话 |
|
||||
| `ED2` | Editor / panels Material Authoring | 建立 `MaterialInspectorMaterialState.md`、`MaterialInspectorMaterialStateIO.md`,同步 `panels.md` | `docs/api/XCEngine/Editor/panels/**` | `low` | `completed` | 当前会话 |
|
||||
| `RR1` | RHI 内容回归 | 根据当前真实头文件更新 `RHI*`、`D3D12`、`OpenGL`、`Vulkan` 文档内容与结构 | `docs/api/XCEngine/RHI/**` | `high-risk` | `completed` | 当前会话 |
|
||||
| `RR2` | Rendering / Passes 内容回归 | 根据当前修改中的 builtin pass 头文件更新文档内容与链接 | `docs/api/XCEngine/Rendering/Passes/**` | `high-risk` | `completed` | 当前会话 |
|
||||
| `RR3` | Rendering / Materials 内容回归 | 把 `RenderMaterialResolve` 相关文档与当前头文件重新对齐 | `docs/api/XCEngine/Rendering/Materials/**` | `high-risk` | `completed` | 当前会话 |
|
||||
| `G1` | 全量审计与空目录清理 | 跑审计、清空旧重复目录、清理空目录与错链 | `docs/api/_meta/**`, `docs/api/XCEngine/**` | `medium` | `pending` | |
|
||||
|
||||
## 最新进度
|
||||
|
||||
- 截至 `2026-04-10 18:36`,`docs/api/_tools/audit_api_docs.py` 审计已全绿:
|
||||
- `Invalid header refs = 0`
|
||||
- `Invalid source refs = 0`
|
||||
- `Broken .md links = 0`
|
||||
- `Missing directory index pages = 0`
|
||||
- 当前第二轮任务板里真正剩余的结构性收口项主要是 `G1`,即历史空目录与重复目录的继续清理。
|
||||
|
||||
## 推荐阶段顺序
|
||||
|
||||
### 第一阶段
|
||||
|
||||
- `R1`
|
||||
- `R2`
|
||||
- `E1`
|
||||
|
||||
这一阶段的目标是先把“结构错位”和“失效历史页”清掉。
|
||||
|
||||
### 第二阶段
|
||||
|
||||
- `V1`
|
||||
- `V2`
|
||||
- `V3`
|
||||
- `ED1`
|
||||
- `ED2`
|
||||
|
||||
这一阶段优先补低冲突、可快速收口的缺页。
|
||||
|
||||
### 第三阶段
|
||||
|
||||
- `V4`
|
||||
- `U1`
|
||||
- `RR1`
|
||||
- `RR2`
|
||||
- `RR3`
|
||||
|
||||
这一阶段等源码波动收敛后再做。
|
||||
|
||||
### 第四阶段
|
||||
|
||||
- `G1`
|
||||
|
||||
## 验收口径
|
||||
|
||||
### 结构验收
|
||||
|
||||
- 每个 API 只保留一个 canonical 目录位置。
|
||||
- 文档目录层级必须与真实源码父目录一致。
|
||||
- 不再允许顶层旧路径和子模块新路径并存。
|
||||
|
||||
### 审计验收
|
||||
|
||||
- `Invalid header refs = 0`
|
||||
- `Invalid source refs = 0`
|
||||
- `Broken .md links = 0`
|
||||
- `Missing directory index pages = 0`
|
||||
|
||||
### 协作验收
|
||||
|
||||
- 每个阶段完成后立即提交推送。
|
||||
- 任务板状态同步更新,避免重复领取。
|
||||
@@ -1,227 +0,0 @@
|
||||
# API 文档目录结构第二轮重构计划
|
||||
|
||||
## 1. 背景
|
||||
|
||||
项目最近又经历了一轮较大的源码重构,`docs/api/XCEngine` 当前虽然顶层大类仍然存在,但内部已经出现了两类更严重的问题:
|
||||
|
||||
- 目录层级错位:文档页名字还对,但挂在了错误的父目录下。
|
||||
- 新旧结构并存:旧位置和新位置同时保留,导致同一 API 在文档树里出现两套入口。
|
||||
|
||||
这轮重构不再是简单补页,而是要把 `docs/api` 再次拉回到“与实际源码模块结构平行”的状态。
|
||||
|
||||
## 2. 本轮核对基准
|
||||
|
||||
本轮计划基于以下真实代码树做对照:
|
||||
|
||||
- 运行时 public headers:`engine/include/XCEngine/**`
|
||||
- 旧版编辑器 source-backed API:`editor/src/**`
|
||||
- 当前文档树:`docs/api/XCEngine/**`
|
||||
|
||||
同时参考了最新本地审计结果:
|
||||
|
||||
- `python -B docs/api/_tools/audit_api_docs.py`
|
||||
|
||||
## 2.1 2026-04-10 状态更新
|
||||
|
||||
截至 `2026-04-10 17:07:09`,这份计划里最核心的阶段性目标已经完成:
|
||||
|
||||
- `XCUIDemoPanel` 已从 canonical 树移除,相关活跃反向链接已清理
|
||||
- `Rendering` 旧错位目录与 stale-token 路径已完成一轮归位/回归
|
||||
- `Volume / Selection / UI helper / Editor helper` 缺页已补齐
|
||||
- `docs/api/XCEditor/**`、`Resources/Model/**`、`Resources/GaussianSplat/**` 已进入 canonical 树
|
||||
- 审计当前全绿:
|
||||
- `Invalid header refs = 0`
|
||||
- `Invalid source refs = 0`
|
||||
- `Broken .md links = 0`
|
||||
- `Missing directory index pages = 0`
|
||||
|
||||
因此下文第 `3` 节保留的是“本轮原始发现快照”,不是当前仍未处理的实时状态。
|
||||
|
||||
## 3. 已确认的结构性问题
|
||||
|
||||
### 3.1 Rendering 存在成对重复目录
|
||||
|
||||
当前已确认以下目录同时出现在“旧顶层位置”和“源码对应的新子模块位置”:
|
||||
|
||||
- `docs/api/XCEngine/Rendering/CameraRenderer`
|
||||
- `docs/api/XCEngine/Rendering/Execution/CameraRenderer`
|
||||
- `docs/api/XCEngine/Rendering/SceneRenderer`
|
||||
- `docs/api/XCEngine/Rendering/Execution/SceneRenderer`
|
||||
- `docs/api/XCEngine/Rendering/CameraRenderRequest`
|
||||
- `docs/api/XCEngine/Rendering/Planning/CameraRenderRequest`
|
||||
- `docs/api/XCEngine/Rendering/SceneRenderRequestPlanner`
|
||||
- `docs/api/XCEngine/Rendering/Planning/SceneRenderRequestPlanner`
|
||||
- `docs/api/XCEngine/Rendering/SceneRenderRequestUtils`
|
||||
- `docs/api/XCEngine/Rendering/Planning/SceneRenderRequestUtils`
|
||||
- `docs/api/XCEngine/Rendering/RenderCameraData`
|
||||
- `docs/api/XCEngine/Rendering/FrameData/RenderCameraData`
|
||||
- `docs/api/XCEngine/Rendering/RenderResourceCache`
|
||||
- `docs/api/XCEngine/Rendering/Caches/RenderResourceCache`
|
||||
- `docs/api/XCEngine/Rendering/RenderSceneExtractor`
|
||||
- `docs/api/XCEngine/Rendering/Extraction/RenderSceneExtractor`
|
||||
- `docs/api/XCEngine/Rendering/RenderSceneUtility`
|
||||
- `docs/api/XCEngine/Rendering/Extraction/RenderSceneUtility`
|
||||
|
||||
这说明文档树里同时保留了“旧的平铺布局”和“新的源码子模块布局”。后续必须只保留源码对应路径,旧路径下的内容要迁移或删除,不能继续并存。
|
||||
|
||||
### 3.2 Rendering 还有一批疑似旧命名/旧抽象残留
|
||||
|
||||
当前已确认下列目录没有直接对应到当前真实头文件命名,属于优先审计对象:
|
||||
|
||||
- `docs/api/XCEngine/Rendering/ObjectIdEncoding`
|
||||
- `docs/api/XCEngine/Rendering/ObjectIdPass`
|
||||
- `docs/api/XCEngine/Rendering/RenderMaterialUtility`
|
||||
- `docs/api/XCEngine/Rendering/VisibleRenderObject`
|
||||
|
||||
这些目录大概率分别对应:
|
||||
|
||||
- 已下沉或改名后的 `Picking/ObjectIdCodec`
|
||||
- `Passes/BuiltinObjectIdPass`
|
||||
- `Materials/RenderMaterialResolve`
|
||||
- `FrameData/VisibleRenderItem`
|
||||
|
||||
但不能直接机械删除,必须先做“旧页内容是否需要迁移”的核对。
|
||||
|
||||
### 3.3 Editor 仍保留已脱离源码的历史页
|
||||
|
||||
当前已确认:
|
||||
|
||||
- `docs/api/XCEngine/Editor/panels/XCUIDemoPanel/XCUIDemoPanel.md`
|
||||
|
||||
对应源码:
|
||||
|
||||
- `editor/src/panels/XCUIDemoPanel.h`
|
||||
- `editor/src/panels/XCUIDemoPanel.cpp`
|
||||
|
||||
这两个文件都已经不存在。
|
||||
|
||||
当前仍引用该历史页的文档包括:
|
||||
|
||||
- `docs/api/XCEngine/Editor/panels/panels.md`
|
||||
- `docs/api/XCEngine/Editor/XCUIBackend/ImGuiTransitionBackend/ImGuiTransitionBackend.md`
|
||||
|
||||
`docs/api/XCEngine/UI/DrawData/DrawData.md` 里已经改成“旧链路说明”,这类描述可以保留,但不应该继续把 `XCUIDemoPanel` 作为真实 canonical API 页面入口。
|
||||
|
||||
### 3.4 审计明确缺页仍然存在
|
||||
|
||||
最新审计仍明确指出以下缺口需要补齐:
|
||||
|
||||
- `XCEngine/Components/VolumeRendererComponent.h`
|
||||
- `XCEngine/Rendering/FrameData/VisibleVolumeItem.h`
|
||||
- `XCEngine/Rendering/Passes/BuiltinSelectionMaskPass.h`
|
||||
- `XCEngine/Rendering/Passes/BuiltinSelectionOutlinePass.h`
|
||||
- `XCEngine/Rendering/Passes/BuiltinVolumetricPass.h`
|
||||
- `XCEngine/Resources/Volume/VolumeField.h`
|
||||
- `XCEngine/Resources/Volume/VolumeFieldLoader.h`
|
||||
- `XCEngine/UI/Widgets/UIDragDropInteraction.h`
|
||||
- `XCEngine/UI/Widgets/UIScrollModel.h`
|
||||
- `editor/src/ComponentEditors/VolumeRendererComponentEditor.h`
|
||||
- `editor/src/panels/MaterialInspectorMaterialState.h`
|
||||
- `editor/src/panels/MaterialInspectorMaterialStateIO.h`
|
||||
|
||||
同时还缺少:
|
||||
|
||||
- `docs/api/XCEngine/Resources/Volume/Volume.md`
|
||||
|
||||
### 3.5 当前存在并发修改热点
|
||||
|
||||
当前工作区里已有其他会话在修改以下源码区域,对应文档重构要么延后,要么单独协调:
|
||||
|
||||
- `editor/src/Viewport/**`
|
||||
- `engine/include/XCEngine/RHI/**`
|
||||
- `engine/include/XCEngine/Rendering/Passes/**`
|
||||
- `engine/include/XCEngine/Rendering/Materials/RenderMaterialResolve.h`
|
||||
- `engine/include/XCEngine/UI/Widgets/UISelectionModel.h`
|
||||
- `engine/include/XCEngine/UI/Widgets/UIDragDropInteraction.h`
|
||||
|
||||
因此本轮执行要按“低冲突优先”组织阶段,避免多个会话同时改同一批文档。
|
||||
|
||||
## 4. 本轮目标
|
||||
|
||||
### 4.1 结构目标
|
||||
|
||||
- `docs/api/XCEngine/**` 内每一个类/模块页都必须与当前真实源码路径平行。
|
||||
- 同一 API 只能保留一个 canonical 位置。
|
||||
- 旧的错位目录必须迁移或移除,不能继续保留作第二入口。
|
||||
|
||||
### 4.2 内容目标
|
||||
|
||||
- 在结构对齐完成后,再逐批做内容重构。
|
||||
- 内容必须基于当前源码与测试,而不是沿用旧说明。
|
||||
|
||||
### 4.3 协作目标
|
||||
|
||||
- 每一批任务都要能被多个会话独立领取。
|
||||
- 每一阶段结束后立即提交并推送,避免长时间悬空。
|
||||
|
||||
## 5. 分阶段执行
|
||||
|
||||
## Phase A:建立新计划与任务板
|
||||
|
||||
- 新开第二轮计划文件
|
||||
- 新开第二轮并行任务板
|
||||
- 标清“当前确定的问题”和“并发风险路径”
|
||||
|
||||
## Phase B:清理已确认的失效历史页
|
||||
|
||||
- 处理 `XCUIDemoPanel`
|
||||
- 修复所有反向链接
|
||||
- 让 `Invalid source refs` 归零
|
||||
|
||||
## Phase C:Rendering 目录结构归位
|
||||
|
||||
- 把所有错位的顶层 Rendering 目录迁移到真实子模块
|
||||
- 合并旧目录里的方法页/细页到正确的新位置
|
||||
- 删除旧顶层重复入口
|
||||
|
||||
## Phase D:补齐审计明确缺页
|
||||
|
||||
- `Resources/Volume`
|
||||
- `Components/VolumeRendererComponent`
|
||||
- `Rendering/VisibleVolumeItem`
|
||||
- `Rendering` 的体积/选择 pass
|
||||
- `UI/Widgets` 新 helper
|
||||
- `Editor` 的体积组件编辑器与材质状态页
|
||||
|
||||
## Phase E:高风险模块内容回归
|
||||
|
||||
在相关源码停止波动后,再处理:
|
||||
|
||||
- `RHI`
|
||||
- `Rendering/Passes`
|
||||
- `Rendering/Materials`
|
||||
- `Editor/Viewport`
|
||||
- `UI/Widgets`
|
||||
|
||||
## Phase F:总回归
|
||||
|
||||
- 全量跑审计
|
||||
- 清理空目录、错链、旧入口
|
||||
- 更新阶段状态并准备下一轮内容重构
|
||||
|
||||
## 6. 本轮优先级判断
|
||||
|
||||
当前最优先的不是继续写新内容,而是先把“错层级”和“重复入口”消掉。否则后面无论哪个会话补文档,都有较高概率继续写到旧路径。
|
||||
|
||||
因此第二轮的第一主战场是:
|
||||
|
||||
- `docs/api/XCEngine/Rendering`
|
||||
|
||||
第二主战场是:
|
||||
|
||||
- `docs/api/XCEngine/Editor` 中仍脱离真实源码的历史页
|
||||
|
||||
第三主战场才是:
|
||||
|
||||
- 审计明确缺页的 Volume / UI / Editor 补齐
|
||||
|
||||
## 7. 阶段收口要求
|
||||
|
||||
每完成一个阶段,必须执行:
|
||||
|
||||
1. 本地核对改动范围
|
||||
2. `python -B docs/api/_tools/audit_api_docs.py`
|
||||
3. `git commit`
|
||||
4. `git push`
|
||||
|
||||
只有在上一阶段已经提交推送后,才进入下一阶段。
|
||||
@@ -1,155 +0,0 @@
|
||||
# API 文档目录结构重大重构并行任务板(2026-04-09)
|
||||
|
||||
## 背景
|
||||
|
||||
项目近期经过了大规模重构,`docs/api/XCEngine` 当前 canonical 树已经和实际源码出现新的结构偏差。
|
||||
本任务板用于给多会话 / 多代理并行协作时直接认领任务,避免重复劳动和目录冲突。
|
||||
|
||||
本轮结论来自两类事实源:
|
||||
|
||||
- 源码目录对照:
|
||||
- `engine/include/XCEngine`
|
||||
- `editor/src`
|
||||
- `new_editor/include/XCEditor`
|
||||
- 文档审计:
|
||||
- `python -B docs/api/_tools/audit_api_docs.py`
|
||||
- 最新生成时间:`2026-04-10 17:07:09`
|
||||
|
||||
## 当前关键问题
|
||||
|
||||
### 当前审计状态
|
||||
|
||||
- 当前 `docs/api/XCEngine/**` + `docs/api/XCEditor/**` + `editor/src/**` 范围内审计已经全绿:
|
||||
- `Invalid header refs = 0`
|
||||
- `Invalid source refs = 0`
|
||||
- `Broken .md links = 0`
|
||||
- `Missing directory index pages = 0`
|
||||
- 本轮补页已经覆盖:
|
||||
- `VolumeRendererComponent`
|
||||
- `VisibleVolumeItem`
|
||||
- `BuiltinSelectionMaskPass`
|
||||
- `BuiltinSelectionOutlinePass`
|
||||
- `BuiltinVolumetricPass`
|
||||
- `Volume`
|
||||
- `VolumeField`
|
||||
- `VolumeFieldLoader`
|
||||
- `UIDragDropInteraction`
|
||||
- `UIScrollModel`
|
||||
- `VolumeRendererComponentEditor`
|
||||
- `MaterialInspectorMaterialState`
|
||||
- `MaterialInspectorMaterialStateIO`
|
||||
- 新增 canonical 根树与资源子模块:
|
||||
- `docs/api/XCEditor/**`
|
||||
- `XCEngine/Resources/Model/**`
|
||||
- `XCEngine/Resources/GaussianSplat/**`
|
||||
- `XCUIDemoPanel` 已从 canonical API 树中移除;活跃 overview 只保留当前真实调用点和历史说明。
|
||||
|
||||
### 剩余结构问题
|
||||
|
||||
- `RHI`、`Rendering/Passes`、`Rendering/Materials` 等高风险内容回归任务已经完成,当前审计维持全绿。
|
||||
- 历史空目录与重复目录的进一步清理仍待继续验证,这部分仍对应 `S9`。
|
||||
- 后续重点已经从“大面积补缺页”转成“任务板/入口状态同步 + 空目录收口 + 新增头文件增量同步”。
|
||||
|
||||
### 当前发现的可疑空目录
|
||||
|
||||
以下目录当前为空,优先视为历史迁移残留;删除前需要先 `rg` 检查是否仍有链接引用:
|
||||
|
||||
- `docs/api/XCEngine/Core/Core`
|
||||
- `docs/api/XCEngine/Core/Containers/Containers`
|
||||
- `docs/api/XCEngine/Debug/Debug`
|
||||
- `docs/api/XCEngine/Editor/Viewport/SceneViewportOverlayRenderer`
|
||||
- `docs/api/XCEngine/Rendering/CameraRenderRequest/BuiltinPostProcessRequest`
|
||||
- `docs/api/XCEngine/Rendering/Passes/BuiltinPostProcessPassPlan`
|
||||
- `docs/api/XCEngine/Rendering/Passes/BuiltinPostProcessPassSequenceBuilder`
|
||||
- `docs/api/XCEngine/Resources/Shader/ShaderRenderState`
|
||||
|
||||
说明:
|
||||
|
||||
- `docs/api/XCEngine/Components/VolumeRendererComponent`
|
||||
- `docs/api/XCEngine/Rendering/FrameData/VisibleVolumeItem`
|
||||
- `docs/api/XCEngine/Rendering/Passes/BuiltinSelectionMaskPass`
|
||||
- `docs/api/XCEngine/Rendering/Passes/BuiltinSelectionOutlinePass`
|
||||
- `docs/api/XCEngine/Rendering/Passes/BuiltinVolumetricPass`
|
||||
- `docs/api/XCEngine/Resources/Volume/VolumeField`
|
||||
- `docs/api/XCEngine/Resources/Volume/VolumeFieldLoader`
|
||||
|
||||
这些空目录是本轮结构补齐时创建的目标目录,不属于历史残留,需要补页面而不是删除。
|
||||
|
||||
## 并行认领规则
|
||||
|
||||
- 一个任务块只允许一个会话认领。
|
||||
- 每个任务块必须同时处理:
|
||||
- 主页面
|
||||
- 所在模块索引页
|
||||
- 相关交叉链接
|
||||
- 删除任何目录或页面前,先执行:
|
||||
- `rg -n "<名称>" docs/api/XCEngine docs/api/_guides`
|
||||
- 每个任务块完成后都要执行:
|
||||
- `python -B docs/api/_tools/audit_api_docs.py`
|
||||
|
||||
## 任务块
|
||||
|
||||
| ID | 范围 | 目标改动 | 主要路径 | 状态 | 认领人 |
|
||||
|----|------|----------|----------|------|--------|
|
||||
| `S1` | Resources / Volume | 新建 `Volume.md`、`VolumeField.md`、`VolumeFieldLoader.md`,并更新 `Resources.md` | `docs/api/XCEngine/Resources/Volume/**` | `completed` | 当前会话 |
|
||||
| `S2` | Components / Volume | 新建 `VolumeRendererComponent.md`,并更新 `Components.md` | `docs/api/XCEngine/Components/VolumeRendererComponent/**` | `completed` | 当前会话 |
|
||||
| `S3` | Rendering / Volume FrameData | 新建 `VisibleVolumeItem.md`,并更新 `FrameData.md` | `docs/api/XCEngine/Rendering/FrameData/**` | `completed` | 当前会话 |
|
||||
| `S4` | Rendering / Volume & Selection Passes | 新建 `BuiltinSelectionMaskPass.md`、`BuiltinSelectionOutlinePass.md`、`BuiltinVolumetricPass.md`,并更新 `Passes.md` | `docs/api/XCEngine/Rendering/Passes/**` | `completed` | 当前会话 |
|
||||
| `S5` | UI / Widgets Helpers | 新建 `UIDragDropInteraction.md`、`UIScrollModel.md`,并更新 `Widgets.md` | `docs/api/XCEngine/UI/Widgets/**` | `completed` | 当前会话 |
|
||||
| `S6` | Editor / ComponentEditors | 新建 `VolumeRendererComponentEditor.md`,并更新 `ComponentEditors.md` | `docs/api/XCEngine/Editor/ComponentEditors/**` | `completed` | 当前会话 |
|
||||
| `S7` | Editor / panels Material Authoring | 新建 `MaterialInspectorMaterialState.md`、`MaterialInspectorMaterialStateIO.md`,并更新 `panels.md` | `docs/api/XCEngine/Editor/panels/**` | `completed` | 当前会话 |
|
||||
| `S8` | Editor 旧页清理 | 删除 `XCUIDemoPanel` 旧页与空目录,修正所有反向链接 | `docs/api/XCEngine/Editor/panels/XCUIDemoPanel/**` | `completed` | 当前会话 |
|
||||
| `S9` | Canonical 空目录清理 | 清理历史空目录并验证无死链 | 见“可疑空目录”列表 | `pending` | |
|
||||
| `S10` | 全量回归 | 运行审计,更新状态,补最后的索引 / 链接 / 空目录问题 | `docs/api/_meta/rebuild-status.md` | `completed` | 当前会话 |
|
||||
|
||||
## 各任务块的最低验收标准
|
||||
|
||||
### `S1` - `S7`
|
||||
|
||||
- 目录结构与源码平行。
|
||||
- 每个类型都是“一个文件夹 + 一个同名主页面”。
|
||||
- 页面必须基于当前源码和测试写内容,不能凭旧文档照搬。
|
||||
- 必须同步更新所属模块总览页中的目录列表 / 页面列表。
|
||||
|
||||
### `S8`
|
||||
|
||||
- `XCUIDemoPanel` 页面与目录从 canonical 树中移除。
|
||||
- 所有指向它的链接都替换为当前真实调用点描述,或者直接删除。
|
||||
- 审计中的 `Invalid source refs` 归零。
|
||||
|
||||
### `S9`
|
||||
|
||||
- 只清理已经确认无源码对应、且无链接引用的目录。
|
||||
- 不能误删本轮待补页面目录。
|
||||
|
||||
### `S10`
|
||||
|
||||
- `Invalid header refs = 0`
|
||||
- `Invalid source refs = 0`
|
||||
- `Broken .md links = 0`
|
||||
- `Missing directory index pages = 0`
|
||||
- 缺页计数进一步下降,最好清零
|
||||
|
||||
## 推荐执行顺序
|
||||
|
||||
1. `S8`
|
||||
2. `S1`
|
||||
3. `S2`
|
||||
4. `S3`
|
||||
5. `S4`
|
||||
6. `S5`
|
||||
7. `S6`
|
||||
8. `S7`
|
||||
9. `S9`
|
||||
10. `S10`
|
||||
|
||||
## 备注
|
||||
|
||||
- 当前阶段已经从“补缺页”转为“空目录清理 + 入口状态同步 + 增量回归维护”。
|
||||
- 下一轮优先收口:
|
||||
- `S9` 对应的历史空目录清理
|
||||
- `docs/api/_meta/rebuild-status.md` 的例行审计回写
|
||||
- 后续新增或继续波动的高风险源码路径增量同步:
|
||||
- `engine/include/XCEngine/RHI/**`
|
||||
- `engine/include/XCEngine/Rendering/Passes/**`
|
||||
- `new_editor/include/XCEditor/**`
|
||||
@@ -1,216 +0,0 @@
|
||||
# API 文档目录结构重构并行任务板(第二轮,2026-04-09)
|
||||
|
||||
## 背景
|
||||
|
||||
本轮不是普通补页,而是一次“目录归位 + 失效页清理 + 新模块补平”混合重构。
|
||||
|
||||
## 状态更新(2026-04-10 17:07:09)
|
||||
|
||||
- 当前 `docs/api/XCEngine/**` + `docs/api/XCEditor/**` + `editor/src/**` 审计已经全绿。
|
||||
- `R1` - `R7` 对应的主要结构归位、失效页清理和缺页补齐已经完成。
|
||||
- 当前剩余重点不再是“补 XCEditor / Volume / XCUIDemoPanel”,而是:
|
||||
- `R8` 这类残余结构规范化
|
||||
- 更高风险的 `RHI / Rendering / Editor/Viewport` 内容回归
|
||||
- 历史空目录与重复入口的持续收口
|
||||
|
||||
已确认的事实来源:
|
||||
|
||||
- 本地源码目录对照
|
||||
- `engine/include/XCEngine/**`
|
||||
- `editor/src/**`
|
||||
- 最新审计
|
||||
- `python -B docs/api/_tools/audit_api_docs.py`
|
||||
- 多路 `GPT-5.4 high` 子代理并行审计结论
|
||||
|
||||
## 当前已确认的结构问题(原始发现快照)
|
||||
|
||||
### 1. Rendering 根目录存在明显错位页面
|
||||
|
||||
以下文档目录名是对的,但父目录已经错了,应该先迁回真实源码子模块:
|
||||
|
||||
- `docs/api/XCEngine/Rendering/CameraRenderer`
|
||||
- 实际应对应 `engine/include/XCEngine/Rendering/Execution/CameraRenderer.h`
|
||||
- 目标路径:`docs/api/XCEngine/Rendering/Execution/CameraRenderer`
|
||||
- `docs/api/XCEngine/Rendering/SceneRenderer`
|
||||
- 实际应对应 `engine/include/XCEngine/Rendering/Execution/SceneRenderer.h`
|
||||
- 目标路径:`docs/api/XCEngine/Rendering/Execution/SceneRenderer`
|
||||
- `docs/api/XCEngine/Rendering/CameraRenderRequest`
|
||||
- 实际应对应 `engine/include/XCEngine/Rendering/Planning/CameraRenderRequest.h`
|
||||
- 目标路径:`docs/api/XCEngine/Rendering/Planning/CameraRenderRequest`
|
||||
- `docs/api/XCEngine/Rendering/SceneRenderRequestPlanner`
|
||||
- 实际应对应 `engine/include/XCEngine/Rendering/Planning/SceneRenderRequestPlanner.h`
|
||||
- 目标路径:`docs/api/XCEngine/Rendering/Planning/SceneRenderRequestPlanner`
|
||||
- `docs/api/XCEngine/Rendering/SceneRenderRequestUtils`
|
||||
- 实际应对应 `engine/include/XCEngine/Rendering/Planning/SceneRenderRequestUtils.h`
|
||||
- 目标路径:`docs/api/XCEngine/Rendering/Planning/SceneRenderRequestUtils`
|
||||
- `docs/api/XCEngine/Rendering/RenderSceneExtractor`
|
||||
- 实际应对应 `engine/include/XCEngine/Rendering/Extraction/RenderSceneExtractor.h`
|
||||
- 目标路径:`docs/api/XCEngine/Rendering/Extraction/RenderSceneExtractor`
|
||||
- `docs/api/XCEngine/Rendering/RenderSceneUtility`
|
||||
- 实际应对应 `engine/include/XCEngine/Rendering/Extraction/RenderSceneUtility.h`
|
||||
- 目标路径:`docs/api/XCEngine/Rendering/Extraction/RenderSceneUtility`
|
||||
- `docs/api/XCEngine/Rendering/RenderResourceCache`
|
||||
- 实际应对应 `engine/include/XCEngine/Rendering/Caches/RenderResourceCache.h`
|
||||
- 目标路径:`docs/api/XCEngine/Rendering/Caches/RenderResourceCache`
|
||||
- `docs/api/XCEngine/Rendering/RenderCameraData`
|
||||
- 实际应对应 `engine/include/XCEngine/Rendering/FrameData/RenderCameraData.h`
|
||||
- 目标路径:`docs/api/XCEngine/Rendering/FrameData/RenderCameraData`
|
||||
- `docs/api/XCEngine/Rendering/ObjectIdPass`
|
||||
- 当前属于旧命名
|
||||
- 实际应归入 `docs/api/XCEngine/Rendering/Passes/BuiltinObjectIdPass`
|
||||
|
||||
### 1.1 已确认“正确目录已存在,但错位旧目录仍保留”的重复区
|
||||
|
||||
以下区域不是“目标目录不存在”,而是“新目录已经有页,旧错位目录还没清掉”:
|
||||
|
||||
- `Rendering/CameraRenderer` 与 `Rendering/Execution/CameraRenderer`
|
||||
- `Rendering/SceneRenderer` 与 `Rendering/Execution/SceneRenderer`
|
||||
- `Rendering/RenderSceneExtractor` 与 `Rendering/Extraction/RenderSceneExtractor`
|
||||
- `Rendering/RenderSceneUtility` 与 `Rendering/Extraction/RenderSceneUtility`
|
||||
- `Rendering/RenderResourceCache` 与 `Rendering/Caches/RenderResourceCache`
|
||||
- `Rendering/RenderCameraData` 与 `Rendering/FrameData/RenderCameraData`
|
||||
- `Rendering/CameraRenderRequest` 与 `Rendering/Planning/CameraRenderRequest`
|
||||
- `Rendering/SceneRenderRequestPlanner` 与 `Rendering/Planning/SceneRenderRequestPlanner`
|
||||
- `Rendering/SceneRenderRequestUtils` 与 `Rendering/Planning/SceneRenderRequestUtils`
|
||||
|
||||
### 2. 已经脱离源码现实的失效页
|
||||
|
||||
- `docs/api/XCEngine/Editor/panels/XCUIDemoPanel/XCUIDemoPanel.md`
|
||||
- 当前仍引用不存在的 `editor/src/panels/XCUIDemoPanel.h`
|
||||
- 这是当前审计里唯一明确的失效源文件引用
|
||||
- `docs/api/XCEngine/Editor/Viewport/SceneViewportOverlayRenderer`
|
||||
- 当前 `editor/src/Viewport` 下已无对应头文件
|
||||
- 优先视为待清理历史目录
|
||||
- 以下页面仍引用或延续了这条旧链路:
|
||||
- `docs/api/XCEngine/Editor/panels/panels.md`
|
||||
- `docs/api/XCEngine/Editor/XCUIBackend/ImGuiTransitionBackend/ImGuiTransitionBackend.md`
|
||||
- `docs/api/XCEngine/UI/DrawData/DrawData.md`
|
||||
|
||||
### 3. 旧概念或旧结构残留页
|
||||
|
||||
以下目录需要先做“是否仍有真实源码对应物”的确认,再决定迁移还是删除:
|
||||
|
||||
- `docs/api/XCEngine/Rendering/RenderMaterialUtility`
|
||||
- `docs/api/XCEngine/Rendering/ObjectIdEncoding`
|
||||
- `docs/api/XCEngine/Rendering/VisibleRenderObject`
|
||||
- `docs/api/XCEngine/Rendering/Pipelines/BuiltinForwardPipelineAsset`
|
||||
- `docs/api/XCEngine/Rendering/Passes/ObjectIdOutlineStyle`
|
||||
- `docs/api/XCEngine/Rendering/Passes/BuiltinPostProcessPassPlan`
|
||||
- `docs/api/XCEngine/Rendering/Passes/BuiltinPostProcessPassSequenceBuilder`
|
||||
- `docs/api/XCEngine/Resources/Shader/ShaderRenderState`
|
||||
|
||||
### 4. 本轮新暴露出来的结构缺页
|
||||
|
||||
这些目录现在是真实源码节点,且已经进入主链,应尽快补平:
|
||||
|
||||
- `docs/api/XCEngine/Resources/Volume/Volume`
|
||||
- `docs/api/XCEngine/Resources/Volume/VolumeField`
|
||||
- `docs/api/XCEngine/Resources/Volume/VolumeFieldLoader`
|
||||
- `docs/api/XCEngine/Components/VolumeRendererComponent`
|
||||
- `docs/api/XCEngine/Rendering/FrameData/VisibleVolumeItem`
|
||||
- `docs/api/XCEngine/Rendering/Passes/BuiltinSelectionMaskPass`
|
||||
- `docs/api/XCEngine/Rendering/Passes/BuiltinSelectionOutlinePass`
|
||||
- `docs/api/XCEngine/Rendering/Passes/BuiltinVolumetricPass`
|
||||
- `docs/api/XCEngine/UI/Widgets/UIDragDropInteraction`
|
||||
- `docs/api/XCEngine/UI/Widgets/UIScrollModel`
|
||||
- `docs/api/XCEngine/Editor/ComponentEditors/VolumeRendererComponentEditor`
|
||||
- `docs/api/XCEngine/Editor/panels/MaterialInspectorMaterialState`
|
||||
- `docs/api/XCEngine/Editor/panels/MaterialInspectorMaterialStateIO`
|
||||
|
||||
## 并行认领规则
|
||||
|
||||
- 一次只认领一个任务块
|
||||
- 认领人必须同时处理:
|
||||
- 目标页面
|
||||
- 所在模块索引页
|
||||
- 交叉引用修正
|
||||
- 做删除前先执行:
|
||||
- `rg -n "<名称>" docs/api/XCEngine docs/api/_guides docs/plan`
|
||||
- 每完成一个任务块后必须执行:
|
||||
- `python -B docs/api/_tools/audit_api_docs.py`
|
||||
- 每完成一个阶段后必须:
|
||||
- `git commit`
|
||||
- `git push`
|
||||
|
||||
## 并行任务块
|
||||
|
||||
| ID | 范围 | 目标改动 | 主要路径 | 状态 | 认领人 |
|
||||
|----|------|----------|----------|------|--------|
|
||||
| `R1` | Rendering 目录归位 | 把错挂在 `Rendering` 根目录下的页面迁回 `Execution / Planning / Extraction / Caches / FrameData / Passes`,并与已存在的正确目录合并 | `docs/api/XCEngine/Rendering/**` | `completed` | 当前会话 |
|
||||
| `R2` | 旧概念 Rendering 清理 | 核查并清理 `RenderMaterialUtility / ObjectIdEncoding / VisibleRenderObject / BuiltinForwardPipelineAsset / ObjectIdOutlineStyle / BuiltinPostProcessPassPlan / BuiltinPostProcessPassSequenceBuilder / ShaderRenderState` | `docs/api/XCEngine/Rendering/**` `docs/api/XCEngine/Resources/Shader/**` | `completed` | 当前会话 |
|
||||
| `R3` | Editor 失效页清理 | 删除或退役 `XCUIDemoPanel / SceneViewportOverlayRenderer`,并修正所有反向引用 | `docs/api/XCEngine/Editor/**` | `completed` | 当前会话 |
|
||||
| `R4` | Volume 资源与运行时主链 | 补齐 `Volume / VolumeField / VolumeFieldLoader / VolumeRendererComponent / VisibleVolumeItem / BuiltinVolumetricPass` | `docs/api/XCEngine/Resources/**` `docs/api/XCEngine/Components/**` `docs/api/XCEngine/Rendering/**` | `completed` | 当前会话 |
|
||||
| `R5` | Selection pass 结构补齐 | 补齐 `BuiltinSelectionMaskPass` 与 `BuiltinSelectionOutlinePass`,并同步 `Passes.md` | `docs/api/XCEngine/Rendering/Passes/**` | `completed` | 当前会话 |
|
||||
| `R6` | UI 新 helper | 补齐 `UIDragDropInteraction` 与 `UIScrollModel`,并同步 `Widgets.md` | `docs/api/XCEngine/UI/Widgets/**` | `completed` | 当前会话 |
|
||||
| `R7` | Editor 当前真实 helper | 补齐 `VolumeRendererComponentEditor / MaterialInspectorMaterialState / MaterialInspectorMaterialStateIO`,并同步 `ComponentEditors.md` 与 `panels.md` | `docs/api/XCEngine/Editor/**` | `completed` | 当前会话 |
|
||||
| `R8` | 结构规范补齐 | 修正仍不满足“一类型一文件夹”的点,例如 `Editor/UI/UI`、`Resources/Material/MaterialRenderState` 这类混挂页 | `docs/api/XCEngine/**` | `pending` | |
|
||||
| `R9` | 全量回归 | 统一修链、清理空目录、重跑审计、收口索引页 | `docs/api/**` | `pending` | |
|
||||
|
||||
## 推荐阶段顺序
|
||||
|
||||
### Phase 1
|
||||
|
||||
- `R3`
|
||||
- `R1`
|
||||
- `R2`
|
||||
|
||||
说明:
|
||||
|
||||
- 先把失效页和错位目录处理掉,后续内容重写才不会继续落在错误路径上
|
||||
|
||||
### Phase 2
|
||||
|
||||
- `R4`
|
||||
- `R5`
|
||||
- `R6`
|
||||
- `R7`
|
||||
- `R8`
|
||||
|
||||
说明:
|
||||
|
||||
- 这一阶段是把新主链和当前真实 helper 补平
|
||||
|
||||
### Phase 3
|
||||
|
||||
- `R9`
|
||||
|
||||
说明:
|
||||
|
||||
- 统一收口、审计、整理最终状态
|
||||
|
||||
## 最低验收标准
|
||||
|
||||
### `R1`
|
||||
|
||||
- 所有迁移后的页面目录与真实头文件父目录一致
|
||||
- 原路径不再保留 active canonical 页面
|
||||
|
||||
### `R2`
|
||||
|
||||
- 每个旧概念页都给出明确结论:
|
||||
- 删除
|
||||
- 迁移
|
||||
- 改写为真实对应页
|
||||
|
||||
### `R3`
|
||||
|
||||
- `Invalid source refs` 归零
|
||||
- `XCUIDemoPanel` 不再作为当前有效 API 页面存在于 canonical 树
|
||||
|
||||
### `R4` - `R8`
|
||||
|
||||
- 每个类型都是“一文件夹 + 一主页面”
|
||||
- 页面描述必须基于当前源码与测试
|
||||
- 模块索引页同步更新
|
||||
|
||||
### `R9`
|
||||
|
||||
- `Invalid header refs = 0`
|
||||
- `Invalid source refs = 0`
|
||||
- `Broken .md links = 0`
|
||||
- `Missing directory index pages = 0`
|
||||
|
||||
## 备注
|
||||
|
||||
- 当前仓库存在多会话并行改动,尤其是 `Rendering`、`RHI`、`Editor/Viewport` 相关头文件;真正执行重构时优先选择干净路径,避免和其他会话冲突
|
||||
- 如果某个任务块执行过程中发现真实源码再次变动,应先回到本任务板更新状态,不要硬做
|
||||
@@ -1,38 +0,0 @@
|
||||
# API 文档目录结构阶段进度:XCEditor 与 Model 收口
|
||||
|
||||
## 本阶段范围
|
||||
|
||||
- 新建 `docs/api/XCEditor/**` canonical 目录树,并生成 `new_editor/include/XCEditor/**` 对应的 header 总览页与方法页。
|
||||
- 新建 `docs/api/XCEngine/Resources/Model/Model.md` 模块索引,并生成 `Model` / `ModelArtifactIO` / `ModelLoader` / `AssimpModelImporter` 对应页面。
|
||||
- 处理并发新增的 `docs/api/XCEngine/Resources/GaussianSplat/**`,补齐模块索引与 `GaussianSplat` / `GaussianSplatArtifactIO` / `GaussianSplatLoader` 页面。
|
||||
- 修正目录脚手架与 canonical 生成器的两个问题:
|
||||
- 根索引页错误把 `XCEditor` 当成普通子目录,生成了失效的 `../api.md` 链接。
|
||||
- 窄范围生成 `Resources/Model` 时,头文件引用缺少 `XCEngine/` 前缀。
|
||||
|
||||
## 当前结果
|
||||
|
||||
执行时间:`2026-04-10`
|
||||
|
||||
审计命令:
|
||||
|
||||
```powershell
|
||||
python -B docs/api/_tools/audit_api_docs.py
|
||||
```
|
||||
|
||||
审计结果:
|
||||
|
||||
- `Public headers: 381`
|
||||
- `Valid header refs (canonical): 381`
|
||||
- `Invalid header refs: 0`
|
||||
- `Editor source headers: 144`
|
||||
- `Valid source refs (Editor canonical): 144`
|
||||
- `Invalid source refs: 0`
|
||||
- `Broken .md links: 0`
|
||||
- `Missing directory index pages: 0`
|
||||
|
||||
## 并行协作说明
|
||||
|
||||
- `docs/api/XCEditor/**` 本轮已经落成,不再作为待认领空树任务。
|
||||
- `docs/api/XCEngine/Resources/Model/**` 本轮已经补齐目录索引与 header 页面,不再重复认领。
|
||||
- `docs/api/XCEngine/Resources/GaussianSplat/**` 也已补齐,如头文件继续扩展,请直接在现有树上增量同步。
|
||||
- 后续如果 `new_editor/include/XCEditor/**` 或 `engine/include/XCEngine/Resources/Model/**` 再发生结构变动,应直接基于当前树增量同步,不要回退到“先补目录骨架”的阶段。
|
||||
@@ -1,148 +0,0 @@
|
||||
# API文档目录重构计划
|
||||
|
||||
## 1. 背景
|
||||
|
||||
当前 API 文档树已经出现明显的“双主线错位”:
|
||||
|
||||
- `docs/api/XCEngine/Editor/**` 主要对应旧 `editor/src/**` 的 ImGui 编辑器应用层。
|
||||
- `new_editor/include/XCEditor/**` 与 `new_editor/src/**` 已经形成新的 Editor 基础层主线。
|
||||
- 这条主线最初没有进入当前 canonical API 树,审计脚本也一度没有覆盖 `new_editor/include/XCEditor/**`。
|
||||
|
||||
这意味着继续只在 `docs/api/XCEngine/Editor/**` 上增量修补,会越来越偏离真实代码结构。
|
||||
|
||||
## 1.1 2026-04-10 状态更新
|
||||
|
||||
截至 `2026-04-10 17:07:09`,以下阶段已经落地:
|
||||
|
||||
- `docs/api/XCEditor/**` 已建立并进入 canonical 根树
|
||||
- 审计脚本已经覆盖:
|
||||
- `engine/include/XCEngine/**`
|
||||
- `new_editor/include/XCEditor/**`
|
||||
- `editor/src/**`
|
||||
- `docs/api/main.md` 已建立 `XCEngine + XCEditor` 双根入口
|
||||
- `XCUIDemoPanel` 已退出当前 canonical API 树
|
||||
- `Resources/Model` 与 `Resources/GaussianSplat` 已补齐 canonical 入口
|
||||
|
||||
因此这份计划里“为什么要拆出 `XCEditor` 根树”的判断仍然有效,但 `Phase B / C` 不再是未来动作,而是已完成事实。
|
||||
|
||||
## 2. 当前判断
|
||||
|
||||
### 2.1 旧 `Editor` 文档树继续保留,但必须收紧边界
|
||||
|
||||
- `docs/api/XCEngine/Editor/**` 继续只文档化旧 `editor/src/**`。
|
||||
- 不再把它当成未来 Editor 主线 API 树。
|
||||
- 其中 `Application / EditorResources / Theme / XCUIBackend / panels / Viewport` 等内容,明确视为旧编辑器应用层。
|
||||
|
||||
### 2.2 新主线已拆出独立文档树
|
||||
|
||||
当前已新增:
|
||||
|
||||
- `docs/api/XCEditor/`
|
||||
|
||||
首层目录直接镜像 `new_editor/include/XCEditor/**`:
|
||||
|
||||
- `Collections`
|
||||
- `Fields`
|
||||
- `Foundation`
|
||||
- `Shell`
|
||||
- `Widgets`
|
||||
|
||||
这样做的原因很直接:
|
||||
|
||||
- 与真实 include 路径一致,后续自动审计最容易做。
|
||||
- 不会把新主线继续混进旧 `XCEngine/Editor` 树里。
|
||||
- 可以允许页面里的命名空间继续写真实值 `XCEngine::UI::Editor` / `XCEngine::UI::Editor::Widgets`,而目录只负责和头文件路径对齐。
|
||||
|
||||
### 2.3 新旧两棵树的职责应明确分开
|
||||
|
||||
- `docs/api/XCEngine/Editor/**`
|
||||
- 旧编辑器应用层、宿主层、过渡层、当前产品参考实现。
|
||||
- `docs/api/XCEditor/**`
|
||||
- `new_editor` 的新 Editor 基础层与宿主骨架。
|
||||
|
||||
## 3. 已确认的结构漂移
|
||||
|
||||
### 3.1 文档树覆盖不到 `new_editor/include/XCEditor`
|
||||
|
||||
当前新主线 public headers 已经至少包含:
|
||||
|
||||
- `XCEditor/Collections/*`
|
||||
- `XCEditor/Fields/*`
|
||||
- `XCEditor/Foundation/*`
|
||||
- `XCEditor/Shell/*`
|
||||
- `XCEditor/Widgets/*`
|
||||
|
||||
现在 `docs/api` 里已经有对应的 `XCEditor` 根树。
|
||||
|
||||
### 3.2 旧树中仍混有已经过时的过渡页
|
||||
|
||||
当前这类问题已经完成清理,最典型的是:
|
||||
|
||||
- `docs/api/XCEngine/Editor/panels/XCUIDemoPanel/XCUIDemoPanel.md`
|
||||
- 仍引用已不存在的 `editor/src/panels/XCUIDemoPanel.h`
|
||||
|
||||
这类页面已经从 active canonical 树移除,不再继续假设旧源码路径仍成立。
|
||||
|
||||
### 3.3 审计工具口径落后
|
||||
|
||||
当前这项问题已经收口;审计脚本现在已经把:
|
||||
|
||||
- `new_editor/include/XCEditor/**/*.h`
|
||||
|
||||
纳入 canonical 统计,`XCEditor` 缺页会直接出现在审计结果里。
|
||||
|
||||
## 4. 分阶段执行
|
||||
|
||||
## Phase A:收紧旧树边界
|
||||
|
||||
- 在 `docs/api/XCEngine/Editor/Editor.md` 明确“这里只对应旧 `editor/src/**`”。
|
||||
- 修掉旧树里已经失效的 source refs。
|
||||
- 继续补齐旧 `editor/src/**` 当前缺失的 canonical 页,避免现有审计长期失真。
|
||||
|
||||
## Phase B:建立 `XCEditor` 新根树(已完成)
|
||||
|
||||
- 新建 `docs/api/XCEditor/XCEditor.md`
|
||||
- 新建 5 个首层 overview:
|
||||
- `Collections`
|
||||
- `Fields`
|
||||
- `Foundation`
|
||||
- `Shell`
|
||||
- `Widgets`
|
||||
- 建立 `docs/api/main.md` 到新根树的入口链接
|
||||
|
||||
## Phase C:接入新审计口径(已完成)
|
||||
|
||||
- 扩展审计脚本识别 `new_editor/include/XCEditor/**/*.h`
|
||||
- 统计 `docs/api/XCEditor/**` 的 canonical 覆盖率
|
||||
- 区分:
|
||||
- 旧 `editor/src/**` 应用层源码页
|
||||
- 新 `XCEditor/**` public header 页
|
||||
|
||||
## Phase D:按新主线分批补页(进行中)
|
||||
|
||||
推荐顺序:
|
||||
|
||||
1. `Foundation`
|
||||
2. `Widgets`
|
||||
3. `Collections`
|
||||
4. `Fields`
|
||||
5. `Shell`
|
||||
|
||||
原因:
|
||||
|
||||
- `Foundation` 与 `Widgets` 是多数页面的前置语义。
|
||||
- `Collections` / `Fields` 数量多,但结构相对规整,适合并行。
|
||||
- `Shell` 依赖最多,最好放后面统一写。
|
||||
|
||||
## Phase E:旧树去历史包袱(进行中)
|
||||
|
||||
- 删除或改写已经脱离旧源码的过渡页
|
||||
- 把“旧 editor 参考实现”和“new_editor 正式主线”在相关 overview 中互相链接,但不再混放
|
||||
- 避免后续继续把 `new_editor` 内容塞进 `docs/api/XCEngine/Editor/**`
|
||||
|
||||
## 5. 本轮执行口径
|
||||
|
||||
当前后续重点已经转到:
|
||||
|
||||
1. 继续回归高风险 `RHI / Rendering / Editor/Viewport` 内容页,避免源码继续演进后文档再次漂移。
|
||||
2. 继续清理旧树里的历史空目录、重复入口和剩余结构噪音。
|
||||
@@ -1,216 +0,0 @@
|
||||
# Audio 模块架构最佳实践重构计划
|
||||
日期:2026-04-14
|
||||
|
||||
## 1. 目标
|
||||
|
||||
本轮不是继续给当前 Audio 模块叠功能,而是把它从“可用的简化运行时”推进到“可扩展、可回归、契约清晰的正式架构”。
|
||||
|
||||
本计划聚焦以下最佳实践差距:
|
||||
|
||||
1. 混音主链仍是 `game thread push -> backend pending buffer`
|
||||
2. `AudioSourceComponent` 持有实例级解码 PCM,资源复用模型不对
|
||||
3. mixer / effect / routing 仍是裸指针图,ownership 不清晰
|
||||
4. backend API 能力声明与实际实现不一致
|
||||
5. master gain / mute 的职责落点分裂
|
||||
6. 混音路径仍有较多临时分配,RT-safe 程度不足
|
||||
|
||||
## 2. 本轮边界
|
||||
|
||||
本轮做:
|
||||
|
||||
1. 先把资源层与 source/voice 层边界做对
|
||||
2. 先把 mixer graph 的 ownership 和路由契约做清楚
|
||||
3. 先把 backend 抽象语义收口到“说什么就真支持什么”
|
||||
4. 先把主线程混音路径中的明显重复分配和重复解码收掉
|
||||
5. 为后续“真正的音频线程拉取式渲染”铺接口和数据结构基础
|
||||
|
||||
本轮不直接做:
|
||||
|
||||
1. 不在第一步就推倒重写成完整 callback renderer
|
||||
2. 不先上 streaming / bank / snapshot / event system
|
||||
3. 不先扩平台后端
|
||||
4. 不把 editor 可视化音频图一起塞进本轮
|
||||
|
||||
## 3. 重构分期
|
||||
|
||||
### Phase 0:冻结当前外部行为
|
||||
|
||||
目标:
|
||||
先保证现有运行时行为有回归保护,避免架构重构时把已有能力打坏。
|
||||
|
||||
执行项:
|
||||
|
||||
1. 盘点现有 Audio 单测覆盖范围
|
||||
2. 明确现阶段保留行为:
|
||||
`Play / Pause / Stop / Loop / Seek / Spatial Pan / HRTF / Reverb Send / Mixer Route`
|
||||
3. 记录当前对外契约:
|
||||
`AudioClip -> AudioSourceComponent -> AudioSystem -> IAudioBackend`
|
||||
|
||||
完成标准:
|
||||
|
||||
1. 关键行为都有最小回归测试入口
|
||||
2. 后续阶段改动不需要靠人工听感判断是否回归
|
||||
|
||||
### Phase 1:重做资源复用模型
|
||||
|
||||
目标:
|
||||
把“音频资源”和“播放实例”彻底拆开。
|
||||
|
||||
执行项:
|
||||
|
||||
1. 将 decoded float PCM 从 `AudioSourceComponent` 下沉到 `AudioClip`
|
||||
2. 让 `AudioClip` 负责:
|
||||
PCM 原始字节
|
||||
派生元数据
|
||||
共享 decoded float cache
|
||||
3. 让 `AudioSourceComponent` 只保留:
|
||||
clip 引用
|
||||
播放游标
|
||||
voice 参数
|
||||
空间化参数
|
||||
4. 统一缓存失效策略:
|
||||
PCM / channels / bitsPerSample / sampleRate 改动时,duration 与 decoded cache 一起刷新
|
||||
5. 补资源层测试,覆盖 decoded cache 和派生元数据刷新
|
||||
|
||||
完成标准:
|
||||
|
||||
1. 同一 `AudioClip` 被多个 source 使用时不再重复解码
|
||||
2. source 不再持有整份 clip 的 float PCM 副本
|
||||
3. `AudioClip` 的 duration / frameCount / sampleCount / decoded cache 语义一致
|
||||
|
||||
当前状态:
|
||||
`进行中,本轮先执行这一阶段。`
|
||||
|
||||
### Phase 2:收口 mixer graph ownership
|
||||
|
||||
目标:
|
||||
把当前“裸指针路由”收口成显式可管理的图结构。
|
||||
|
||||
执行项:
|
||||
|
||||
1. 为 mixer node 建立明确 owner
|
||||
2. 明确 source 输出路由、listener reverb send、mixer output 的生命周期规则
|
||||
3. 禁止悬挂 graph node 被继续访问
|
||||
4. 为未来 editor/runtime graph 统一预留 handle 或 registry 入口
|
||||
|
||||
完成标准:
|
||||
|
||||
1. graph 生命周期可推理
|
||||
2. scene 切换与对象销毁不会留下悬挂路由
|
||||
3. mixer routing 可以被测试验证
|
||||
|
||||
### Phase 3:统一控制语义与 backend 能力
|
||||
|
||||
目标:
|
||||
去掉“同一语义多处实现”的问题。
|
||||
|
||||
执行项:
|
||||
|
||||
1. 统一 master volume / mute 的唯一 owner
|
||||
2. backend 只保留设备与提交职责
|
||||
3. 移除误导性的 `WASAPIBackend` 别名或改成真实实现
|
||||
4. 明确 `SetDevice()` 是否真支持热切换;如果不支持,就不要暴露伪能力
|
||||
|
||||
完成标准:
|
||||
|
||||
1. gain staging 只有一套主语义
|
||||
2. backend 能力声明与实现一致
|
||||
|
||||
### Phase 4:从主线程推送过渡到音频线程拉取
|
||||
|
||||
目标:
|
||||
把当前 `Update()` 主导混音的模型,重构为更接近实时音频最佳实践的 render path。
|
||||
|
||||
执行项:
|
||||
|
||||
1. 从 `AudioSystem` 中拆出音频渲染上下文
|
||||
2. 让 backend 线程按设备需求拉取 render block
|
||||
3. 把游戏线程职责收缩到:
|
||||
发布 source/listener 状态
|
||||
提交控制参数
|
||||
不直接承担设备节奏的最终混音责任
|
||||
4. 明确 block size、latency、underrun fallback 行为
|
||||
|
||||
完成标准:
|
||||
|
||||
1. 设备消费节奏不再依赖游戏帧节奏
|
||||
2. render 线程契约独立成立
|
||||
|
||||
### Phase 5:RT-safe 清理
|
||||
|
||||
目标:
|
||||
减少实时路径上的临时分配和不可控开销。
|
||||
|
||||
执行项:
|
||||
|
||||
1. 缓存 `AudioSystem` 混音 scratch buffer
|
||||
2. 减少 `unordered_map` / `vector` 的逐帧临时构建
|
||||
3. 把 `Equalizer` / `Reverbation` / `FFTFilter` 的临时缓冲改成复用型工作区
|
||||
4. 明确哪些 DSP 允许进实时渲染链,哪些只能做分析
|
||||
|
||||
完成标准:
|
||||
|
||||
1. 混音热路径不再做明显重复分配
|
||||
2. DSP 链路更接近 RT-safe
|
||||
|
||||
### Phase 6:回归测试与阶段收口
|
||||
|
||||
目标:
|
||||
让架构重构具备真正的落地闭环。
|
||||
|
||||
执行项:
|
||||
|
||||
1. 补充资源共享、graph 生命周期、backend 语义、render 路径相关测试
|
||||
2. 补阶段性文档
|
||||
3. 按阶段提交 git commit,并在每个稳定节点推送
|
||||
|
||||
完成标准:
|
||||
|
||||
1. 每一阶段都有对应提交点
|
||||
2. 关键行为和关键架构约束都有自动化保护
|
||||
|
||||
## 4. 执行顺序
|
||||
|
||||
按优先级执行:
|
||||
|
||||
1. `Phase 1` 资源复用模型
|
||||
2. `Phase 3` backend 与控制语义收口
|
||||
3. `Phase 2` mixer graph ownership
|
||||
4. `Phase 5` RT-safe 清理
|
||||
5. `Phase 4` 音频线程拉取式渲染
|
||||
6. `Phase 6` 收口与验证贯穿全程
|
||||
|
||||
原因:
|
||||
|
||||
1. `Phase 1` 改动收益大、风险低、最容易稳定落地
|
||||
2. `Phase 3` 能先消掉接口层误导
|
||||
3. `Phase 2` 需要建立在边界先清楚的前提下
|
||||
4. `Phase 4` 是最大手术,必须放到前置契约稳定之后
|
||||
|
||||
## 5. 当前这一步准备执行的内容
|
||||
|
||||
第一批落地项:
|
||||
|
||||
1. 新增 `AudioClip` 共享 decoded float cache
|
||||
2. 移除 `AudioSourceComponent` 的实例级 `m_decodedData`
|
||||
3. 统一 `AudioClip` 派生数据失效与刷新逻辑
|
||||
4. 补资源层和 source 层测试
|
||||
|
||||
这一步完成后,Audio 模块会先从“每个 source 自带一份解码副本”进入“资源共享 + 播放实例分离”的正确方向。
|
||||
|
||||
## 6. 阶段性提交策略
|
||||
|
||||
每阶段至少形成一次独立提交:
|
||||
|
||||
1. `phase1/audio-clip-shared-decoded-cache`
|
||||
2. `phase3/backend-contract-cleanup`
|
||||
3. `phase2/mixer-graph-ownership`
|
||||
4. `phase5/rt-safe-buffer-reuse`
|
||||
5. `phase4/audio-thread-pull-render`
|
||||
|
||||
执行要求:
|
||||
|
||||
1. 每次只提交一个可回归的小阶段
|
||||
2. 提交前先跑对应最小测试集
|
||||
3. 阶段完成后及时推送,避免大堆积
|
||||
|
||||
@@ -1,287 +0,0 @@
|
||||
# C#脚本模块下一阶段计划
|
||||
|
||||
日期:2026-04-03
|
||||
|
||||
## 1. 当前阶段判断
|
||||
|
||||
C# 脚本模块已经完成了第一阶段的核心闭环,不再是“从 0 到 1 的原型验证”状态,而是进入了“从可运行走向可长期使用”的第二阶段。
|
||||
|
||||
当前已经完成的关键能力包括:
|
||||
|
||||
1. `ScriptComponent + MonoBehaviour` 基本运行时模型已经建立
|
||||
2. `MonoScriptRuntime` 已经能加载程序集、发现脚本类、创建托管实例、调用生命周期
|
||||
3. `Awake / OnEnable / Start / FixedUpdate / Update / LateUpdate / OnDisable / OnDestroy` 已经打通
|
||||
4. `Debug.Log / LogWarning / LogError` 已经打通到 native logger
|
||||
5. `Time`、`Input`、`GameObject`、`Transform`、`Behaviour.enabled`、部分内建组件包装已经可用
|
||||
6. 脚本字段存储、默认值、覆盖值、运行时值三层模型已经建立
|
||||
7. Play / Pause / Resume / Step 已经能驱动脚本生命周期
|
||||
8. editor 已经具备脚本类选择、字段 Inspector 编辑、项目脚本程序集重建与重载入口
|
||||
|
||||
这意味着下一阶段的重点,不再是“脚本能不能跑”,而是:
|
||||
|
||||
1. Unity 风格 API 是否足够严格一致
|
||||
2. 项目级脚本工作流是否足够稳定
|
||||
3. 字段系统是否能支撑真实项目使用
|
||||
|
||||
---
|
||||
|
||||
## 2. 下一阶段总目标
|
||||
|
||||
下一阶段的总目标是:
|
||||
|
||||
把当前“可运行的 C# 脚本运行时”收口成“命名、语义、工作流都更接近 Unity 的第一版可用脚本模块”。
|
||||
|
||||
具体聚焦三件事:
|
||||
|
||||
1. **Unity API 严格对齐**
|
||||
2. **项目脚本程序集链路收口**
|
||||
3. **脚本字段系统扩展**
|
||||
|
||||
---
|
||||
|
||||
## 3. 第一优先级:Unity API 严格对齐
|
||||
|
||||
这是当前最高优先级。
|
||||
|
||||
原因:
|
||||
|
||||
1. 你已经明确要求 API 命名必须和 Unity C# API 保持严格一致
|
||||
2. 运行时主链路已经可用,当前最需要尽快收口的是 API 契约
|
||||
3. 如果 API 名字、属性名、行为语义先发散,后面越做越难回收
|
||||
|
||||
本阶段需要重点检查和补齐以下几类接口:
|
||||
|
||||
### 3.1 基础对象层
|
||||
|
||||
优先补齐 Unity 风格的基础对象模型:
|
||||
|
||||
1. `Object`
|
||||
2. `Component`
|
||||
3. `Behaviour`
|
||||
4. `MonoBehaviour`
|
||||
|
||||
重点不是“再做一套功能”,而是统一 API 入口和语义边界。
|
||||
|
||||
### 3.2 GameObject / Component 常用 API
|
||||
|
||||
优先补齐最常用、最影响脚本编写体验的 Unity 接口:
|
||||
|
||||
1. `GetComponent<T>()`
|
||||
2. `TryGetComponent<T>(out T)`
|
||||
3. `AddComponent<T>()`
|
||||
4. `GetComponents<T>()`
|
||||
5. `GetComponentInChildren<T>()`
|
||||
6. `GetComponentInParent<T>()`
|
||||
7. `CompareTag`
|
||||
8. `tag`
|
||||
9. `layer`
|
||||
|
||||
其中前四项优先级最高。
|
||||
|
||||
### 3.3 Object 静态入口
|
||||
|
||||
优先补齐 Unity 风格最核心的对象静态方法:
|
||||
|
||||
1. `Object.Destroy`
|
||||
2. `Object.Instantiate`
|
||||
|
||||
这一层非常关键,因为 Unity 用户的很多使用习惯都是围绕 `Object` 静态 API 建立的。
|
||||
|
||||
### 3.4 Transform 常用缺口补齐
|
||||
|
||||
当前 `Transform` 已经有较完整的空间变换接口,但还需要继续检查 Unity 一致性,重点看:
|
||||
|
||||
1. 属性命名
|
||||
2. 重载形态
|
||||
3. `childCount` / `GetChild`
|
||||
4. `parent` / `SetParent`
|
||||
5. `Translate` / `Rotate` / `LookAt`
|
||||
6. 常用便捷属性是否缺失
|
||||
|
||||
原则是:
|
||||
|
||||
1. 已有 API 尽量不发散出自定义命名
|
||||
2. 优先补 Unity 常见重载
|
||||
|
||||
---
|
||||
|
||||
## 4. 第二优先级:项目脚本程序集链路收口
|
||||
|
||||
当前 editor 已经具备:
|
||||
|
||||
1. `project/Assets` 扫描
|
||||
2. `GameScripts.dll` 编译
|
||||
3. `Rebuild Scripts`
|
||||
4. `Reload Scripts`
|
||||
5. Inspector 脚本类发现
|
||||
|
||||
但这一层还没有完全稳定,尤其是:
|
||||
|
||||
1. 项目程序集输出目录依赖当前工作区状态
|
||||
2. 测试环境下 `project/Library/ScriptAssemblies` 还不稳定
|
||||
3. editor / 测试 / 项目目录三者之间还缺少更彻底的收口
|
||||
|
||||
这一阶段要完成的目标是:
|
||||
|
||||
1. `project/Assets/*.cs -> Library/ScriptAssemblies/*.dll` 变成稳定链路
|
||||
2. editor 重建后总能看到最新脚本类
|
||||
3. 对应测试不依赖手工残留文件
|
||||
4. 项目程序集相关测试可以稳定进入常规回归集
|
||||
|
||||
这部分的目标不是继续扩 API,而是把工程化链路做稳。
|
||||
|
||||
---
|
||||
|
||||
## 5. 第三优先级:脚本字段系统扩展
|
||||
|
||||
当前字段系统已经支持:
|
||||
|
||||
1. `float`
|
||||
2. `double`
|
||||
3. `bool`
|
||||
4. `int32`
|
||||
5. `uint64`
|
||||
6. `string`
|
||||
7. `Vector2`
|
||||
8. `Vector3`
|
||||
9. `Vector4`
|
||||
10. `GameObject` 引用
|
||||
|
||||
下一阶段应继续向 Unity 常用字段模型推进,优先顺序建议如下:
|
||||
|
||||
1. `enum`
|
||||
2. `SerializeField` 支持
|
||||
3. private 可序列化字段
|
||||
4. 组件引用字段
|
||||
5. 数组 / List
|
||||
6. 资源引用字段
|
||||
|
||||
其中最优先的是:
|
||||
|
||||
1. `enum`
|
||||
2. `[SerializeField]`
|
||||
3. 组件引用字段
|
||||
|
||||
因为这三项最直接决定脚本是否能进入“真实可写”阶段。
|
||||
|
||||
---
|
||||
|
||||
## 6. editor 集成边界
|
||||
|
||||
这一阶段 editor 不再是完全不碰,但仍然不是主战场。
|
||||
|
||||
原则是:
|
||||
|
||||
1. 只做支撑脚本模块使用所必需的 editor 收口
|
||||
2. 不把主要精力放在复杂编辑器体验优化上
|
||||
3. 继续优先保证 runtime、程序集链路、字段模型稳定
|
||||
|
||||
本阶段 editor 侧只建议继续做以下范围:
|
||||
|
||||
1. 脚本类发现与重建流程稳定性
|
||||
2. Inspector 字段编辑最小闭环
|
||||
3. 类型新增后对应字段控件补齐
|
||||
|
||||
以下内容暂时不进入主线:
|
||||
|
||||
1. 热重载
|
||||
2. 托管调试器
|
||||
3. 完整 Console/Exception 调试体验
|
||||
4. 高级脚本模板与自动生成工具
|
||||
|
||||
---
|
||||
|
||||
## 7. 本阶段不做的内容
|
||||
|
||||
为避免范围继续膨胀,下一阶段先明确不做:
|
||||
|
||||
1. 域重载 / 热重载
|
||||
2. CoreCLR 切换
|
||||
3. IL2CPP / AOT
|
||||
4. 完整 Unity 级别资源 API
|
||||
5. 复杂序列化对象图
|
||||
6. 完整调试器接入
|
||||
|
||||
这些都可以进入后续阶段,但不应抢占当前优先级。
|
||||
|
||||
---
|
||||
|
||||
## 8. 建议执行顺序
|
||||
|
||||
建议严格按下面顺序推进:
|
||||
|
||||
1. 先做 **Unity API 命名与契约收口**
|
||||
2. 再做 **项目脚本程序集链路稳定化**
|
||||
3. 再做 **字段系统扩展**
|
||||
4. 再做 **新增字段类型对应的 Inspector 支持**
|
||||
5. 最后再评估热重载、调试器、异常体验
|
||||
|
||||
原因很简单:
|
||||
|
||||
1. API 契约不先收口,后面所有脚本都会建立在不稳定接口上
|
||||
2. 程序集链路不稳定,项目脚本工作流就不可靠
|
||||
3. 字段系统是把脚本从“可跑”推进到“可用”的关键
|
||||
|
||||
---
|
||||
|
||||
## 9. 验收标准
|
||||
|
||||
本阶段完成后,至少应满足:
|
||||
|
||||
1. 核心托管 API 的命名与 Unity 保持一致,不再出现明显自定义发散
|
||||
2. `Object / GameObject / Component / Behaviour / MonoBehaviour / Transform` 的主干接口基本齐全
|
||||
3. 项目脚本程序集能稳定重建、重载、发现
|
||||
4. 项目级脚本程序集测试可以稳定跑通
|
||||
5. Inspector 能编辑扩展后的核心字段类型
|
||||
6. 脚本模块可以支撑真实项目写出第一批常规 gameplay 脚本
|
||||
|
||||
---
|
||||
|
||||
## 10. 当前结论
|
||||
|
||||
脚本模块现在已经完成了“第一阶段:核心运行时落地”。
|
||||
|
||||
下一阶段不应该再围绕“能不能跑”展开,而应该围绕:
|
||||
|
||||
1. **Unity API 严格一致**
|
||||
2. **项目工作流稳定**
|
||||
3. **字段系统可用于真实开发**
|
||||
|
||||
后续执行时,默认按这个优先级推进。
|
||||
## 阶段进展 2026-04-03
|
||||
|
||||
- 已完成第一步 Unity API 对齐收口:
|
||||
- 新增 `XCEngine.Object` 基类。
|
||||
- 新增 `Object.Destroy(Object)` 静态销毁入口。
|
||||
- 新增 `GameObject / Component.GetComponentInChildren<T>()`。
|
||||
- 新增 `GameObject / Component.GetComponentInParent<T>()`。
|
||||
- 已补齐对应 Mono internal call 与 native 销毁路径。
|
||||
- 已新增运行时回归用例,验证层级查找、自身命中、组件销毁、GameObject 销毁。
|
||||
- 已通过 `MonoScriptRuntimeTest.*` 与 `ProjectScriptAssemblyTest.*` 相关整组验证。
|
||||
|
||||
- 已完成第二步第一小项:`GetComponents<T>()`
|
||||
- 已完成第二步第二小项:`tag / CompareTag / layer`
|
||||
- `GameObject`、`Component` 与 `MonoBehaviour` 已提供 Unity 风格 `tag`、`layer`、`CompareTag(string)` 入口。
|
||||
- native `GameObject`、场景查找、序列化与反序列化已同步收口,`FindGameObjectWithTag` / `FindGameObjectsWithTag` 已改为基于 tag。
|
||||
- 已新增 `TagLayerProbe` 与对应 C++ / Mono 回归测试,覆盖默认 tag、layer 裁剪、脚本侧读写与场景 roundtrip。
|
||||
- 相关定向测试全部通过;完整 `MonoScriptRuntimeTest.*:ProjectScriptAssemblyTest.*` 输出全绿,当前仍存在历史性的 `exit code 3` 异常,需后续单独跟踪。
|
||||
- 下一步建议继续做第三小项:`Object.Instantiate`
|
||||
|
||||
- 已完成字段系统第一小项:`enum` 字段支持
|
||||
- `MonoScriptRuntime` 现已支持把常见整数底层的 C# `enum` 字段纳入脚本字段模型,并按 `Int32` 进入默认值、存储值、运行时值三层同步链路。
|
||||
- 已新增 `FieldMetadataProbeState` / `EnumFieldProbeState` 探针,覆盖枚举字段发现、默认值提取、运行时写回与场景 roundtrip。
|
||||
- 已通过新增定向测试,以及完整 `ScriptFieldStorage_Test.*:MonoScriptRuntimeTest.*:ProjectScriptAssemblyTest.*` 整组验证;输出全绿,`exit code 3` 仍为既有历史现象。
|
||||
- 已完成字段系统第二小项:`[SerializeField] private` 字段支持
|
||||
- 新增 `XCEngine.SerializeField` attribute,命名与 Unity 对齐;runtime 字段发现现已支持“public 字段”与“带 `[SerializeField]` 的 private 字段”双通路。
|
||||
- 字段筛选已同步排除 `static` / `const` / `readonly`,并新增 `SerializeFieldProbe`、`FieldMetadataProbe` 扩展与对应 C++ 回归测试,覆盖默认值提取、存储覆盖、运行时写回与场景 roundtrip。
|
||||
- `ProjectScriptAssemblyTest.*` 现改为使用独立的测试项目程序集输出目录,不再依赖真实 `project/Library/ScriptAssemblies`,避免与 editor / Mono 持有的文件锁互相干扰。
|
||||
- 已通过完整 `ScriptFieldStorage_Test.*:MonoScriptRuntimeTest.*:ProjectScriptAssemblyTest.*` 验证;输出全绿,`exit code 3` 仍为既有历史现象。
|
||||
- 字段系统下一步建议切到:组件引用字段支持
|
||||
- 已完成字段系统第三小项:具体组件引用字段支持
|
||||
- `MonoScriptRuntime` 现已支持把常用具体组件字段纳入脚本字段模型,包括 `Transform`、`Camera`、`Light`、`MeshFilter`、`MeshRenderer`,以及具体脚本类字段(`MonoBehaviour` 子类)。
|
||||
- 字段存储层已新增 `ScriptFieldType::Component` 与 `ComponentReference`,序列化格式同时保存 `gameObjectUUID` 与 `scriptComponentUUID`,从而能区分内建组件引用与脚本组件引用。
|
||||
- 当前刻意暂不支持抽象基类字段:`Component`、`Behaviour`、`MonoBehaviour`;这样先保证字段定位与场景 roundtrip 语义稳定,不把抽象匹配和 editor 复杂度提前拉进主线。
|
||||
- 已新增 `ComponentFieldMetadataProbe` / `ComponentFieldProbe` 与对应 C++ 回归测试,覆盖字段发现、默认空引用、存储值应用、运行时写回,以及场景 roundtrip 恢复。
|
||||
- 本步定向测试 `ScriptFieldStorage_Test.*:ScriptComponent_Test.*:MonoScriptRuntimeTest.ClassFieldMetadataListsConcreteComponentReferenceFields:MonoScriptRuntimeTest.ClassFieldDefaultValueQueryReturnsNullComponentReferences:MonoScriptRuntimeTest.ComponentReferenceFieldsApplyStoredValuesAndPersistAcrossSceneRoundTrip` 全部通过。
|
||||
- 扩大回归 `ScriptFieldStorage_Test.*:MonoScriptRuntimeTest.*:ProjectScriptAssemblyTest.*` 日志层面全绿;当前测试进程仍存在历史性的异常退出码现象,需要后续单独跟踪,不是本步引入的问题。
|
||||
- 字段系统下一步建议切到:资源引用字段,或等 editor Inspector 重构稳定后,再补组件字段的可视化选择器。
|
||||
@@ -1,446 +0,0 @@
|
||||
# Editor 架构说明
|
||||
|
||||
## 1. 当前目标
|
||||
|
||||
当前这一轮 editor 重构,目标不是继续在各个 panel 上零散修 UI,而是先把 editor 自身的架构层次收稳:
|
||||
|
||||
- 把视觉样式、交互路由、编辑命令、dock 布局、面板壳层拆开。
|
||||
- 把 `Hierarchy / Project / Inspector / Console / MenuBar` 统一到同一套 shared UI 和 action 语义上。
|
||||
- 把 `Scene / Game` viewport 保持在当前真实主链上:`ViewportHostService -> Rendering + RHI -> ImGui panel`。
|
||||
- 把 `Assets + .meta + Library` 项目工作流、脚本程序集构建与运行时状态纳入 editor 正式分层,而不是继续当外围脚本。
|
||||
|
||||
这意味着当前 editor 的重点已经不是“先把外壳搭出来”,而是:
|
||||
|
||||
- 在现有外壳分层上继续收口真实可运行的 viewport / project / scripting 主链。
|
||||
- 让 panel、viewport helper、commands、managers 和引擎侧 `Rendering / Resources / Scene / Scripting` 的边界继续清晰化。
|
||||
|
||||
## 2. 总体分层
|
||||
|
||||
当前 editor 推荐按下面的依赖方向理解:
|
||||
|
||||
`Application -> EditorLayer -> EditorWorkspace -> Panels/Viewport -> Actions -> Commands -> Managers/Core`
|
||||
|
||||
同时还有一条横向的共享 UI 层:
|
||||
|
||||
`Panels / Actions / ComponentEditors -> UI`
|
||||
|
||||
以及一条 inspector 专用扩展链路:
|
||||
|
||||
`InspectorPanel -> ComponentEditorRegistry -> IComponentEditor`
|
||||
|
||||
以及一条已经落地的 editor 到引擎主链:
|
||||
|
||||
`Viewport / Managers / Scripting -> Rendering / Resources / Scene / Scripting / RHI`
|
||||
|
||||
允许依赖的基本原则:
|
||||
|
||||
- `UI` 只负责样式 token、共享控件、popup/property-grid 等表现层能力,不承担业务语义。
|
||||
- `Actions` 负责把 button/menu/shortcut/context menu 这些 UI 意图转换为命令调用、事件请求或共享状态更新。
|
||||
- `Commands` 负责真正修改 scene/project/component 数据,并处理 dirty/undo/selection 的业务边界。
|
||||
- `Panels` 只保留最小的渲染壳层和少量局部瞬时状态,不直接堆业务逻辑。
|
||||
- `Layout` 只负责 dockspace 和布局持久化,不处理 scene/project 业务。
|
||||
- `Core/Managers` 提供 editor 运行时共享状态与数据入口。
|
||||
- `Viewport` 是 editor 宿主和引擎渲染主链之间的正式桥接层,不是 panel 内随手拼的辅助代码。
|
||||
|
||||
不允许继续扩散的方向:
|
||||
|
||||
- 不要在 panel 里直接散落 scene/project 业务修改。
|
||||
- 不要把菜单、快捷键、右键菜单逻辑分别复制到不同 panel。
|
||||
- 不要把样式常量重新写回 panel 本地。
|
||||
- 不要让 `UI` 反向依赖 `Commands` 或具体 panel。
|
||||
|
||||
## 3. 主要模块职责
|
||||
|
||||
### 3.1 Application / Platform
|
||||
|
||||
关键文件:
|
||||
|
||||
- `editor/src/Application.cpp`
|
||||
- `editor/src/Platform/Win32EditorHost.h`
|
||||
- `editor/src/Platform/D3D12WindowRenderer.h`
|
||||
- `editor/src/UI/ImGuiSession.h`
|
||||
- `editor/src/UI/ImGuiBackendBridge.h`
|
||||
|
||||
职责:
|
||||
|
||||
- 创建窗口、D3D12 renderer、ImGui session 与 backend bridge。
|
||||
- 初始化 `EditorContext`。
|
||||
- 监听 editor 级退出事件。
|
||||
- 驱动 layer attach/detach/update/render 主循环。
|
||||
- 更新窗口标题。
|
||||
|
||||
边界:
|
||||
|
||||
- 这里是 editor 的宿主壳层,不负责具体 panel 交互。
|
||||
- 这里可以处理平台与渲染 backend 生命周期,但不应该继续写 editor 业务逻辑。
|
||||
|
||||
### 3.2 EditorLayer / EditorWorkspace
|
||||
|
||||
关键文件:
|
||||
|
||||
- `editor/src/Layers/EditorLayer.cpp`
|
||||
- `editor/src/Core/EditorWorkspace.h`
|
||||
|
||||
职责:
|
||||
|
||||
- `EditorLayer` 只做 layer 生命周期转发。
|
||||
- `EditorWorkspace` 负责组装 panel 集合、初始化 project panel、加载启动场景、挂接 dock layout controller。
|
||||
- 统一调度 panel 的 attach/detach/update/render/event。
|
||||
|
||||
边界:
|
||||
|
||||
- `EditorLayer` 不能回到“自己直接维护一堆 panel 生命周期”的旧结构。
|
||||
- 新增 panel 时,优先在 `EditorWorkspace` 里做装配,不回写到 `Application`。
|
||||
|
||||
### 3.3 UI Shared Layer
|
||||
|
||||
关键文件:
|
||||
|
||||
- `editor/src/UI/BaseTheme.h`
|
||||
- `editor/src/UI/StyleTokens.h`
|
||||
- `editor/src/UI/DockHostStyle.h`
|
||||
- `editor/src/UI/PanelChrome.h`
|
||||
- `editor/src/UI/Widgets.h`
|
||||
- `editor/src/UI/PopupState.h`
|
||||
- `editor/src/UI/PropertyGrid.h`
|
||||
- `editor/src/UI/UI.h`
|
||||
|
||||
职责:
|
||||
|
||||
- 提供 editor 统一主题、尺寸、留白、颜色和面板 chrome。
|
||||
- 提供 toolbar、tab、popup、dialog、property row、asset tile、empty state 等共享控件。
|
||||
- 提供 inspector/property-grid 的公共表现层。
|
||||
|
||||
边界:
|
||||
|
||||
- 这一层可以知道 ImGui,但不应该知道 scene/project 业务对象如何变化。
|
||||
- 这一层输出的是“怎样画”,不是“点了以后改什么”。
|
||||
|
||||
### 3.4 Actions / Routers
|
||||
|
||||
关键文件:
|
||||
|
||||
- `editor/src/Actions/EditorActions.h`
|
||||
- `editor/src/Actions/ActionBinding.h`
|
||||
- `editor/src/Actions/ActionRouting.h`
|
||||
- `editor/src/Actions/EditActionRouter.h`
|
||||
- `editor/src/Actions/MainMenuActionRouter.h`
|
||||
- `editor/src/Actions/HierarchyActionRouter.h`
|
||||
- `editor/src/Actions/ProjectActionRouter.h`
|
||||
- `editor/src/Actions/InspectorActionRouter.h`
|
||||
- `editor/src/Actions/ConsoleActionRouter.h`
|
||||
|
||||
职责:
|
||||
|
||||
- 定义 editor 内部动作项的文案、快捷键、可用状态。
|
||||
- 统一菜单点击、快捷键触发、toolbar 按钮、右键菜单动作。
|
||||
- 处理 active route/focused route,把 `Edit` 类动作路由到正确 panel。
|
||||
- 处理 popup 请求、rename 请求、局部状态切换等“轻量交互编排”。
|
||||
|
||||
边界:
|
||||
|
||||
- `Actions` 可以依赖 `Commands`、`EventBus`、`UI`,但不负责底层数据结构修改细节。
|
||||
- `Actions` 不负责持久保存复杂状态;复杂状态应留给 manager 或共享 state object。
|
||||
- `Actions` 不应该包含大量 panel 私有布局代码。
|
||||
|
||||
判断标准:
|
||||
|
||||
- 一个交互如果同时被 menu、shortcut、context menu、toolbar 复用,它应先进入 router。
|
||||
- 一个交互如果只是“请求 panel 开一个 popup/进入 rename”,更适合走 `Actions + EventBus/shared state`。
|
||||
|
||||
### 3.5 Commands
|
||||
|
||||
关键文件:
|
||||
|
||||
- `editor/src/Commands/SceneCommands.h`
|
||||
- `editor/src/Commands/EntityCommands.h`
|
||||
- `editor/src/Commands/ProjectCommands.h`
|
||||
- `editor/src/Commands/ComponentCommands.h`
|
||||
|
||||
职责:
|
||||
|
||||
- 处理 scene/project/component 的实际编辑行为。
|
||||
- 统一 undo 快照、dirty 标记、selection reset 等业务边界。
|
||||
- 统一保存、加载、复制、粘贴、重命名、重挂接、资源移动等操作。
|
||||
|
||||
边界:
|
||||
|
||||
- `Commands` 不依赖 ImGui。
|
||||
- `Commands` 不直接绘制 UI。
|
||||
- `Commands` 返回的是业务结果,不承载 popup 绘制和菜单拼装。
|
||||
|
||||
经验规则:
|
||||
|
||||
- 只要一个操作会改 scene/project 数据,就优先考虑落到 `Commands`。
|
||||
- 只要一个操作涉及 undo/redo,就不要留在 panel 本地手写。
|
||||
|
||||
### 3.6 Core / Managers
|
||||
|
||||
关键文件:
|
||||
|
||||
- `editor/src/Core/EditorContext.h`
|
||||
- `editor/src/Core/EventBus.h`
|
||||
- `editor/src/Core/SelectionManager.h`
|
||||
- `editor/src/Core/UndoManager.h`
|
||||
- `editor/src/Managers/SceneManager.h`
|
||||
- `editor/src/Managers/ProjectManager.h`
|
||||
|
||||
职责:
|
||||
|
||||
- `EditorContext` 聚合 event bus、selection、scene、project、undo、active action route。
|
||||
- `SceneManager` 持有场景对象、根节点、场景路径、dirty 状态、clipboard。
|
||||
- `ProjectManager` 扫描 `Assets`、维护当前目录、选择索引、文件夹导航。
|
||||
- `SelectionManager` 统一发布 selection changed 事件。
|
||||
- `UndoManager` 负责快照历史、interactive change 边界、undo/redo。
|
||||
|
||||
所有权约定:
|
||||
|
||||
- selection 所有权在 `SelectionManager`。
|
||||
- undo 历史所有权在 `UndoManager`。
|
||||
- scene dirty 与当前场景路径所有权在 `SceneManager`。
|
||||
- 当前活动编辑路由所有权在 `EditorContext`。
|
||||
|
||||
### 3.7 Layout
|
||||
|
||||
关键文件:
|
||||
|
||||
- `editor/src/Layout/DockLayoutController.h`
|
||||
|
||||
职责:
|
||||
|
||||
- 创建 dockspace。
|
||||
- 应用默认布局。
|
||||
- 响应 reset layout 请求。
|
||||
- 持久化 ImGui layout 到项目目录下的 `.xceditor/imgui_layout.ini`。
|
||||
|
||||
边界:
|
||||
|
||||
- layout controller 不应该知道 hierarchy/project/scene 的编辑业务。
|
||||
- panel 是否存在由 workspace 决定,不由 layout controller 反向创建。
|
||||
|
||||
### 3.8 Panels
|
||||
|
||||
关键文件:
|
||||
|
||||
- `editor/src/panels/MenuBar.cpp`
|
||||
- `editor/src/panels/HierarchyPanel.cpp`
|
||||
- `editor/src/panels/ProjectPanel.cpp`
|
||||
- `editor/src/panels/InspectorPanel.cpp`
|
||||
- `editor/src/panels/ConsolePanel.cpp`
|
||||
|
||||
当前 panel 应保留的内容:
|
||||
|
||||
- 窗口壳层。
|
||||
- 生命周期订阅与退订。
|
||||
- 非共享的极少量局部瞬时状态。
|
||||
- 调用 shared UI/widget 和 action router 进行拼装。
|
||||
|
||||
当前 panel 不应该再承载的内容:
|
||||
|
||||
- undo/dirty/selection 的业务判断。
|
||||
- 菜单和快捷键的重复定义。
|
||||
- 资源/实体操作的底层命令执行细节。
|
||||
- 大量散落的视觉常量。
|
||||
|
||||
### 3.9 ComponentEditors
|
||||
|
||||
关键文件:
|
||||
|
||||
- `editor/src/ComponentEditors/IComponentEditor.h`
|
||||
- `editor/src/ComponentEditors/ComponentEditorRegistry.h`
|
||||
- `editor/src/ComponentEditors/ComponentEditorRegistry.cpp`
|
||||
- `editor/src/ComponentEditors/TransformComponentEditor.h`
|
||||
- `editor/src/ComponentEditors/CameraComponentEditor.h`
|
||||
- `editor/src/ComponentEditors/LightComponentEditor.h`
|
||||
|
||||
职责:
|
||||
|
||||
- 为某一类 component 提供 inspector 内容绘制。
|
||||
- 定义该 component 的显示名、是否能添加、是否能删除、添加禁用原因。
|
||||
- 通过 registry 统一注册到 inspector 与 component commands。
|
||||
|
||||
当前注册机制:
|
||||
|
||||
- `ComponentEditorRegistry` 是 editor 侧单例注册表。
|
||||
- 注册发生在 `ComponentEditorRegistry` 构造函数内。
|
||||
- `RegisterEditor(std::unique_ptr<IComponentEditor>)` 将 editor 同时放入顺序列表和按类型名索引表。
|
||||
- inspector 绘制时通过 component 实例类型名查找 editor。
|
||||
- Add Component 菜单通过遍历 registry 的已注册 editor 生成。
|
||||
- `ComponentCommands` 通过相同 registry 复用 add/remove 规则,而不是在 inspector 单独硬编码。
|
||||
|
||||
这套机制的意义:
|
||||
|
||||
- inspector 的“显示逻辑”和“组件增删能力”在同一处收口。
|
||||
- 新增一个 component editor 时,不需要去 panel 里到处补分支。
|
||||
- 后续如果要做脚本组件、自定义组件 inspector,优先扩展 registry,而不是污染 panel。
|
||||
|
||||
新增 component editor 的推荐步骤:
|
||||
|
||||
1. 新建一个实现 `IComponentEditor` 的 editor。
|
||||
2. 在其中定义 `GetComponentTypeName / GetDisplayName / Render / CanAddTo / CanRemove`。
|
||||
3. 在 `ComponentEditorRegistry.cpp` 注册。
|
||||
4. 如果涉及复杂交互,优先复用 `UI::PropertyGrid` 和 undo interactive change 机制。
|
||||
|
||||
### 3.10 Viewport
|
||||
|
||||
关键文件:
|
||||
|
||||
- `editor/src/Viewport/ViewportHostService.h`
|
||||
- `editor/src/Viewport/IViewportHostService.h`
|
||||
- `editor/src/Viewport/SceneViewportChrome.h`
|
||||
- `editor/src/Viewport/SceneViewportInteractionFrame.h`
|
||||
- `editor/src/Viewport/SceneViewportNavigation.h`
|
||||
- `editor/src/Viewport/SceneViewportTransformGizmoCoordinator.h`
|
||||
- `editor/src/Viewport/SceneViewportOverlayBuilder.h`
|
||||
- `editor/src/Viewport/SceneViewportOverlayFrameCache.h`
|
||||
- `editor/src/Viewport/SceneViewportOverlaySpriteResources.h`
|
||||
- `editor/src/Viewport/SceneViewportResourcePaths.h`
|
||||
- `editor/src/Viewport/Passes/SceneViewportEditorOverlayPass.h`
|
||||
|
||||
职责:
|
||||
|
||||
- 作为 editor 宿主与引擎 `Rendering + RHI` 的桥接层,维护 Scene / Game viewport 的离屏渲染接线。
|
||||
- 维护当前 Scene View helper 主链:
|
||||
- `SceneViewportChrome`
|
||||
- `SceneViewportInteractionFrame`
|
||||
- `SceneViewportNavigation`
|
||||
- `SceneViewportTransformGizmoCoordinator`
|
||||
- `ViewportHostService`
|
||||
- 负责 overlay builder、overlay frame cache、sprite 资源准备、object-id picking、grid、outline 和 gizmo overlay state。
|
||||
|
||||
边界:
|
||||
|
||||
- `Viewport` 是正式子系统,不再是“等待未来回归”的空位。
|
||||
- panel 不应自己拼接一套独立渲染路径;新的 viewport 行为优先落到 helper、host service 或 overlay pass。
|
||||
- `SceneViewportShaderPaths.h` 当前主要是兼容 include;资源路径真实 owner 已经转到 `SceneViewportResourcePaths.h`。
|
||||
|
||||
### 3.11 Scripting / Project Workflow
|
||||
|
||||
关键文件:
|
||||
|
||||
- `editor/src/Scripting/EditorScriptAssemblyBuilder.h`
|
||||
- `editor/src/Scripting/EditorScriptRuntimeStatus.h`
|
||||
- `editor/src/Managers/ProjectManager.h`
|
||||
- `editor/src/Managers/SceneManager.h`
|
||||
- `editor/src/Utils/ProjectFileUtils.h`
|
||||
|
||||
职责:
|
||||
|
||||
- 解析项目根目录、读写 `Project.xcproject`,并把仓库内 `project/` 或 `--project <path>` 解析为当前工程。
|
||||
- 驱动 `Assets + .meta + Library` 风格项目 workflow,包括项目资源浏览、脚本程序集重建入口和运行时状态反馈。
|
||||
- 把项目脚本程序集与 editor/runtime 实际消费的 `Library/ScriptAssemblies/` 目录连接起来。
|
||||
|
||||
边界:
|
||||
|
||||
- 与项目资产、`.meta`、`Library`、脚本程序集相关的问题,不应再按“editor 仍处于无工程状态”理解。
|
||||
- `ProjectManager`、`SceneManager`、`EditorScriptAssemblyBuilder` 与引擎侧 `ResourceManager / AssetImportService / ScriptEngine` 是协作关系,不应在 panel 里各自复制一层状态机。
|
||||
|
||||
## 4. EventBus 使用规则
|
||||
|
||||
`EventBus` 现在主要承担两类职责:
|
||||
|
||||
- editor 范围的状态通知,例如 selection changed、entity created/deleted、scene changed。
|
||||
- UI 请求类事件,例如 rename request、exit request、reset layout request。
|
||||
|
||||
推荐规则:
|
||||
|
||||
- “请求某个 panel 进入某种 UI 状态”时,优先用事件或共享 popup state。
|
||||
- “真正修改数据”时,优先走 command,不要只发 event 期待别人去改数据。
|
||||
- 事件用于解耦,不用于隐藏业务路径。
|
||||
|
||||
一个简单判断:
|
||||
|
||||
- 如果动作需要 undo/dirty,通常应该先有 `Command`。
|
||||
- 如果动作只是让某个 panel 弹窗或进入 rename,通常可以只发 `Event`。
|
||||
|
||||
## 5. Undo / Dirty / Selection 约定
|
||||
|
||||
这是 editor 最容易再次失控的地方,必须保持统一:
|
||||
|
||||
- scene 数据修改通过 `Commands` 收口。
|
||||
- `UndoUtils::ExecuteSceneCommand(...)` 负责把一次编辑包成可回退命令。
|
||||
- inspector 连续拖拽这类交互,使用 interactive change 边界,不在 panel 里手搓多次提交。
|
||||
- 场景切换、新建场景、加载场景后,selection 与 undo 历史由 scene command 统一重置。
|
||||
- scene dirty 由 `SceneManager` 维护,保存成功后归零。
|
||||
|
||||
禁止事项:
|
||||
|
||||
- 不要在 panel 里直接偷偷 `MarkSceneDirty()` 来替代 command。
|
||||
- 不要让某个 panel 自己保存一份 selection。
|
||||
- 不要让快捷键直接跨过 command 改 manager。
|
||||
|
||||
## 6. 快捷键与菜单路由规则
|
||||
|
||||
当前 editor 已形成两条主路由:
|
||||
|
||||
- `MainMenuActionRouter` 负责 `File / View / Help / global shortcut`。
|
||||
- `EditActionRouter` 负责 `Edit` 菜单和 panel-focused edit shortcut。
|
||||
|
||||
约定:
|
||||
|
||||
- `Global` 类快捷键由 menu bar 统一分发。
|
||||
- `Hierarchy / Project` 等焦点相关动作,先根据 `EditorActionRoute` 解析目标,再执行对应 action。
|
||||
- panel 只负责声明自己何时成为 active route,不负责重复实现整套 edit 菜单。
|
||||
|
||||
这样做的收益:
|
||||
|
||||
- 同一个动作不会再出现“菜单能点、快捷键失效、右键菜单又是另一套”的问题。
|
||||
- 后续增加新 panel 的编辑语义时,只需要接入 route,不必复制整套菜单逻辑。
|
||||
|
||||
## 7. 当前已完成与明确暂缓的部分
|
||||
|
||||
已完成的重点:
|
||||
|
||||
- 统一 UI token、panel chrome、popup/property-grid/shared widgets。
|
||||
- menu/shortcut/context menu/action 的大部分共享路由。
|
||||
- scene/project/entity/component 的主要编辑命令收口。
|
||||
- dock layout controller 与 editor workspace 装配。
|
||||
- inspector 的 component editor registry 接入。
|
||||
- editor 级回归测试基础框架与关键命令测试。
|
||||
- `Scene / Game` viewport 已经重新接回当前正式主链:引擎 `Rendering + RHI` 离屏输出 -> `ViewportHostService` -> ImGui panel。
|
||||
- `Assets + .meta + Library` 项目工作流、`Project.xcproject`、脚本程序集重建与脚本运行时状态已经进入 editor 正式工作流。
|
||||
- viewport helper 已按 `Chrome -> InteractionFrame -> Navigation -> TransformGizmoCoordinator -> ViewportHostService` 显式拆层。
|
||||
|
||||
当前明确暂缓:
|
||||
|
||||
- 把 editor 主线程上残留的同步资源兜底点继续清理到更严格的异步消费模型。
|
||||
- 把 `Library bootstrap / scene streaming / explicit import` 的状态模型继续正式化到 UI。
|
||||
- 继续减少 panel 内局部瞬时状态与 helper 间重复规则。
|
||||
|
||||
原因很明确:
|
||||
|
||||
- 前三项已经不是“没接回来的未来工作”,而是已经落地、但还要继续收口的当前主线。
|
||||
|
||||
## 8. 后续新增功能时的落点原则
|
||||
|
||||
如果以后继续扩 editor,推荐按下面的判断落点:
|
||||
|
||||
- 新视觉样式或共享控件:放 `UI`
|
||||
- 新菜单项/快捷键/右键菜单复用:放 `Actions`
|
||||
- 新的 scene/project/component 编辑行为:放 `Commands`
|
||||
- 新 inspector 组件面板:放 `ComponentEditors`
|
||||
- 新 dock/window 布局控制:放 `Layout`
|
||||
- 新 editor 全局状态:放 `Core/Managers`
|
||||
- 新 viewport host / overlay / interaction helper:放 `Viewport`
|
||||
- 只是把已有能力拼进某个窗口:放 `Panels`
|
||||
|
||||
如果一个功能不知道放哪,一般先问自己:
|
||||
|
||||
- 它是不是只关乎“怎么画”?
|
||||
- 它是不是多个入口共享的交互?
|
||||
- 它是不是会真正改数据并进入 undo?
|
||||
|
||||
这三个问题基本能把落点判断清楚。
|
||||
|
||||
## 9. 当前收尾阶段剩余事项
|
||||
|
||||
从 UI 架构角度看,当前已经不是“推倒重来”阶段,而是最后的封口阶段。剩余事项主要有:
|
||||
|
||||
- 继续压缩少量 panel 本地瞬时状态,能下沉的继续下沉。
|
||||
- 继续补命令/路由回归测试,尤其是 inspector interactive undo 边界。
|
||||
- 继续补 viewport helper、project workflow、script assembly builder 与 scene streaming 相关回归测试。
|
||||
- 把 `Library bootstrap`、显式导入、后台 scene asset streaming 这三类状态在 editor UI 上分开表达。
|
||||
|
||||
结论:
|
||||
|
||||
editor 当前已经形成稳定分层,而且这套分层已经承接了真实的 viewport / project / scripting 工作流。后面再做功能迭代时,应坚持“先看边界,再落代码”,不要回到 panel 内部堆逻辑的旧路线。
|
||||
@@ -1,227 +0,0 @@
|
||||
# MainLight 方向光阴影修复计划
|
||||
|
||||
日期: `2026-04-13`
|
||||
|
||||
## 1. 文档定位
|
||||
|
||||
这份文档是基于当前仓库代码状态重新整理的版本,用来承接 MainLight 单张方向光阴影的后续修复工作。
|
||||
|
||||
需要明确:
|
||||
|
||||
- 这不是对之前已删除计划文件的逐字恢复。
|
||||
- 这是一份按当前实现状态、最近两次提交和现有阴影链路重新整理的执行计划。
|
||||
- 当前目标不是上级联阴影,而是先把单张 MainLight 阴影做到可用。
|
||||
|
||||
## 2. 当前问题定义
|
||||
|
||||
当前 MainLight 阴影已经具备从规划、投射到接收采样的完整闭环,但实际效果仍然不可用,核心问题有两个:
|
||||
|
||||
1. 自阴影过重,表面出现明显 acne。
|
||||
2. 阴影边缘呈现大块锯齿,采样质量不足。
|
||||
|
||||
当前阶段暂不解决:
|
||||
|
||||
- 级联阴影
|
||||
- 点光 / 聚光阴影
|
||||
- 阴影时域稳定与降噪的完整方案
|
||||
- 多光源阴影编排
|
||||
|
||||
## 3. 当前阴影链路梳理
|
||||
|
||||
当前单张 MainLight 阴影主链如下:
|
||||
|
||||
`SceneRenderRequestPlanner`
|
||||
-> `DirectionalShadowRenderPlan`
|
||||
-> `CameraRenderer`
|
||||
-> `ShadowCaster Pass`
|
||||
-> `RenderSceneData::lighting.mainDirectionalShadow`
|
||||
-> `BuiltinForwardPipeline`
|
||||
-> `forward-lit.shader / Toon.shader`
|
||||
|
||||
关键代码位置:
|
||||
|
||||
- 规划层
|
||||
- `engine/include/XCEngine/Rendering/Planning/SceneRenderRequestPlanner.h`
|
||||
- `engine/src/Rendering/Planning/Internal/DirectionalShadowPlanning.cpp`
|
||||
- 请求与运行时数据
|
||||
- `engine/include/XCEngine/Rendering/Planning/CameraRenderRequest.h`
|
||||
- `engine/include/XCEngine/Rendering/FrameData/RenderSceneData.h`
|
||||
- `engine/src/Rendering/Execution/CameraRenderer.cpp`
|
||||
- ShadowCaster 消费 bias
|
||||
- `engine/include/XCEngine/Rendering/Passes/BuiltinDepthStylePassBase.h`
|
||||
- `engine/src/Rendering/Passes/BuiltinDepthStylePassBaseResources.cpp`
|
||||
- `engine/assets/builtin/shaders/shadow-caster.shader`
|
||||
- 接收端采样
|
||||
- `engine/src/Rendering/Pipelines/BuiltinForwardPipeline.cpp`
|
||||
- `engine/assets/builtin/shaders/forward-lit.shader`
|
||||
- `project/Assets/Shaders/Toon.shader`
|
||||
|
||||
## 4. 已完成阶段
|
||||
|
||||
### Phase 0:阴影参数契约正式化
|
||||
|
||||
已完成,目标是先把原来散落在不同位置的 shadow 参数收成正式数据契约。
|
||||
|
||||
对应提交:
|
||||
|
||||
- `2ee74e7` `rendering: formalize main light shadow params`
|
||||
|
||||
完成结果:
|
||||
|
||||
- MainLight shadow 的 map metrics / sampling 数据有了明确结构。
|
||||
- 规划层到运行时数据链路不再依赖匿名 float 参数拼装。
|
||||
|
||||
### Phase 1:bias 设置正式化并接入 ShadowCaster
|
||||
|
||||
已完成,目标是把 caster bias 和 receiver bias 的职责拆清楚,并让 ShadowCaster 真正消费运行时设置。
|
||||
|
||||
对应提交:
|
||||
|
||||
- `1d6f2e2` `rendering: formalize main light shadow bias settings`
|
||||
|
||||
完成结果:
|
||||
|
||||
- 新增 `DirectionalShadowSamplingSettings`
|
||||
- 新增 `DirectionalShadowCasterBiasSettings`
|
||||
- planner 能输出 sampling / caster bias 默认值
|
||||
- `ShadowCaster` pass 不再依赖 shader 内部写死的 `Offset`
|
||||
- forward / toon 接收端继续消费统一的 shadow sampling contract
|
||||
|
||||
## 5. 根因判断
|
||||
|
||||
### 5.1 自阴影严重的根因
|
||||
|
||||
当前 acne 的根因不是单一问题,而是以下几项叠加:
|
||||
|
||||
1. caster bias 与 receiver bias 原先没有清晰契约,调参入口混乱。
|
||||
2. receiver 端 normal bias 和 depth bias 默认值没有经过系统标定。
|
||||
3. caster 端深度偏移之前由 shader 写死,无法和场景尺度、shadow map texel 尺度统一调整。
|
||||
|
||||
### 5.2 阴影锯齿严重的根因
|
||||
|
||||
当前接收端虽然已经做了一个固定 3x3 手写采样,但效果仍然偏糙,原因主要是:
|
||||
|
||||
1. 当前仍然是单张 shadow map,分辨率预算有限。
|
||||
2. 阴影采样核是最基础的固定 3x3 box,没有更平滑的权重设计。
|
||||
3. `BuiltinForwardPipeline` 里的 shadow sampler 目前仍是 point sampler。
|
||||
4. 当前还没有专门面向“单张 MainLight 阴影可用性”的 filter 参数设计。
|
||||
|
||||
### 5.3 当前不应优先处理的方向
|
||||
|
||||
以下方向现在都不是第一优先级:
|
||||
|
||||
- 直接上级联阴影
|
||||
- 直接引入更复杂的多光源阴影系统
|
||||
- 先大改 planner 架构
|
||||
|
||||
原因很简单:如果当前单张阴影的 bias 和 filter 基线都没有站稳,上级方案只会把问题放大。
|
||||
|
||||
## 6. 下一阶段执行顺序
|
||||
|
||||
## Phase 2:建立可用的 bias 基线
|
||||
|
||||
这是下一步最高优先级。
|
||||
|
||||
目标:
|
||||
|
||||
- 明显压住自阴影 acne
|
||||
- 不引入明显 peter-panning
|
||||
- 让不同材质和几何体至少达到“能看”的单张阴影结果
|
||||
|
||||
本阶段只调这四个核心参数:
|
||||
|
||||
- `DirectionalShadowCasterBiasSettings.depthBiasFactor`
|
||||
- `DirectionalShadowCasterBiasSettings.depthBiasUnits`
|
||||
- `DirectionalShadowSamplingSettings.receiverDepthBias`
|
||||
- `DirectionalShadowSamplingSettings.normalBiasScale`
|
||||
|
||||
执行要点:
|
||||
|
||||
1. 先以默认值为基线做小步调参,不再混用 shader 内固定 offset。
|
||||
2. 先看 caster bias 是否足以压掉大面积 acne,再看 receiver bias 是否还需要补偿。
|
||||
3. `normalBiasScale` 只用于削减掠射角表面 acne,不能把它当成主修复手段。
|
||||
4. 调参顺序优先保证“角色和常见静态模型表面不脏”,再控制阴影悬浮。
|
||||
|
||||
验收标准:
|
||||
|
||||
- 球、立方体、角色模型等常见几何体上没有大片自阴影脏斑。
|
||||
- 接触阴影没有整体漂浮一截。
|
||||
- forward-lit 与 toon 两条接收路径结果一致性不回退。
|
||||
|
||||
## Phase 3:升级单张阴影采样质量
|
||||
|
||||
这个阶段才开始处理“大块锯齿”。
|
||||
|
||||
目标:
|
||||
|
||||
- 让当前单张 MainLight shadow 的边缘从“块状锯齿”变成“有限预算下可接受的软化边缘”
|
||||
|
||||
优先处理项:
|
||||
|
||||
1. 升级当前固定 3x3 box 采样,不再停留在最基础平均核。
|
||||
2. 明确是否继续走跨后端一致的手写 PCF,还是为 comparison sampler 单独补后端支持。
|
||||
3. 如果继续保持跨后端一致性优先,则先做更好的手写 PCF 核,再评估 comparison sampler。
|
||||
|
||||
本阶段建议的最小落地方案:
|
||||
|
||||
- 先保留单张 shadow map
|
||||
- 先保留当前主链结构
|
||||
- 把 receiver 端阴影采样从固定 3x3 平均核升级为更稳定的 PCF 核
|
||||
- 如有必要,再补 `filterRadiusInTexels` 一类的正式参数
|
||||
|
||||
验收标准:
|
||||
|
||||
- 阴影边缘不再呈现明显的 1-bit 台阶块状感。
|
||||
- 角色和场景静态物体阴影边缘的可读性明显提升。
|
||||
- 不因为滤波升级导致阴影整体发灰或漏光严重。
|
||||
|
||||
## Phase 4:单张方向光阴影稳定性收口
|
||||
|
||||
在 bias 和 filter 达到可用以后,再收口稳定性问题。
|
||||
|
||||
目标:
|
||||
|
||||
- 降低相机轻微移动时的 shadow crawl / shimmering
|
||||
|
||||
重点项:
|
||||
|
||||
1. 审查当前 shadow camera 拟合结果是否需要 texel snapping。
|
||||
2. 审查 ortho bounds 与 focus point 的稳定性。
|
||||
3. 重新评估 `boundsPadding` / `minDepthPadding` / `minDepthRange` 的默认值是否过保守或过激进。
|
||||
|
||||
说明:
|
||||
|
||||
这一阶段仍然是“单张 MainLight 阴影修好”,不是进入级联阴影。
|
||||
|
||||
## Phase 5:为后续级联阴影预留演进点
|
||||
|
||||
只有前面几个阶段都稳定后,才进入这一阶段。
|
||||
|
||||
目标:
|
||||
|
||||
- 让当前单张 MainLight 阴影实现不阻塞未来 CSM 演进
|
||||
|
||||
需要预留但暂不展开的点:
|
||||
|
||||
- split 数据结构
|
||||
- 每级 shadow map / sampler / matrix contract
|
||||
- 接收端 cascade 选择逻辑
|
||||
- 级联间过渡和稳定化
|
||||
|
||||
## 7. 推荐的提交切分
|
||||
|
||||
后续建议按下面的提交粒度推进:
|
||||
|
||||
1. `rendering: tune main light shadow bias defaults`
|
||||
2. `rendering: improve main light shadow receiver filtering`
|
||||
3. `rendering: stabilize single-map directional shadow fitting`
|
||||
|
||||
## 8. 当前结论
|
||||
|
||||
当前正确的下一步不是“直接做级联阴影”,而是:
|
||||
|
||||
1. 先把 bias 默认值标定到可用区间。
|
||||
2. 再把当前接收端采样升级成真正可用的单张 shadow filter。
|
||||
3. 最后再处理单张阴影稳定性。
|
||||
|
||||
只有这三步完成,当前 MainLight 阴影才算真正脱离“占位实现”。
|
||||
@@ -1,174 +0,0 @@
|
||||
# Nahida Unity式Model导入与Genshin卡通渲染正式化计划
|
||||
|
||||
日期:2026-04-11
|
||||
|
||||
## 1. 目标
|
||||
|
||||
这一轮不再按“静态拆件预览”推进,而是正式切到更接近 Unity 的方案:
|
||||
|
||||
- FBX/OBJ 等外部模型统一作为 `Model` 主资产导入
|
||||
- 场景侧通过 `Model -> GameObject hierarchy` 实例化恢复节点层级
|
||||
- `Mesh` 继续只负责底层几何与 section/material slot
|
||||
- Nahida 的卡通渲染改为“对齐 Unity 旧工程 `Genshin.shader` 语义”,而不是继续维持近似版 shader
|
||||
|
||||
本轮仍然明确不做:
|
||||
|
||||
- 骨骼动画
|
||||
- GPU skinning
|
||||
- `SkinnedMeshRenderer` 运行时
|
||||
- BlendShape
|
||||
- Animator / AnimationClip 播放系统
|
||||
|
||||
## 2. 当前判断
|
||||
|
||||
### 2.1 Model链路已经具备的能力
|
||||
|
||||
代码里已经有以下基础设施:
|
||||
|
||||
- `ResourceType::Model`
|
||||
- `Model` / `ModelLoader`
|
||||
- `xcmodel` artifact
|
||||
- `AssimpModelImporter`
|
||||
- `AssetDatabase` 中 `ModelImporter` 以 `Model` 为主资产导入
|
||||
- sub-asset manifest 与 `LocalID -> artifact path` 解析
|
||||
|
||||
这说明“Unity式 Model 主资产”不是从零开始,而是缺最后几段关键闭环。
|
||||
|
||||
### 2.2 当前最主要的缺口
|
||||
|
||||
真正还没闭环的是:
|
||||
|
||||
1. `Model` 还不能正式实例化成场景层级
|
||||
2. `MeshFilter/MeshRenderer` 还缺稳定的 sub-asset `AssetRef` 绑定入口
|
||||
3. 编辑器侧还没有把模型资产当成“可实例化层级对象”来用
|
||||
4. Nahida 当前 `XCCharacterToon.shader` 不是 Unity 旧工程 `Genshin.shader` 的等价移植
|
||||
5. FBX 导入后的静态 mesh 目前丢失了 Unity shader 依赖的顶点语义,尤其是 `vertex color` 与 `UV1/backUV`
|
||||
|
||||
### 2.3 关于当前 shader 的明确结论
|
||||
|
||||
当前使用的是:
|
||||
|
||||
- `project/Assets/Shaders/XCCharacterToon.shader`
|
||||
|
||||
Unity 参考原件是:
|
||||
|
||||
- `docs/reference/NahidaUnity/Shaders/Genshin.shader`
|
||||
- `docs/reference/NahidaUnity/Shaders/GenshinInput.hlsl`
|
||||
- `docs/reference/NahidaUnity/Shaders/GenshinForwardPass.hlsl`
|
||||
- `docs/reference/NahidaUnity/Shaders/GenshinOutlinePass.hlsl`
|
||||
|
||||
当前 shader 只是第一版近似实现,不是原 shader 原样移植。当前效果发怪,核心原因不是简单调参,而是语义缺口:
|
||||
|
||||
1. 没有按 Unity 的 `_IS_FACE / _SPECULAR / _RIM / _NORMAL_MAP / _DOUBLE_SIDED` 关键字分支工作
|
||||
2. 面部阴影没有按 `_FaceDirection + _FaceLightMap + _FaceShadow + _FaceShadowOffset` 的逻辑算
|
||||
3. 阴影 ramp 还没有按 Unity 的 material ID 分层抽样
|
||||
4. specular 还不是 Unity 那套 `lightMap + metalMap + matcap` 路径
|
||||
5. rim 不是基于 scene depth 的 URP 风格边缘检测
|
||||
6. outline pass 还没有正式接回 `Nahida_Body_Smooth.mesh` 与 outline color 分档逻辑
|
||||
7. Unity 里还有 `MaterialUpdater.cs` 在运行时写 `_FaceDirection`,当前引擎里这条驱动链不存在
|
||||
8. 更关键的是,当前引擎导入出的 Nahida mesh 只有 `Position/Normal/Tangent/Bitangent/UV0`,缺 `Color/UV1`
|
||||
9. Unity 的 `GenshinForwardPass.hlsl` 明确依赖 `input.color.r` 与 `backUV`
|
||||
10. 这会直接破坏 body/hair 分支的 `aoFactor = lightMap.g * input.color.r` 与双面材质背面采样,因此“脸基本对、身体和头发大面积偏色”是符合代码现状的结果
|
||||
|
||||
所以它现在看起来不像原工程,是正常结果。
|
||||
|
||||
## 3. 本轮正式范围
|
||||
|
||||
### Phase 1:Model实例化基础链路
|
||||
|
||||
目标:
|
||||
|
||||
- 把 `Model` 正式实例化为场景 `GameObject` 层级
|
||||
|
||||
任务:
|
||||
|
||||
- 为 `MeshFilterComponent` 增加 mesh sub-asset `AssetRef` 绑定入口
|
||||
- 为 `MeshRendererComponent` 增加 material sub-asset `AssetRef` 绑定入口
|
||||
- 保证这些 sub-asset 引用能被场景序列化稳定保存
|
||||
- 新增 `Model -> Scene hierarchy` 实例化工具
|
||||
- 恢复节点本地 TRS
|
||||
- 恢复 mesh binding 与 material slot binding
|
||||
|
||||
验收:
|
||||
|
||||
- 导入一个 `OBJ/FBX Model` 后,可以在场景里创建出层级对象
|
||||
- 场景存盘后 sub-asset 引用不丢
|
||||
- 不需要把 FBX 拆成手工摆放的多个静态对象
|
||||
|
||||
### Phase 2:编辑器侧 Model使用工作流
|
||||
|
||||
目标:
|
||||
|
||||
- 让编辑器把 `Model` 当成 Unity 式模型资产使用
|
||||
|
||||
任务:
|
||||
|
||||
- 增加“从模型资产创建场景对象”的命令入口
|
||||
- 后续接到 Project/Hierarchy/Viewport 的拖拽放置链路
|
||||
- 让 Nahida 预览场景切到 `Model` 驱动的实例化路径
|
||||
|
||||
验收:
|
||||
|
||||
- 编辑器里不再主要依赖“手工往 `MeshFilter` 塞 FBX 路径”
|
||||
- Nahida 预览对象结构来自 `Model` 实例化,而不是手工拆件
|
||||
|
||||
### Phase 3:Genshin shader 语义对齐
|
||||
|
||||
目标:
|
||||
|
||||
- 让 Nahida 使用更接近 Unity 旧工程的卡通渲染语义
|
||||
|
||||
任务:
|
||||
|
||||
- 先补齐静态 mesh 顶点语义链路:`Color`、`UV1/backUV`
|
||||
- 让前向渲染输入布局与 `XCCharacterToon.shader` 能真正接到 `COLOR` 与 `TEXCOORD1`
|
||||
- 恢复 body/hair 分支里的 `lightMap.g * input.color.r`
|
||||
- 恢复双面材质对 `backUV` 的切换采样
|
||||
- 按 Unity 原 shader 拆分 forward / outline 两条主路径
|
||||
- 补 `_IS_FACE / _SPECULAR / _RIM / _NORMAL_MAP / _DOUBLE_SIDED` 语义
|
||||
- 补 face shadow 正式逻辑
|
||||
- 补 outline pass 与 `Nahida_Body_Smooth.mesh`
|
||||
- 视情况补一个轻量 `_FaceDirection` 运行时驱动
|
||||
|
||||
验收:
|
||||
|
||||
- 角色明暗分层、面部阴影、描边、头发高光接近 Unity 参考
|
||||
|
||||
## 4. 执行顺序
|
||||
|
||||
这一轮按下面顺序推进:
|
||||
|
||||
1. 先补 `Model` 实例化与 sub-asset 引用闭环
|
||||
2. 再把 Nahida 预览场景切到 `Model` 路径
|
||||
3. 再补 FBX 静态 mesh 的 `Color/UV1` 导入、artifact 保存、渲染输入布局与 shader 接线
|
||||
4. 再做 shader 语义对齐
|
||||
5. 最后做画面调参与残余语义收口
|
||||
|
||||
不能反过来做。因为当前 shader 再怎么调,只要场景组织和资源绑定语义不对,结果都不稳定。
|
||||
|
||||
## 5. 当前这一刀
|
||||
|
||||
这一轮立刻执行的第一刀是:
|
||||
|
||||
- 补齐 FBX 静态 mesh 的 `vertex color` 与 `UV1/backUV` 导入
|
||||
- 让 `BuiltinForwardPipeline` 与 `XCCharacterToon.shader` 真正吃到 `COLOR/TEXCOORD1`
|
||||
- 补 Nahida 集成诊断与回归验证,先把 body/hair 的基础色输入纠正
|
||||
- 在这个基础上继续向 Unity 式 `Model -> hierarchy` 与完整 shader 语义收口推进
|
||||
|
||||
这是 Nahida 当前从“基础贴图都不稳定”切回“先保证静态基础颜色正确”的前置条件,也是后续继续 Unity 式正式方案的必要补丁。
|
||||
|
||||
## 6. 2026-04-11 新发现补充
|
||||
|
||||
在实际跑 `tests/Rendering/integration/nahida_preview_scene` 之后,问题又进一步收窄了:
|
||||
|
||||
- Nahida 的 `Body_Mesh0` 运行时已经有 `uv1` 数值,且当前实现会在缺少第二套 UV 时回填 `uv1 = uv0`
|
||||
- 但导入器只在 `mesh.HasTextureCoords(1)` 为真时才打 `VertexAttribute::UV1` 标记
|
||||
- 结果就是:数据层面有 fallback `uv1`,语义层面却仍被当成“没有 UV1”
|
||||
- 这会导致后续依赖 `backUV` 的 shader / 诊断逻辑继续走错分支
|
||||
|
||||
因此当前这一刀的执行重点再精确一步,变成:
|
||||
|
||||
1. 修复 `AssimpModelImporter` / `MeshLoader` 中“fallback uv1 已写入但 `UV1` flag 未置位”的不一致
|
||||
2. 提升 `ModelImporter` 版本,强制 Nahida 现有 `.xcmodel` artifact 重导
|
||||
3. 补针对 Nahida FBX 的导入回归测试,确保 `UV1` fallback 与 `Color` 语义不会再次退化
|
||||
4. 再继续跑 Nahida 集成图验证 body/hair 基础色是否进一步收敛
|
||||
@@ -1,253 +0,0 @@
|
||||
# NewEditor 结构收口与正式迁移计划
|
||||
|
||||
日期: `2026-04-15`
|
||||
|
||||
## 1. 文档定位
|
||||
|
||||
这份文档是当前 `new_editor` 主线的唯一有效计划。
|
||||
|
||||
本轮已经把此前分散的 `NewEditor_*` 阶段性计划全部归档到 `docs/plan/used/`,原因不是这些计划完全错误,而是它们都只覆盖了某一段局部问题:
|
||||
|
||||
- 3D 渲染主链接入
|
||||
- 宿主重构
|
||||
- 无边框宿主采用
|
||||
- Tab 脱离独立窗口
|
||||
|
||||
当前主线已经进入新的阶段,继续靠这些局部计划推进,只会让执行顺序继续发散。
|
||||
|
||||
现在真正需要的是一份单一主线文档,把 `new_editor` 接下来必须先做完的结构收口路线写死。
|
||||
|
||||
## 2. 当前事实
|
||||
|
||||
### 2.1 已经具备的基础
|
||||
|
||||
当前 `new_editor` 已经不再是一个单纯的 UI 试验壳,已经具备继续向上承接正式编辑器重建的基础:
|
||||
|
||||
- `XCEditor` 库层已经形成明确目录边界:
|
||||
- `Collections`
|
||||
- `Docking`
|
||||
- `Fields`
|
||||
- `Foundation`
|
||||
- `Menu`
|
||||
- `Panels`
|
||||
- `Shell`
|
||||
- `Viewport`
|
||||
- `Workspace`
|
||||
- `new_editor/app` 宿主层也已经开始从旧的扁平 `Host/*` 结构,收敛为:
|
||||
- `Bootstrap`
|
||||
- `Platform`
|
||||
- `Rendering`
|
||||
- `Composition`
|
||||
- `Features`
|
||||
- `State`
|
||||
- `Support`
|
||||
- `UI`
|
||||
- `XCUIEditorApp` 当前可以稳定编译通过,说明宿主主链并没有断。
|
||||
|
||||
### 2.2 当前真正的主要问题
|
||||
|
||||
当前最大的阻塞已经不是“有没有这个面板”或者“某个小功能能不能先做出来”,而是结构债还没有清干净。
|
||||
|
||||
现在最明显的两个问题是:
|
||||
|
||||
1. `new_editor/app` 还处在一次目录迁移的中间态
|
||||
旧 `app/Host/*` 的删除和新 `Bootstrap / Platform / Rendering` 的接管同时存在,工作区里会看到大量 `D` 与 `??` 混杂。这说明方向是对的,但这次重构还没有形成一个真正干净的闭环。
|
||||
|
||||
2. `XCEditor` 库层还有几块超大实现文件没有拆干净
|
||||
目前最危险的热点主要集中在:
|
||||
- `Workspace`
|
||||
- `Docking`
|
||||
- `PropertyGrid`
|
||||
|
||||
如果不先收掉这两类结构债,后面继续往 `new_editor` 里迁产品层,只会继续把问题滚大。
|
||||
|
||||
## 3. 当前主线判断
|
||||
|
||||
当前主线不是继续加更多业务面板,也不是继续单点修某个局部交互。
|
||||
|
||||
当前主线固定为三步,顺序不能反:
|
||||
|
||||
1. 先把 `new_editor/app` 这次宿主目录迁移彻底收口
|
||||
2. 再把 `XCEditor` 库层几个最大热点文件拆薄并稳定下来
|
||||
3. 只有前两步完成后,才正式进入 `new_editor` 产品层迁移
|
||||
|
||||
这三步里,前两步是后续所有产品迁移的地基。
|
||||
|
||||
## 4. 不可违背的执行原则
|
||||
|
||||
### 4.1 先结构,后功能
|
||||
|
||||
在宿主层目录迁移和 `XCEditor` 热点拆分没有完成前,不继续扩写新的产品功能面板,不继续铺新的产品工作流。
|
||||
|
||||
### 4.2 不允许临时兼容层
|
||||
|
||||
不允许为了“先跑起来”继续加 wrapper、双入口、临时桥接壳、一次性兼容适配层。
|
||||
|
||||
要么把旧结构彻底迁走,要么明确保留为正式边界;不允许长期中间态并存。
|
||||
|
||||
### 4.3 Editor UI 不走 Runtime 的资源样式体系
|
||||
|
||||
`Runtime UI` 允许继续保留样式资源机制;
|
||||
`Editor UI` 不再往那条路径上加厚,编辑器样式固定在代码里。
|
||||
|
||||
### 4.4 问题必须从根因修
|
||||
|
||||
如果在迁移过程中暴露出:
|
||||
|
||||
- 宿主层边界错误
|
||||
- `XCEditor` 库层接口职责错误
|
||||
- 状态 owner 错位
|
||||
- 文件和目录层级不合理
|
||||
|
||||
必须先回到底层修根因,再继续往上迁。
|
||||
|
||||
## 5. 阶段 A:宿主目录迁移收口
|
||||
|
||||
### 5.1 目标
|
||||
|
||||
把 `new_editor/app` 从当前的“迁移进行中状态”收成一个正式、稳定、可继续扩展的宿主结构。
|
||||
|
||||
### 5.2 主要任务
|
||||
|
||||
1. 把旧 `app/Host/*` 体系彻底退场
|
||||
2. 确认新结构成为唯一正式入口:
|
||||
- `Bootstrap`
|
||||
- `Platform/Win32`
|
||||
- `Rendering/D3D12`
|
||||
- `Rendering/Native`
|
||||
- `Rendering/Viewport`
|
||||
- `Composition`
|
||||
3. 清理迁移残留:
|
||||
- CMake 源文件接线
|
||||
- include 路径
|
||||
- 旧头源文件引用
|
||||
- 目录层级命名不一致
|
||||
4. 把当前仍然过厚的宿主热点继续拆薄,但只做职责拆分,不改行为语义:
|
||||
- `BorderlessWindowChrome`
|
||||
- `EditorWindowLifecycle`
|
||||
- `ViewportHostService`
|
||||
- 其他仍然显著偏厚的宿主实现
|
||||
|
||||
### 5.3 完成标准
|
||||
|
||||
满足以下条件,阶段 A 才算完成:
|
||||
|
||||
- `new_editor/app` 不再同时保留旧 `Host/*` 正式实现和新目录正式实现
|
||||
- 目录边界对外清晰,职责一眼可读
|
||||
- `XCUIEditorApp` 编译通过
|
||||
- `XCUIEditor.exe` 运行不回退
|
||||
- 这次迁移可以形成一笔干净的 `refactor(new_editor/app): ...` 提交
|
||||
|
||||
## 6. 阶段 B:XCEditor 库层热点拆分收口
|
||||
|
||||
### 6.1 目标
|
||||
|
||||
在继续迁产品层之前,把 `XCEditor` 当前最容易继续膨胀成屎山的几块核心实现拆薄。
|
||||
|
||||
### 6.2 优先级
|
||||
|
||||
优先级固定为:
|
||||
|
||||
1. `Workspace`
|
||||
2. `Docking`
|
||||
3. `PropertyGrid`
|
||||
|
||||
也就是先处理这些热点:
|
||||
|
||||
- `new_editor/src/Workspace/UIEditorWorkspaceModel.cpp`
|
||||
- `new_editor/src/Workspace/UIEditorWorkspaceController.cpp`
|
||||
- `new_editor/src/Docking/UIEditorDockHost.cpp`
|
||||
- `new_editor/src/Docking/UIEditorDockHostInteraction.cpp`
|
||||
- `new_editor/src/Fields/UIEditorPropertyGrid.cpp`
|
||||
- `new_editor/src/Fields/UIEditorPropertyGridInteraction.cpp`
|
||||
|
||||
### 6.3 拆分原则
|
||||
|
||||
1. 按职责拆,不按“随便分行数”拆
|
||||
2. 模型、状态变换、命中测试、交互会话、渲染组织分开
|
||||
3. 不把产品层业务逻辑塞回库层
|
||||
4. 先保行为稳定,再收接口命名和文件粒度
|
||||
|
||||
### 6.4 完成标准
|
||||
|
||||
满足以下条件,阶段 B 才算完成:
|
||||
|
||||
- `Workspace / Docking / PropertyGrid` 三组热点都被拆成清晰子职责文件
|
||||
- 单文件复杂度明显下降,不再存在新的上千行核心实现文件继续堆积
|
||||
- 相关 unit / integration 测试仍可通过或至少能稳定编译
|
||||
- `XCUIEditorApp` 继续可编译运行
|
||||
|
||||
## 7. 阶段 C:正式进入 NewEditor 产品层迁移
|
||||
|
||||
### 7.1 前提
|
||||
|
||||
只有阶段 A 和阶段 B 都完成后,才进入这一阶段。
|
||||
|
||||
### 7.2 目标
|
||||
|
||||
开始把 `new_editor` 从“宿主 + XCEditor 库 + 少量产品面板”推进到“正式的新编辑器产品层”。
|
||||
|
||||
### 7.3 迁移顺序
|
||||
|
||||
产品层迁移不从“继续多堆几个面板”开始,而是从全局 owner 开始:
|
||||
|
||||
1. `State / Context / Selection / Commands / Actions / Managers`
|
||||
2. `Scene / Game / Viewport` 产品工作流 owner
|
||||
3. `Hierarchy / Inspector / Project / Console` 等业务面板继续正式化
|
||||
4. `ComponentEditors` 与旧 editor 业务能力迁入
|
||||
|
||||
### 7.4 原则
|
||||
|
||||
- 参考旧 `editor` 的成熟实现与行为
|
||||
- 但不原样照搬 ImGui 壳
|
||||
- 旧 editor 里正确的 owner、工作流和数据流要迁过来
|
||||
- 不合理的旧结构允许在迁移时顺手正规化
|
||||
|
||||
### 7.5 完成标准
|
||||
|
||||
进入这一阶段后,`new_editor` 的主线定义就正式从“基础设施收口”切换为“新编辑器产品重建”。
|
||||
|
||||
## 8. 当前明确不做的事
|
||||
|
||||
在这份计划生效期间,以下工作不作为主线优先项:
|
||||
|
||||
- 不继续把精力放在零散小 UI 效果修补上
|
||||
- 不继续围绕旧阶段性 `NewEditor_*` 子计划扩写
|
||||
- 不把 `Editor UI` 再拉回资源样式体系
|
||||
- 不为未收口的架构继续追加临时功能
|
||||
|
||||
## 9. 可并行切分方式
|
||||
|
||||
### 9.1 可以并行的部分
|
||||
|
||||
在阶段 A 内部,可并行切分为:
|
||||
|
||||
- `Bootstrap / Application` 收口
|
||||
- `Platform/Win32` 宿主收口
|
||||
- `Rendering/D3D12 + Native + Viewport` 收口
|
||||
|
||||
在阶段 B 内部,可并行切分为:
|
||||
|
||||
- `Workspace`
|
||||
- `Docking`
|
||||
- `PropertyGrid`
|
||||
|
||||
### 9.2 必须串行的部分
|
||||
|
||||
以下顺序不能乱:
|
||||
|
||||
1. 先完成阶段 A
|
||||
2. 再完成阶段 B
|
||||
3. 再进入阶段 C
|
||||
|
||||
原因很简单:产品层迁移不能建立在尚未稳定的宿主层和库层上。
|
||||
|
||||
## 10. 收口判断
|
||||
|
||||
当满足以下条件时,说明当前这轮结构收口真正完成:
|
||||
|
||||
1. `new_editor/app` 迁移闭环完成
|
||||
2. `XCEditor` 三大热点收薄完成
|
||||
3. `new_editor` 可以在稳定宿主和稳定库层之上,开始正式承接旧 editor 的产品工作流迁移
|
||||
|
||||
在这之前,所有主线工作都应服务于“收结构债”,而不是继续发散。
|
||||
@@ -1,310 +0,0 @@
|
||||
# Renderer C++层第一阶段收口计划
|
||||
|
||||
日期: `2026-04-13`
|
||||
|
||||
## 1. 文档定位
|
||||
|
||||
这份文档是 `Render Graph` 之前的最后一轮 `native render kernel v1` 收口计划。
|
||||
|
||||
目标不是继续往当前 `Rendering` 层里塞新功能,而是先把下面几件事彻底做清楚:
|
||||
|
||||
- `request -> frame plan -> execution` 三层语义分开。
|
||||
- `RenderSceneExtractor -> CullingResults -> RendererList -> DrawSettings` 这条数据组织链正式化。
|
||||
- `BuiltinForwardPipeline` 从“大杂烩渲染器”收成“协调器 + 子能力”。
|
||||
- `Editor` 注入点、阴影、主场景、后处理之间的边界说清楚。
|
||||
- 给下一步 `C++ Render Graph` 留出稳定输入,而不是把当前混乱直接 graph 化。
|
||||
|
||||
结论先写在前面:
|
||||
|
||||
- `Render Graph` 应该做在 `C++ native` 层。
|
||||
- 现在还不应该直接开做 `Render Graph` 或 `Deferred Renderer`。
|
||||
- 当前更优先的是把现有渲染层整理干净,再往 SRP/URP 方向演进。
|
||||
|
||||
## 2. 当前阶段已经完成的收口
|
||||
|
||||
截至 `2026-04-13` 晚间,已经落地的内容:
|
||||
|
||||
- `CameraRenderRequest -> CameraFramePlan` 已经分层,`CameraRenderer` 开始正式消费 plan。
|
||||
- `CullingResults / RendererList` contract 已经进入 `RenderSceneData`。
|
||||
- `Forward / Depth / ObjectId` 已经优先走 `RendererList`,旧 `visibleItems` 只保留过渡 fallback。
|
||||
- `RendererListUtils` 已经把可见项遍历规则收口成公共工具。
|
||||
- `Gaussian / Volumetric` 已经从 `BuiltinForwardPipeline` 中抽成统一 `SceneRenderFeaturePass`。
|
||||
- `FrameExecutionContext / ScenePhase / DrawSettings` 已经引入。
|
||||
- `RenderPipeline` 已经支持新的 `FrameExecutionContext` 入口,旧三参数入口保留为兼容适配层。
|
||||
- `BuiltinForwardPipeline` 已经开始按 scene phase 组织主场景执行。
|
||||
- `CameraRenderer` 主场景阶段已经走新的 execution context,而不是继续只传三参数。
|
||||
|
||||
本轮验证结果:
|
||||
|
||||
- `XCEditor` 已重新编译通过。
|
||||
- `rendering_unit_tests` 已重新编译通过。
|
||||
- `editor_tests` 已重新编译通过。
|
||||
- `editor_tests --gtest_filter=*ViewportRenderFlow*:*SceneViewportRenderPassBundle* --gtest_brief=1` 通过 `14/14`。
|
||||
- `rendering_unit_tests --gtest_filter=*BuiltinForwardPipeline*:*RenderPass*:*CameraSceneRenderer*:*Shadow*:*ObjectId* --gtest_brief=1` 通过 `67/68`。
|
||||
- 唯一失败仍然是既有老问题:
|
||||
`BuiltinForwardPipeline_Test.OpenGLRuntimeTranspilesForwardShadowVariantToLegacyClipConventions`
|
||||
|
||||
## 3. 为什么现在还不能直接上 Render Graph
|
||||
|
||||
现在直接上 `Render Graph`,本质上是在 graph 里继续承接当前的隐式耦合,问题只会换个位置存在。
|
||||
|
||||
当前还没完全收口的核心问题不是“没有 graph”,而是下面这些边界还不够正式:
|
||||
|
||||
- `CameraRenderer` 和各类 scene pass 之间,谁负责组织阶段,谁负责执行,还没有完全模块化。
|
||||
- `Shadow` 相关逻辑仍然分散在 planner、camera execution、pipeline、surface cache 几处。
|
||||
- `BuiltinForwardPipeline` 虽然已经开始瘦身,但还没有彻底收成一个明确的 coordinator。
|
||||
- `Editor` 的扩展点虽然已可用,但 contract 还偏“约定式”,还不够像以后给 `C# SRP` 暴露的正式接口。
|
||||
- 目录结构仍然在暴露旧历史:一些“子系统”目前还是文件堆,不是真正的模块。
|
||||
|
||||
如果这些问题不先解决,`Render Graph` 只会变成一个新的承压层,后面再拆更贵。
|
||||
|
||||
## 4. Render Graph 和未来 SRP/URP 的边界
|
||||
|
||||
未来的推荐结构仍然是这条线:
|
||||
|
||||
`RHI -> Native Render Kernel -> Render Graph -> SRP-like Contract -> Universal Renderer -> C# Custom Pipeline`
|
||||
|
||||
其中边界应当明确成这样:
|
||||
|
||||
- `C++ native` 保留:
|
||||
- `Render Graph`
|
||||
- `CullingResults / RendererList`
|
||||
- draw / dispatch context
|
||||
- GPU resource cache
|
||||
- shadow map / atlas 执行能力
|
||||
- Gaussian 排序与 working set
|
||||
- Volume 资源上传与底层执行
|
||||
- `URP-like` 包层保留:
|
||||
- feature 编排
|
||||
- pass 注入顺序
|
||||
- renderer feature 配置
|
||||
- 用户级 pipeline 组合
|
||||
- 未来的 `C#` 自定义渲染管线 API
|
||||
|
||||
这意味着:
|
||||
|
||||
- 阴影、Gaussian、Volumetric 不是整块搬去包层。
|
||||
- 包层更像 Unity 的 `URP renderer` 和 `renderer feature`。
|
||||
- native 层更像 Unity 没公开给用户、但真正负责执行和图资源生命周期的内核。
|
||||
|
||||
## 5. 第一阶段还差哪些工作才能收口
|
||||
|
||||
### 5.1 Shadow 子系统正式化
|
||||
|
||||
这是当前最值得先做的一块。
|
||||
|
||||
现状问题:
|
||||
|
||||
- 阴影规划在 `Planning`。
|
||||
- 阴影 surface/cache 在 `Execution/Caches`。
|
||||
- 阴影执行又是 standalone pass。
|
||||
- 主场景采样阴影的状态切换仍在 `BuiltinForwardPipeline`。
|
||||
|
||||
这说明阴影现在“能跑”,但还不是一个正式子系统。
|
||||
|
||||
收口目标:
|
||||
|
||||
- 明确 `shadow planning / shadow resources / shadow execution / shadow sampling contract` 四层边界。
|
||||
- 把方向光阴影相关共享数据收成一组正式类型,而不是散落在多个调用点上。
|
||||
- 为以后扩展 `cascades / shadow atlas / additional light shadows / baked shadowmask` 留出位置。
|
||||
|
||||
### 5.2 Editor 注入点正式化
|
||||
|
||||
现状问题:
|
||||
|
||||
- 当前有 `pre scene / post scene / overlay / object id / outline / grid` 多种 editor 路径。
|
||||
- 这些能力已经能工作,但还没有统一成“正式 stage 注入 contract”。
|
||||
|
||||
收口目标:
|
||||
|
||||
- 明确哪些注入点属于 runtime 正式阶段,哪些属于 editor-only extension。
|
||||
- 让 `CameraFramePlan` 对这些阶段的描述更加稳定。
|
||||
- 给以后 `C# renderer feature` 的注入点设计提供 native 对照物。
|
||||
|
||||
### 5.3 BuiltinForwardPipeline 继续瘦身
|
||||
|
||||
本轮已经完成第一刀,但还没收完。
|
||||
|
||||
还需要继续做的事情:
|
||||
|
||||
- 把 forward scene phase 执行和底层 draw/resource 逻辑彻底分开。
|
||||
- 把 forward renderer 自己的内部资源、skybox、feature 协调代码进一步收拢。
|
||||
- 保证 `BuiltinForwardPipeline` 自己只表达“阶段顺序和协调”,不再继续膨胀。
|
||||
|
||||
### 5.4 旧 fallback 的裁边
|
||||
|
||||
当前有一些过渡兼容层是故意保留的:
|
||||
|
||||
- `RenderPipeline::Render(context, surface, sceneData)` 旧入口
|
||||
- `visibleItems` fallback
|
||||
- `BuildRenderRequests` 旧习惯入口
|
||||
|
||||
这些现在不该硬删,因为会影响现有 tests 和 editor 链路。
|
||||
|
||||
但第一阶段收口前,至少要做到:
|
||||
|
||||
- 新主链默认只走正式 contract。
|
||||
- 旧入口只作为 adapter,不再新增依赖。
|
||||
- 每个 fallback 都有明确退出条件。
|
||||
|
||||
### 5.5 测试和文档补齐
|
||||
|
||||
当前已有回归还不够系统。
|
||||
|
||||
还需要补的重点测试:
|
||||
|
||||
- `FrameExecutionContext` 是否完整透传 source surface / source color view / state。
|
||||
- `BuiltinForwardPipeline` scene phase 顺序是否稳定。
|
||||
- feature pass 的 `Prepare -> Execute` 顺序是否稳定。
|
||||
- editor 注入点在有后处理和无后处理两种情况下是否仍能保持正确 source/destination surface。
|
||||
- shadow planning 和 main scene shadow sampling 之间的契约测试。
|
||||
|
||||
## 6. 下一步最优先该做什么
|
||||
|
||||
下一步最优先建议做:
|
||||
|
||||
`Shadow 子系统收口`
|
||||
|
||||
原因很直接:
|
||||
|
||||
- 它横跨 `Planning / Execution / Pipeline / Resources / Sampling`。
|
||||
- 它是以后 `Deferred / Light Baking / ShadowMask / Additional Light Shadows` 的共同基础。
|
||||
- 它也是未来 `Render Graph` 最敏感的一类资源依赖链。
|
||||
- 如果阴影先不收,后面 graph 化时 barrier、resource lifetime、pass dependency 都会更乱。
|
||||
|
||||
建议顺序:
|
||||
|
||||
1. 先把方向光阴影的 plan/data/resource/execute contract 固化。
|
||||
2. 再把 editor 注入 contract 固化。
|
||||
3. 然后做第一轮目录收拢。
|
||||
4. 最后判断这一阶段是否可以正式收口,进入 `Render Graph` 设计。
|
||||
|
||||
## 7. 当前 Rendering 目录结构存在的问题
|
||||
|
||||
### 7.1 `FrameData` 目录太杂
|
||||
|
||||
现在 `FrameData` 里同时混着:
|
||||
|
||||
- camera/environment 数据
|
||||
- scene snapshot
|
||||
- visible item
|
||||
- culling results
|
||||
- renderer list utils
|
||||
|
||||
这说明它不是一个明确模块,而是“跟帧有关的先放这”。
|
||||
|
||||
建议方向:
|
||||
|
||||
- `FrameData` 保留纯只读帧快照类型。
|
||||
- 把 `CullingResults / RendererList / Filtering / Sorting / DrawSettings` 逐步收进更明确的 `Execution` 或 `Culling` 子域。
|
||||
- `RendererListUtils` 这种执行辅助逻辑,不适合长期留在 `FrameData`。
|
||||
|
||||
### 7.2 `Passes` 目录混合了三类东西
|
||||
|
||||
现在 `Passes` 里同时有:
|
||||
|
||||
- 主场景 pass
|
||||
- fullscreen/post-process pass
|
||||
- editor pass
|
||||
|
||||
这会让“runtime 正式渲染能力”和“editor 辅助渲染能力”继续混在一起。
|
||||
|
||||
建议方向:
|
||||
|
||||
- `Passes/Scene`
|
||||
- `Passes/Fullscreen`
|
||||
- `Passes/Editor`
|
||||
- `Passes/Shadow`
|
||||
|
||||
不一定要一次性全搬,但后面新增文件不应继续平铺。
|
||||
|
||||
### 7.3 `BuiltinForwardPipeline` 还没形成真正子模块
|
||||
|
||||
当前 forward 相关代码已经分散在:
|
||||
|
||||
- `BuiltinForwardPipeline.h/.cpp`
|
||||
- `BuiltinForwardPipelineSkybox.cpp`
|
||||
- `Internal/BuiltinForwardPipelineResources.cpp`
|
||||
|
||||
这已经具备“应该单独成目录”的条件。
|
||||
|
||||
建议方向:
|
||||
|
||||
- `Rendering/Pipelines/BuiltinForward/`
|
||||
- `BuiltinForwardPipeline.h`
|
||||
- `BuiltinForwardPipeline.cpp`
|
||||
- `BuiltinForwardPipelineScene.cpp`
|
||||
- `BuiltinForwardPipelineResources.cpp`
|
||||
- `BuiltinForwardPipelineSkybox.cpp`
|
||||
|
||||
这样后面 forward / deferred / universal renderer 才能并列演进。
|
||||
|
||||
### 7.4 `Shadow` 目录还不算真正的 shadow 子系统
|
||||
|
||||
目前虽然已经有 `Rendering/Shadow`,但从全链路看,阴影的责任仍然散在其他目录。
|
||||
|
||||
建议方向:
|
||||
|
||||
- `Shadow` 目录最终至少容纳:
|
||||
- planning types
|
||||
- shared frame data
|
||||
- runtime resources / caches
|
||||
- shadow executor or shadow renderer
|
||||
|
||||
### 7.5 `Internal` 边界不稳定
|
||||
|
||||
现在 `src/Rendering/Internal` 更像历史遗留缓冲区。
|
||||
|
||||
长期风险:
|
||||
|
||||
- 真正属于 forward 的内部实现放在全局 `Internal`
|
||||
- 真正属于 volume / splat / shadow 的内部实现也可能继续堆进去
|
||||
|
||||
建议方向:
|
||||
|
||||
- 全局 `Internal` 只保留跨模块公共 helper。
|
||||
- 各子系统自己的内部文件放回各自目录。
|
||||
|
||||
## 8. 建议的第一轮目录收拢动作
|
||||
|
||||
这一轮只做低风险收拢,不做大搬家。
|
||||
|
||||
建议动作:
|
||||
|
||||
- 把 `BuiltinForwardPipeline*` 相关实现收成 `Pipelines/BuiltinForward/` 子目录。
|
||||
- 给 `Passes` 至少先分出 `Editor` 和 `Fullscreen` 两个子目录。
|
||||
- 给 `Shadow` 补一组正式 shared types,再决定是否移动更多实现文件。
|
||||
- 暂时不大动 `include` 层 public 路径,先保证编译和引用稳定。
|
||||
|
||||
原则:
|
||||
|
||||
- 先按职责拆,再按目录搬。
|
||||
- 不为了“好看”做纯目录手术。
|
||||
- 每次收拢都必须带编译和回归。
|
||||
|
||||
## 9. 第一阶段收口完成的判定标准
|
||||
|
||||
满足下面这些条件,就可以认为 `Render Graph` 之前这一阶段基本收口:
|
||||
|
||||
- `CameraFramePlan` 成为主执行入口,旧 request 入口只保留兼容壳。
|
||||
- `FrameExecutionContext / ScenePhase / DrawSettings` 成为主场景执行正式 contract。
|
||||
- `CullingResults / RendererList` 成为主要 draw organization contract。
|
||||
- `BuiltinForwardPipeline` 被收成 coordinator,而不是继续长成总垃圾堆。
|
||||
- `Shadow` 成为清晰子系统,而不是散点逻辑。
|
||||
- `Editor` 注入点形成稳定 contract。
|
||||
- 目录结构不再继续鼓励“新逻辑直接往老文件里塞”。
|
||||
- 相关 tests 和编译链稳定。
|
||||
|
||||
到这一步,再开始 `C++ Render Graph`,代价才是可控的。
|
||||
|
||||
## 10. 当前建议
|
||||
|
||||
当前最佳路线不变:
|
||||
|
||||
- 短期:继续按 Unity 的 `SRP + URP` 方向做 native 基座。
|
||||
- 中期:先在 `C++` 做出稳定的 `Render Graph + RendererList + Feature Injection` 内核。
|
||||
- 中长期:再暴露 `C#` 自定义渲染管线接口,做你自己的 `URP-like` 包层。
|
||||
|
||||
眼下最正确的动作不是“赶紧补 deferred”,也不是“先把所有特效搬去包层”,而是:
|
||||
|
||||
`先把当前 native rendering layer 整理成一个真正可扩展的内核。`
|
||||
@@ -1,462 +0,0 @@
|
||||
# Renderer C++层第一阶段重构计划(Render Graph 前)
|
||||
|
||||
日期:`2026-04-13`
|
||||
|
||||
## 1. 文档定位
|
||||
|
||||
这份计划只处理 `Render Graph` 之前的那一步,也就是把当前 `Rendering` 原生主链先整理成一个可长期演进的正式架构。
|
||||
|
||||
这一步的目标不是新增大功能,而是先把下面这些边界收口:
|
||||
|
||||
1. `SceneRenderer / CameraRenderer / SceneRenderRequestPlanner` 的职责边界
|
||||
2. `RenderSceneExtractor / RenderSceneData / VisibleRenderItem` 的数据边界
|
||||
3. `RenderPipeline / RenderPass / BuiltinForwardPipeline` 的执行边界
|
||||
4. Runtime 主链与 Editor 注入点的边界
|
||||
|
||||
这一步做完之后,下一阶段才适合引入真正的 `Render Graph`。
|
||||
|
||||
---
|
||||
|
||||
## 2. 关于 Render Graph 的结论
|
||||
|
||||
结论很明确:
|
||||
|
||||
1. `Render Graph` 应该先做在 `C++ native` 层
|
||||
2. 它不应该直接作为第一阶段的一部分
|
||||
3. 第一阶段的任务,是先把当前 native renderer 收口到足够清晰,避免后面只是把现有混乱机械搬进 graph
|
||||
|
||||
后面的目标结构应该是:
|
||||
|
||||
`RHI -> Native Render Kernel -> Render Graph -> SRP-like Contract -> Universal Renderer -> C# Custom Pipeline`
|
||||
|
||||
其中:
|
||||
|
||||
1. `Render Graph` 属于 `Native Render Kernel`
|
||||
2. `C#` 层以后可以编排 pass,但图资源生命周期、资源状态、barrier、跨 pass 读写依赖仍应先由 native graph 掌控
|
||||
|
||||
---
|
||||
|
||||
## 3. 当前代码里的真实主链
|
||||
|
||||
当前项目并不是没有架构,而是已经形成了一条手工编排的 mini-SRP 主链:
|
||||
|
||||
1. `SceneRenderRequestPlanner`
|
||||
- 收集 camera
|
||||
- 生成 `CameraRenderRequest`
|
||||
- 负责方向光阴影规划参数
|
||||
2. `SceneRenderer`
|
||||
- 调 planner
|
||||
- 解析 final color policy
|
||||
- 为 post-process / final-output 附加 fullscreen stage request
|
||||
3. `CameraRenderer`
|
||||
- 做 shadow request resolve
|
||||
- 提取 `RenderSceneData`
|
||||
- 按固定 stage 顺序执行
|
||||
4. `BuiltinForwardPipeline`
|
||||
- 负责主场景绘制
|
||||
- 同时背着 shader 绑定、PSO 缓存、材质资源解析、skybox、splat、volumetric 等大量职责
|
||||
|
||||
对应的当前入口主要是:
|
||||
|
||||
1. `engine/include/XCEngine/Rendering/Execution/SceneRenderer.h`
|
||||
2. `engine/include/XCEngine/Rendering/Execution/CameraRenderer.h`
|
||||
3. `engine/include/XCEngine/Rendering/Planning/SceneRenderRequestPlanner.h`
|
||||
4. `engine/include/XCEngine/Rendering/Planning/CameraRenderRequest.h`
|
||||
5. `engine/include/XCEngine/Rendering/FrameData/RenderSceneData.h`
|
||||
6. `engine/include/XCEngine/Rendering/FrameData/VisibleRenderItem.h`
|
||||
7. `engine/include/XCEngine/Rendering/RenderPipeline.h`
|
||||
8. `engine/include/XCEngine/Rendering/RenderPipelineAsset.h`
|
||||
9. `engine/include/XCEngine/Rendering/Pipelines/BuiltinForwardPipeline.h`
|
||||
10. `engine/src/Rendering/Execution/SceneRenderer.cpp`
|
||||
11. `engine/src/Rendering/Execution/CameraRenderer.cpp`
|
||||
12. `engine/src/Rendering/Extraction/RenderSceneExtractor.cpp`
|
||||
13. `engine/src/Rendering/Pipelines/BuiltinForwardPipeline.cpp`
|
||||
14. `engine/src/Rendering/Pipelines/Internal/BuiltinForwardPipelineResources.cpp`
|
||||
|
||||
---
|
||||
|
||||
## 4. 当前真正的问题
|
||||
|
||||
当前主要不是“功能太少”,而是“职责层次还不够正式”。
|
||||
|
||||
### 4.1 request、plan、execution 混在一起
|
||||
|
||||
`CameraRenderRequest` 现在既像外部请求,又像内部执行计划,还夹带了一部分 runtime surface / fullscreen chain 组织信息。
|
||||
`SceneRenderer` 也同时承担了 request build、final color resolve、fullscreen intermediate surface ownership 这几类事情。
|
||||
|
||||
这样的问题是:
|
||||
|
||||
1. 后面很难区分“用户想渲染什么”和“引擎决定怎么执行”
|
||||
2. Editor 也会继续直接依赖底层 stage 细节
|
||||
3. Render Graph 以后很难接到一个稳定的 frame plan 输入
|
||||
|
||||
### 4.2 extraction 数据还偏早期
|
||||
|
||||
`RenderSceneExtractor` 现在能工作,但产物仍然偏“把可见对象收集成数组”。
|
||||
它还没有正式长成后续 SRP / Render Graph 真正需要的那种中间层:
|
||||
|
||||
1. `CullingResults`
|
||||
2. `RendererList`
|
||||
3. `FilteringSettings`
|
||||
4. `SortingSettings`
|
||||
5. `DrawSettings`
|
||||
|
||||
如果这层不先正式化,后面 forward、deferred、shadow、object-id、editor overlay 都会继续各自拿 `visibleItems` 做自己的隐式解释。
|
||||
|
||||
### 4.3 BuiltinForwardPipeline 过重
|
||||
|
||||
当前 `BuiltinForwardPipeline` 不只是一个 renderer,它已经同时包含:
|
||||
|
||||
1. 主场景 pass 编排
|
||||
2. 材质资源布局解析
|
||||
3. descriptor set 组织
|
||||
4. pipeline state cache
|
||||
5. lighting / shadow 绑定
|
||||
6. skybox 逻辑
|
||||
7. gaussian splat 特殊路径
|
||||
8. volumetric 特殊路径
|
||||
|
||||
这会带来两个后果:
|
||||
|
||||
1. 后面任何主场景新能力都会继续往这个类里堆
|
||||
2. 未来要抽 `Universal Renderer` 或切出 `Deferred` 时,拆分成本会很高
|
||||
|
||||
### 4.4 runtime 主线和 editor 扩展点还没正式隔离
|
||||
|
||||
现在 Editor 已经深度依赖 request stage 注入点,这个方向本身没错,但 contract 还不够正式。
|
||||
如果不先收口,后面 graph 化时 editor 特殊路径会变成额外复杂度来源。
|
||||
|
||||
### 4.5 pipeline contract 还不够像未来的 SRP 底座
|
||||
|
||||
当前 `RenderPipeline` 还是:
|
||||
|
||||
`Render(context, surface, sceneData)`
|
||||
|
||||
这个接口对当前 builtin forward 足够,但对未来这些东西不够:
|
||||
|
||||
1. renderer list
|
||||
2. graph resource declaration
|
||||
3. per-frame context
|
||||
4. pass feature 注入
|
||||
5. 多渲染路径共存
|
||||
|
||||
第一阶段不要求一步到位,但至少要把它朝这个方向整理。
|
||||
|
||||
---
|
||||
|
||||
## 5. 本阶段明确不做的事
|
||||
|
||||
为了保证收口不失控,这一阶段明确不做下面这些:
|
||||
|
||||
1. 不引入真正运行时 `Render Graph`
|
||||
2. 不做完整 `Deferred Renderer`
|
||||
3. 不做 `C# SRP` 暴露
|
||||
4. 不重写 RHI
|
||||
5. 不新增大型渲染特性来打断架构收口
|
||||
|
||||
本阶段只做一件事:
|
||||
|
||||
`把当前 native rendering layer 整理成 Render Graph 之前的正式形态`
|
||||
|
||||
---
|
||||
|
||||
## 6. 第一阶段完成后应该达到什么状态
|
||||
|
||||
本阶段完成后,native renderer 至少应满足下面这些条件:
|
||||
|
||||
1. 外部 request、内部 frame plan、实际 execution 三层语义分开
|
||||
2. extraction / culling / draw organization 有正式中间层,不再只靠裸 `visibleItems`
|
||||
3. `BuiltinForwardPipeline` 明显瘦身,不再继续当总垃圾桶
|
||||
4. runtime pass 与 editor pass 有明确注入 contract
|
||||
5. 后续 `Render Graph` 能接一个稳定的 `Frame Plan + Renderer Lists + Resource Needs` 输入
|
||||
|
||||
---
|
||||
|
||||
## 7. 第一阶段的重构原则
|
||||
|
||||
### 7.1 先 formalize,再 graphize
|
||||
|
||||
先把 contract 和边界做清楚,再做 graph。
|
||||
不要反过来。
|
||||
|
||||
### 7.2 不破坏现有主链闭环
|
||||
|
||||
当前 `Scene / Game / Editor Viewport` 已经能跑通,第一阶段不能为了“好看”把现有可运行链条打散。
|
||||
|
||||
### 7.3 新中间层优先 native internal
|
||||
|
||||
这一阶段新补的 `Frame Plan`、`CullingResults`、`RendererList`、`DrawSettings` 都先是 C++ 内部契约,不急着暴露给 C#。
|
||||
|
||||
### 7.4 先解耦职责,再决定目录长相
|
||||
|
||||
不要先做大范围目录搬家。
|
||||
先把职责拆开,目录只是最后的外显结果。
|
||||
|
||||
### 7.5 editor contract 正式化,但不去特殊化主链
|
||||
|
||||
Editor 的 object-id、outline、grid、overlay 依然要保留,但它们应该依附在正式 contract 上,而不是继续共享 runtime 的隐式细节。
|
||||
|
||||
---
|
||||
|
||||
## 8. 工作包拆分
|
||||
|
||||
## 工作包 A:request / frame plan 分层
|
||||
|
||||
目标:
|
||||
|
||||
把“用户想渲染什么”和“引擎这帧怎么执行”拆开。
|
||||
|
||||
建议结果:
|
||||
|
||||
1. 保留 `CameraRenderRequest` 作为外部请求描述
|
||||
2. 新增内部 `CameraFramePlan` 或等价类型,承载:
|
||||
- 实际启用的 stage
|
||||
- fullscreen chain
|
||||
- resolved target/surface
|
||||
- 阴影计划结果
|
||||
- editor 注入点
|
||||
3. `SceneRenderer` 只负责:
|
||||
- 请求收集
|
||||
- 请求排序
|
||||
- request -> frame plan 转换
|
||||
4. `CameraRenderer` 只负责:
|
||||
- frame plan 执行
|
||||
- 调 scene extraction
|
||||
- 调 pipeline / standalone pass
|
||||
|
||||
优先涉及文件:
|
||||
|
||||
1. `engine/include/XCEngine/Rendering/Planning/CameraRenderRequest.h`
|
||||
2. `engine/include/XCEngine/Rendering/Execution/SceneRenderer.h`
|
||||
3. `engine/src/Rendering/Execution/SceneRenderer.cpp`
|
||||
4. `engine/include/XCEngine/Rendering/Execution/CameraRenderer.h`
|
||||
5. `engine/src/Rendering/Execution/CameraRenderer.cpp`
|
||||
|
||||
完成标准:
|
||||
|
||||
1. request 不再混入过多 runtime-owned intermediate state
|
||||
2. frame plan 成为 camera 执行的正式输入
|
||||
3. SceneRenderer 和 CameraRenderer 的边界可以一句话说清
|
||||
|
||||
## 工作包 B:scene extraction -> culling results / renderer list
|
||||
|
||||
目标:
|
||||
|
||||
把当前 `RenderSceneExtractor` 的数组式输出,推进为后续 SRP/RenderGraph 可用的原生中间层。
|
||||
|
||||
建议结果:
|
||||
|
||||
1. 在 native 层引入等价于以下概念的类型:
|
||||
- `CullingResults`
|
||||
- `RendererListDesc`
|
||||
- `RendererList`
|
||||
- `FilteringSettings`
|
||||
- `SortingSettings`
|
||||
- `DrawSettings`
|
||||
2. `RenderSceneData` 不再承担过多“什么都往里塞”的职责
|
||||
3. `VisibleRenderItem` 继续保留为底层记录,但不再直接成为所有 pass 的唯一公共输入
|
||||
4. shadow、main scene、object-id 等路径逐步改为消费 `RendererList`
|
||||
|
||||
优先涉及文件:
|
||||
|
||||
1. `engine/include/XCEngine/Rendering/FrameData/RenderSceneData.h`
|
||||
2. `engine/include/XCEngine/Rendering/FrameData/VisibleRenderItem.h`
|
||||
3. `engine/src/Rendering/Extraction/RenderSceneExtractor.cpp`
|
||||
4. `engine/include/XCEngine/Rendering/Extraction/`
|
||||
5. `engine/include/XCEngine/Rendering/Builtin/`
|
||||
|
||||
完成标准:
|
||||
|
||||
1. opaque、transparent、shadow、object-id 至少能共用同一套 draw organization contract
|
||||
2. 后面新增 deferred 时,不需要再发明第二套“可见对象数组解释逻辑”
|
||||
|
||||
## 工作包 C:pipeline contract 收口
|
||||
|
||||
目标:
|
||||
|
||||
把当前 `RenderPipeline / RenderPass / RenderPipelineAsset` 收口到更像未来 SRP native kernel 的形态。
|
||||
|
||||
建议结果:
|
||||
|
||||
1. 继续保留 `RenderPipelineAsset -> RenderPipeline` 这条总方向
|
||||
2. 明确区分:
|
||||
- pipeline asset:配置与默认策略
|
||||
- pipeline runtime:本帧执行
|
||||
- standalone pass:独立功能 pass
|
||||
3. 给主场景 pipeline 引入更正式的执行输入,而不是继续只吃 `surface + sceneData`
|
||||
4. 为下一阶段 graph 化预留清晰输入面:
|
||||
- frame context
|
||||
- renderer lists
|
||||
- per-frame resources
|
||||
|
||||
优先涉及文件:
|
||||
|
||||
1. `engine/include/XCEngine/Rendering/RenderPipeline.h`
|
||||
2. `engine/include/XCEngine/Rendering/RenderPipelineAsset.h`
|
||||
3. `engine/include/XCEngine/Rendering/RenderPass.h`
|
||||
4. `engine/include/XCEngine/Rendering/Pipelines/BuiltinForwardPipeline.h`
|
||||
|
||||
完成标准:
|
||||
|
||||
1. 主 pipeline 输入面能明显映射到未来 `Universal Renderer`
|
||||
2. standalone pass 与 main scene pipeline 的边界清楚
|
||||
|
||||
## 工作包 D:BuiltinForwardPipeline 瘦身
|
||||
|
||||
目标:
|
||||
|
||||
把 `BuiltinForwardPipeline` 从“大一统实现类”拆成可长期维护的 renderer 内部模块。
|
||||
|
||||
建议结果:
|
||||
|
||||
1. 按职责切成内部模块或 helper:
|
||||
- main scene draw
|
||||
- skybox draw
|
||||
- lighting binding
|
||||
- shadow binding
|
||||
- material binding
|
||||
- pipeline state cache
|
||||
- per-frame resource cache
|
||||
2. `GaussianSplat` 和 `Volumetric` 继续保留,但从“主 pipeline 杂糅逻辑”变成清晰的 feature-style 子模块
|
||||
3. `BuiltinForwardPipelineResources.cpp` 里和运行时编排无关的资源/绑定组织进一步下沉
|
||||
|
||||
优先涉及文件:
|
||||
|
||||
1. `engine/include/XCEngine/Rendering/Pipelines/BuiltinForwardPipeline.h`
|
||||
2. `engine/src/Rendering/Pipelines/BuiltinForwardPipeline.cpp`
|
||||
3. `engine/src/Rendering/Pipelines/Internal/BuiltinForwardPipelineResources.cpp`
|
||||
4. `engine/include/XCEngine/Rendering/Materials/RenderMaterialResolve.h`
|
||||
|
||||
完成标准:
|
||||
|
||||
1. `BuiltinForwardPipeline` 主类显著变薄
|
||||
2. 新增一种主场景能力时,不需要继续把所有逻辑堆回同一个 cpp
|
||||
|
||||
## 工作包 E:editor 注入点正式化
|
||||
|
||||
目标:
|
||||
|
||||
保留当前 editor 渲染能力,但把它从“依赖阶段细节”变成“依赖正式 extension contract”。
|
||||
|
||||
建议结果:
|
||||
|
||||
1. 继续保留:
|
||||
- object-id
|
||||
- outline
|
||||
- grid
|
||||
- overlay
|
||||
2. 把这些能力明确分成:
|
||||
- runtime stage
|
||||
- editor-only extension stage
|
||||
3. 收口 `RenderPassSequence` 在 request 上的使用边界,避免后续 graph 化时出现“谁都能往 request 里塞东西”的状态
|
||||
|
||||
优先涉及文件:
|
||||
|
||||
1. `engine/include/XCEngine/Rendering/Planning/CameraRenderRequest.h`
|
||||
2. `editor/src/Viewport/SceneViewportRenderPlan.h`
|
||||
3. `editor/src/Viewport/`
|
||||
4. `engine/src/Rendering/Execution/CameraRenderer.cpp`
|
||||
|
||||
完成标准:
|
||||
|
||||
1. Editor 仍能完整接入当前主链
|
||||
2. 但 editor 不再直接绑死 runtime 内部实现细节
|
||||
|
||||
## 工作包 F:测试与文档同步
|
||||
|
||||
目标:
|
||||
|
||||
把第一阶段重构做成可回归、可交接的正式收口,而不是一次只靠手工验证的大重排。
|
||||
|
||||
建议结果:
|
||||
|
||||
1. 补 `tests/Rendering/unit`
|
||||
2. 保底回归现有 `tests/Rendering/integration`
|
||||
3. 必要时补 editor viewport 级验证
|
||||
4. 更新 API 文档与后续计划入口
|
||||
|
||||
完成标准:
|
||||
|
||||
1. request / extractor / pipeline 边界都有对应测试覆盖
|
||||
2. 当前 forward、shadow、object-id、editor scene view 不回退
|
||||
|
||||
---
|
||||
|
||||
## 9. 执行顺序
|
||||
|
||||
必须按下面的顺序推进:
|
||||
|
||||
1. 先做工作包 A
|
||||
2. 再做工作包 B
|
||||
3. 再做工作包 C
|
||||
4. 然后做工作包 D
|
||||
5. 接着做工作包 E
|
||||
6. 最后统一做工作包 F
|
||||
|
||||
原因:
|
||||
|
||||
1. 不先分清 request 和 frame plan,后面所有 contract 都会悬空
|
||||
2. 不先把 extraction 推进到 `renderer list` 层,pipeline 收口只是表面整理
|
||||
3. 不先把 pipeline contract 稳住,`BuiltinForwardPipeline` 的瘦身会缺少稳定目标
|
||||
4. 不先把 native 主线收紧,editor contract 很容易继续沿着旧细节扩张
|
||||
|
||||
---
|
||||
|
||||
## 10. 建议新增或调整的 native 类型
|
||||
|
||||
第一阶段不要求名字完全按这个来,但建议至少出现这些等价层:
|
||||
|
||||
1. `CameraFramePlan`
|
||||
2. `FrameExecutionContext`
|
||||
3. `CullingResults`
|
||||
4. `RendererListDesc`
|
||||
5. `RendererList`
|
||||
6. `DrawSettings`
|
||||
7. `FilteringSettings`
|
||||
8. `SortingSettings`
|
||||
9. `EditorRenderExtensions` 或等价 editor 注入描述
|
||||
|
||||
注意:
|
||||
|
||||
1. 这些类型先是 `C++ internal contract`
|
||||
2. 这一阶段不急着桥接到 `managed`
|
||||
3. 下一阶段 `Render Graph` 会直接消费其中一部分
|
||||
|
||||
---
|
||||
|
||||
## 11. 这一阶段完成的验收标准
|
||||
|
||||
当以下条件同时成立时,这一阶段才算完成:
|
||||
|
||||
1. `SceneRenderer / CameraRenderer / Planner` 三者职责边界稳定
|
||||
2. native 渲染主链内部已经形成 request、frame plan、execution 三层
|
||||
3. `RenderSceneExtractor` 不再只是输出裸数组,而是能支持正式的 draw organization
|
||||
4. `BuiltinForwardPipeline` 不再承担明显超载职责
|
||||
5. editor 的注入点已经正规化,且没有破坏当前 Scene View / Game View 能力
|
||||
6. 现有 forward、shadow、post-process、final-output、object-id、overlay 主路径回归通过
|
||||
|
||||
---
|
||||
|
||||
## 12. 下一阶段如何接 Render Graph
|
||||
|
||||
等本阶段完成后,下一阶段才进入真正的 `Render Graph`。
|
||||
|
||||
那时的接法应该是:
|
||||
|
||||
1. `CameraFramePlan` 提供本帧逻辑阶段与 feature 需求
|
||||
2. `CullingResults / RendererList` 提供 draw 输入
|
||||
3. `FrameExecutionContext` 提供本帧统一资源上下文
|
||||
4. `Render Graph` 负责:
|
||||
- pass declaration
|
||||
- resource creation/import
|
||||
- read/write dependency
|
||||
- barrier / lifetime
|
||||
- transient resource reuse
|
||||
|
||||
也就是说,`Render Graph` 不是来替代第一阶段,而是建立在第一阶段之上。
|
||||
|
||||
---
|
||||
|
||||
## 13. 一句话结论
|
||||
|
||||
当前最佳路线不是立刻补 `Deferred`,也不是立刻补 `Render Graph`,而是先把你现有这条 native rendering 主链整理成真正的 `Render Kernel v1`;这一步做实了,后面的 `Render Graph`、`Universal Renderer`、`C# SRP` 才会接得稳。
|
||||
@@ -1,71 +0,0 @@
|
||||
# Renderer C++层第七阶段计划:渲染模块收口与 SRP 宿主去临时化
|
||||
|
||||
## 阶段目标
|
||||
|
||||
本阶段不继续扩展新渲染特性,重点处理当前 Rendering 模块里仍然存在的临时组织、隐式依赖和未收口边界,为后续正式构建 SRP/URP 风格宿主层做准备。
|
||||
|
||||
收口标准:
|
||||
|
||||
1. `CameraFramePlan` 成为真正可安全返回、复制、缓存的值对象,不再依赖 builder 内部临时托管资源的生命周期。
|
||||
2. `RenderPipeline` / `RenderPipelineStageRecorder` 生命周期进入统一主链,不再依赖 builtin 分支各自兜底初始化。
|
||||
3. builtin 渲染 policy 从 `CameraRenderer` / planner / host 中外提到 renderer asset / renderer 实现层,不再由 engine core 直接决定。
|
||||
4. RenderGraph fallback 仅保留必要兼容点,去掉重复桥接和职责重叠实现。
|
||||
5. editor 专用 overlay / picking / viewport pass 与 runtime builtin 渲染边界更清晰。
|
||||
|
||||
## 当前确认的问题
|
||||
|
||||
### P0
|
||||
|
||||
1. `CameraFramePlan` 内部保存的 fullscreen `RenderPassSequence*` 由 `CameraFramePlanBuilder` 内部成员托管,plan 对外按值返回时存在悬空生命周期风险。
|
||||
2. `ScriptableRenderPipelineHost` 已有生命周期接口,但运行主链没有真正统一调用,managed recorder 未来会直接踩到这个缺口。
|
||||
3. 阴影、天空盒、final color、post-process、默认 standalone stage pass 等 policy 仍散落在 engine core,而不是 renderer asset / renderer 自身闭合。
|
||||
|
||||
### P1
|
||||
|
||||
1. native RenderGraph 仍保留多处 fallback 录制与重复 surface helper,说明兼容层还未完全收口。
|
||||
2. builtin forward 与 graph builder 之间仍存在 `friend` 级耦合,部分逻辑仍是“双轨并存”。
|
||||
3. editor 专用 pass 还在 runtime rendering core 中,占用 runtime builtin 命名空间。
|
||||
|
||||
## 执行顺序
|
||||
|
||||
### Step 1:修复 CameraFramePlan 所有权
|
||||
|
||||
目标:
|
||||
|
||||
1. generated fullscreen sequence 由 `CameraFramePlan` 自持有。
|
||||
2. `CameraFramePlanBuilder` 不再保管 `postProcess/finalOutput` sequence。
|
||||
3. 补测试覆盖“plan 返回后 / 复制后 / 再次 build 后”sequence 仍有效。
|
||||
|
||||
### Step 2:统一 pipeline 生命周期
|
||||
|
||||
目标:
|
||||
|
||||
1. 明确 `RenderPipeline`、`RenderPipelineRenderer`、`RenderPipelineStageRecorder` 的初始化时机。
|
||||
2. 让 graph 录制与执行链共享同一套 lifecycle 入口。
|
||||
3. 去掉 builtin forward 在 graph execute callback 里的额外初始化兜底。
|
||||
|
||||
### Step 3:回收 builtin policy
|
||||
|
||||
目标:
|
||||
|
||||
1. 方向光阴影启用策略、环境数据、final color 默认策略、fullscreen stage 生成策略逐步下沉到 builtin renderer asset / renderer。
|
||||
2. `CameraRenderer` 退化为 scene extract + render plan execute 的薄协调层。
|
||||
|
||||
### Step 4:压缩 RenderGraph 兼容层
|
||||
|
||||
目标:
|
||||
|
||||
1. 清理重复的 graph-managed surface helper。
|
||||
2. 收敛 fallback raster pass 触发条件。
|
||||
3. 继续削减 `RecordCompatible*` 路径在核心主线中的存在感。
|
||||
|
||||
### Step 5:整理 editor/runtime 渲染边界
|
||||
|
||||
目标:
|
||||
|
||||
1. editor viewport grid / outline / selection mask 等 pass 从 runtime builtin 语义上剥离。
|
||||
2. 形成 editor renderer bundle 或 editor-only pass package 的组织方式。
|
||||
|
||||
## 本轮起手项
|
||||
|
||||
本轮先执行 Step 1。
|
||||
@@ -1,779 +0,0 @@
|
||||
# Unity 风格模型导入与 Model 资产架构重构计划
|
||||
|
||||
日期:2026-04-10
|
||||
|
||||
## 1. 文档定位
|
||||
|
||||
这份计划覆盖 XCEngine 现阶段外部模型资源导入链路的结构性重构,目标不是“再给 `MeshLoader` 多加几个扩展名”,而是把模型资源正式提升为接近 Unity 的 `ModelImporter + ModelAsset` 工作流。
|
||||
|
||||
本计划默认遵循以下战略判断:
|
||||
|
||||
1. 当前工程已经具备基于 `Assimp` 的基础静态模型读取能力,`.obj/.fbx/.gltf/.glb/.dae/.stl` 都能进入导入链。
|
||||
2. 当前主资源仍然是 `Mesh`,这导致导入时会把大量上层语义压扁到静态网格层。
|
||||
3. 如果要走 Unity 风格,后续继续在 `Mesh` 主资产上堆功能会越来越别扭,必须先补一层真正的 `Model` 资产。
|
||||
4. 骨骼动画不是本轮主目标,但本轮的数据结构和 artifact 设计必须为它预留正式扩展位。
|
||||
|
||||
本轮计划的本质是:
|
||||
|
||||
1. 把“source model import”和“runtime mesh load”拆开。
|
||||
2. 把“外部模型文件的主资产类型”从 `Mesh` 提升到 `Model`。
|
||||
3. 把 `.obj/.fbx/...` 的导入体验统一到一条 `ModelImporter` 主链上。
|
||||
|
||||
---
|
||||
|
||||
## 2. 当前状态判断
|
||||
|
||||
基于当前代码结构,可以确认已有能力与缺口如下。
|
||||
|
||||
### 2.1 已有能力
|
||||
|
||||
1. `MeshLoader` 已通过 `Assimp` 支持 `.fbx/.obj/.gltf/.glb/.dae/.stl/.xcmesh`。
|
||||
2. `AssetDatabase` 已将 `.obj/.fbx/.gltf/.glb/.dae/.stl` 识别为 `ModelImporter`。
|
||||
3. 编辑器 `MeshFilter` 的资源选择 UI 已允许 `.fbx/.obj/.gltf/.glb`。
|
||||
4. 工程已接入 `assimp-vc143-mt.dll`,说明构建链和基础运行依赖已经建立。
|
||||
5. 当前 artifact 管线已经具备 `xcmesh/xcmat/xctex` 的写入与回读能力。
|
||||
|
||||
### 2.2 当前核心问题
|
||||
|
||||
1. `ModelImporter` 的主资源类型实际上仍然是 `Mesh`,并不是真正的 `Model`。
|
||||
2. 导入时递归遍历 Assimp node,但会把 node transform 烘进顶点,原始层级、局部变换、pivot 语义丢失。
|
||||
3. `Mesh` 顶点结构当前仍是静态网格视角,只覆盖 `position/normal/tangent/bitangent/uv0`。
|
||||
4. `MeshImportSettings` 中虽然已经出现 `ImportSkinning / ImportAnimations / ImportCameras / ImportLights` 等标志,但没有形成对应的正式数据通路。
|
||||
5. `.meta` 当前只写 importer 名称和版本,没有形成 Unity 风格的模型导入设置持久化。
|
||||
6. 测试主要覆盖 `obj` 路径,针对真实 `fbx` fixture 的链路验证明显不足。
|
||||
7. 拖模型进场景时,现有工作流更接近“给一个 `GameObject` 绑定单个 `Mesh`”,而不是实例化一棵模型层级。
|
||||
|
||||
### 2.3 当前阶段最重要的判断
|
||||
|
||||
当前问题不在于“FBX 能不能读进来”,而在于“读进来以后是被当成 `Mesh` 还是被当成 `Model`”。
|
||||
|
||||
如果继续让外部模型文件直接产出主 `Mesh`:
|
||||
|
||||
1. `OBJ` 还能勉强成立。
|
||||
2. `FBX` 会不断丢失层级、pivot、子节点、多部件组织等上层语义。
|
||||
3. 后续无论做子资产展开、模型 prefab 化、骨骼动画还是稳定 reimport,都会越来越难。
|
||||
|
||||
---
|
||||
|
||||
## 3. 目标架构决策
|
||||
|
||||
### 3.1 总体决策
|
||||
|
||||
长期目标不是:
|
||||
|
||||
1. `OBJ -> Mesh`
|
||||
2. `FBX -> Model`
|
||||
|
||||
而是统一到:
|
||||
|
||||
1. 外部模型格式统一进入 `ModelImporter`
|
||||
2. `ModelImporter` 的主产物统一是 `Model`
|
||||
3. `Model` 内部再引用一个或多个 `Mesh/Material/Texture`
|
||||
|
||||
即:
|
||||
|
||||
1. `.obj -> 简化 Model`
|
||||
2. `.fbx -> 完整 Model`
|
||||
3. `.gltf/.glb/... -> 同样走 Model 主链`
|
||||
|
||||
这样做的好处是:
|
||||
|
||||
1. 资源系统主线统一。
|
||||
2. 编辑器工作流统一。
|
||||
3. 子资产稳定引用机制统一。
|
||||
4. 骨骼、动画、blend shape、嵌入纹理等后续扩展都有正式落点。
|
||||
|
||||
### 3.2 `Mesh` 与 `Model` 的职责边界
|
||||
|
||||
`Mesh` 只回答一件事:
|
||||
|
||||
1. 这个表面怎么画。
|
||||
|
||||
它应该承载:
|
||||
|
||||
1. 顶点数据
|
||||
2. 索引数据
|
||||
3. section
|
||||
4. bounds
|
||||
5. 材质槽位数量与 section-material 映射
|
||||
|
||||
`Model` 回答另一件事:
|
||||
|
||||
1. 这个资源整体怎么组织。
|
||||
|
||||
它应该承载:
|
||||
|
||||
1. 节点层级
|
||||
2. 节点局部 TRS
|
||||
3. 节点名字与路径
|
||||
4. 节点绑定的 mesh 引用
|
||||
5. 每个 mesh 节点的材质槽绑定
|
||||
6. 根节点信息
|
||||
7. 导入元数据
|
||||
8. 未来的 skeleton / animation / blend shape 扩展位
|
||||
|
||||
### 3.3 运行时链路的长期形态
|
||||
|
||||
长期上应当形成三层:
|
||||
|
||||
1. `ModelImporter`
|
||||
负责 source file -> artifact graph
|
||||
2. `ModelLoader`
|
||||
负责读取 `xcmodel`
|
||||
3. `MeshLoader`
|
||||
负责读取 `xcmesh`
|
||||
|
||||
其中:
|
||||
|
||||
1. `MeshLoader` 不再承担完整 source scene import 的主责任。
|
||||
2. `MeshLoader` 更适合退化成“运行时 mesh artifact 加载器 + builtin mesh loader”。
|
||||
3. 所有 source model 的正式导入都应该通过 `ModelImporter` 的专用实现完成。
|
||||
|
||||
---
|
||||
|
||||
## 4. 本轮范围与明确不做的内容
|
||||
|
||||
### 4.1 本轮必须完成
|
||||
|
||||
1. `Model` 资源类型与 `xcmodel` artifact。
|
||||
2. 统一的 `ModelImporter` 主链。
|
||||
3. `.meta` 中的 Model Import Settings 持久化。
|
||||
4. 保留层级的静态模型导入。
|
||||
5. 场景中实例化模型层级的工作流。
|
||||
6. 子资产与稳定 `LocalID` 规则。
|
||||
7. 编辑器中的模型导入设置 Inspector。
|
||||
8. `OBJ/FBX` 静态模型的正式测试闭环。
|
||||
|
||||
### 4.2 本轮暂不做
|
||||
|
||||
1. `SkinnedMeshRenderer` 正式渲染链。
|
||||
2. 骨骼矩阵上传与 GPU skinning。
|
||||
3. 动画 clip runtime 播放系统。
|
||||
4. blend shape runtime。
|
||||
5. 完整相机/灯光从 `FBX` 到 scene 的自动生成。
|
||||
6. 模型子资产在 Project 面板中的完整可展开 UI。
|
||||
|
||||
### 4.3 本轮只预留不落地的内容
|
||||
|
||||
1. `Skeleton` 资源类型接口
|
||||
2. `AnimationClip` 资源类型接口
|
||||
3. `Model` 中 skeleton/animation 的 artifact 扩展位
|
||||
4. skinning/blend shape 所需的稳定 source 标识规则
|
||||
|
||||
---
|
||||
|
||||
## 5. 目标数据结构设计
|
||||
|
||||
### 5.1 新增资源类型
|
||||
|
||||
建议在 `ResourceType` 中正式新增:
|
||||
|
||||
1. `Model`
|
||||
|
||||
同时保留已有:
|
||||
|
||||
1. `Mesh`
|
||||
2. `Material`
|
||||
3. `Texture`
|
||||
4. `AnimationClip`
|
||||
5. `Skeleton`
|
||||
|
||||
即使 `AnimationClip/Skeleton` 本轮不真正导出,也应在设计上与 `Model` 并列存在。
|
||||
|
||||
### 5.2 `Model` 资源结构建议
|
||||
|
||||
`Model` 至少包含以下结构:
|
||||
|
||||
1. `ModelNode`
|
||||
- `name`
|
||||
- `parentIndex`
|
||||
- `firstChildIndex / childCount` 或 child index array
|
||||
- `localPosition`
|
||||
- `localRotation`
|
||||
- `localScale`
|
||||
- `meshBindingStart`
|
||||
- `meshBindingCount`
|
||||
2. `ModelMeshBinding`
|
||||
- `meshLocalID`
|
||||
- `materialBindingStart`
|
||||
- `materialBindingCount`
|
||||
3. `ModelMaterialBinding`
|
||||
- `slotIndex`
|
||||
- `materialLocalID`
|
||||
4. `ModelImportMetadata`
|
||||
- importer version
|
||||
- source file signature
|
||||
- import settings snapshot
|
||||
|
||||
### 5.3 `Mesh` 资源职责调整
|
||||
|
||||
`Mesh` 继续作为低层渲染资源保留,但职责要收紧:
|
||||
|
||||
1. 不再把 source model file 当成它的长期主输入。
|
||||
2. 主要负责:
|
||||
- `xcmesh`
|
||||
- builtin mesh
|
||||
3. source format 直接读取只作为过渡能力,后续应弱化。
|
||||
|
||||
### 5.4 `Model` artifact 文件布局
|
||||
|
||||
建议 artifact 目录布局统一为:
|
||||
|
||||
1. `main.xcmodel`
|
||||
2. `mesh_0.xcmesh`
|
||||
3. `mesh_1.xcmesh`
|
||||
4. `material_0.xcmat`
|
||||
5. `material_1.xcmat`
|
||||
6. `texture_0.xctex`
|
||||
7. `texture_1.xctex`
|
||||
8. 未来可扩展:
|
||||
- `skeleton_0.xcskel`
|
||||
- `anim_0.xcanim`
|
||||
|
||||
### 5.5 `LocalID` 稳定规则
|
||||
|
||||
这是整个 Unity 风格方案里最关键的一部分。
|
||||
|
||||
不能简单使用“导入顺序下标”作为长期稳定标识。应当引入基于源语义的稳定 `LocalID` 生成策略:
|
||||
|
||||
1. Node:基于节点路径生成
|
||||
2. Mesh:基于节点路径 + mesh name + source mesh index 生成
|
||||
3. Material:基于 material name + source material index 生成
|
||||
4. Texture:基于 source texture path 或 embedded texture key 生成
|
||||
5. 后续骨骼/动画:基于骨骼名、clip 名、source index 生成
|
||||
|
||||
目标是:
|
||||
|
||||
1. 同一个模型在普通 reimport 后,子资产 `LocalID` 不变。
|
||||
2. 场景/prefab/材质槽引用不因为 artifact 目录变化而失效。
|
||||
|
||||
---
|
||||
|
||||
## 6. 导入链路重构方案
|
||||
|
||||
### 6.1 引入专用 source importer
|
||||
|
||||
建议新增专用模块,例如:
|
||||
|
||||
1. `AssimpModelImporter`
|
||||
|
||||
它的职责是:
|
||||
|
||||
1. 读取 `.obj/.fbx/.gltf/.glb/...`
|
||||
2. 产出统一中间结构 `ImportedModel`
|
||||
3. 再由 artifact writer 写出 `xcmodel/xcmesh/xcmat/xctex`
|
||||
|
||||
不建议继续把这部分主逻辑堆在 `MeshLoader` 内部。
|
||||
|
||||
### 6.2 导入中间结构
|
||||
|
||||
建议先建立 importer 内部中间结构:
|
||||
|
||||
1. `ImportedModel`
|
||||
2. `ImportedNode`
|
||||
3. `ImportedMesh`
|
||||
4. `ImportedMaterial`
|
||||
5. `ImportedTexture`
|
||||
|
||||
这样可以把:
|
||||
|
||||
1. Assimp scene 读取
|
||||
2. 引擎内部资源表示
|
||||
3. artifact 写出
|
||||
|
||||
三者解耦。
|
||||
|
||||
### 6.3 节点与变换处理原则
|
||||
|
||||
这是与当前实现最大的差异之一。
|
||||
|
||||
当前做法是把 `node` 变换乘到顶点上,再把所有几何收进同一个 `Mesh`。本轮要改成:
|
||||
|
||||
1. Mesh 顶点保持在 mesh local space
|
||||
2. Node local transform 单独存进 `Model`
|
||||
3. Scene 实例化时再把 node local transform 还原到 `GameObject`
|
||||
|
||||
只有这样才能保留:
|
||||
|
||||
1. 层级
|
||||
2. pivot
|
||||
3. 本地 TRS
|
||||
4. 后续动画骨骼的基础结构
|
||||
|
||||
### 6.4 轴系与缩放的处理原则
|
||||
|
||||
建议明确以下规则:
|
||||
|
||||
1. 轴系转换属于导入标准化步骤,但不能以“摧毁原始层级”为代价。
|
||||
2. 全局 import scale 应优先体现在 root 侧或 mesh 侧的单一标准化策略中,不要 mesh 与 node 两边重复施加。
|
||||
3. 一旦规则确定,要在 `ModelImportSettings` 中固定,并进入 `metaHash`。
|
||||
|
||||
本轮必须把“坐标转换在哪里做、缩放在哪里做”写成正式约束,而不是散落在 loader 里。
|
||||
|
||||
### 6.5 `OBJ` 的导入策略
|
||||
|
||||
`OBJ` 仍然统一走 `ModelImporter`,但导入结果通常是一个简化模型:
|
||||
|
||||
1. 一个 root node
|
||||
2. 一个或少量 mesh node
|
||||
3. 少量 material bindings
|
||||
|
||||
即:
|
||||
|
||||
1. `OBJ` 不是继续作为架构特例保留在 `Mesh` 主链外面
|
||||
2. 它只是“语义很简单的 model source”
|
||||
|
||||
### 6.6 `FBX` 的导入策略
|
||||
|
||||
`FBX` 则要保留完整静态结构:
|
||||
|
||||
1. node hierarchy
|
||||
2. local transform
|
||||
3. mesh attachments
|
||||
4. material slots
|
||||
5. embedded/external textures
|
||||
6. 后续可扩展 skeleton/animation metadata
|
||||
|
||||
即使本轮不做动画,也不应该再把 `FBX` 烘成单个主 `Mesh`。
|
||||
|
||||
---
|
||||
|
||||
## 7. AssetDatabase 与 ArtifactDatabase 改造计划
|
||||
|
||||
### 7.1 主资产类型调整
|
||||
|
||||
当前 `ModelImporter` 的主资产仍是 `Mesh`。本轮要改成:
|
||||
|
||||
1. `ModelImporter` 主资产类型为 `Model`
|
||||
2. `mainLocalID` 指向 `Model` 主资产
|
||||
3. `Mesh/Material/Texture` 成为其子资产
|
||||
|
||||
### 7.2 `EnsureArtifact` 语义调整
|
||||
|
||||
对 `Assets/Models/robot.fbx` 执行 `EnsureArtifact(..., ResourceType::Model)` 时:
|
||||
|
||||
1. 返回主 `xcmodel`
|
||||
2. 内部子资产可通过 `AssetRef(assetGuid, localID, resourceType)` 访问
|
||||
|
||||
若后续有需要,`MeshFilter` 等组件可直接引用某个 `Mesh` 子资产,而不是引用主 `Model`。
|
||||
|
||||
### 7.3 依赖追踪调整
|
||||
|
||||
当前依赖追踪对 `obj -> mtl -> texture` 已有基础覆盖,但本轮要升级成通用模型依赖追踪:
|
||||
|
||||
1. source model file
|
||||
2. 外部纹理
|
||||
3. embedded texture 的派生 key
|
||||
4. 导入设置 meta
|
||||
5. future:外部 animation source / skeleton source
|
||||
|
||||
目标是:
|
||||
|
||||
1. 改 texture 会触发模型 reimport
|
||||
2. 改 importer settings 会触发模型 reimport
|
||||
3. 子资产 artifact 会稳定重建
|
||||
|
||||
### 7.4 资源查询接口调整
|
||||
|
||||
建议新增或调整:
|
||||
|
||||
1. `TryGetAssetRef(path, ResourceType::Model, ...)`
|
||||
2. `TryGetSubAssetRef(path, subAssetKey or localID, ResourceType::Mesh, ...)`
|
||||
3. `TryGetPrimaryAssetPath(guid, ...)` 对 `Model` 继续保持主资产语义
|
||||
|
||||
同时要保证:
|
||||
|
||||
1. 主 `Model` 与子 `Mesh` 的引用路径语义清晰
|
||||
2. 编辑器与场景序列化知道自己引用的是主资产还是子资产
|
||||
|
||||
---
|
||||
|
||||
## 8. `.meta` 与导入设置计划
|
||||
|
||||
### 8.1 当前问题
|
||||
|
||||
当前 `.meta` 只有:
|
||||
|
||||
1. `guid`
|
||||
2. `folderAsset`
|
||||
3. `importer`
|
||||
4. `importerVersion`
|
||||
|
||||
这不足以支撑 Unity 风格模型工作流。
|
||||
|
||||
### 8.2 新增 `ModelImportSettings`
|
||||
|
||||
建议正式引入或升级为:
|
||||
|
||||
1. `ModelImportSettings`
|
||||
|
||||
至少包括:
|
||||
|
||||
1. `globalScale`
|
||||
2. `axisConversion`
|
||||
3. `flipUVs`
|
||||
4. `flipWindingOrder`
|
||||
5. `generateNormals`
|
||||
6. `generateTangents`
|
||||
7. `importMaterials`
|
||||
8. `extractEmbeddedTextures`
|
||||
9. `preserveHierarchy`
|
||||
10. `mergeStaticMeshes`
|
||||
11. 预留:
|
||||
- `importSkinning`
|
||||
- `importAnimations`
|
||||
- `importCameras`
|
||||
- `importLights`
|
||||
|
||||
### 8.3 `.meta` 持久化规则
|
||||
|
||||
应当把上述设置正式写入 `.meta`,并参与 `metaHash`。
|
||||
|
||||
目标是:
|
||||
|
||||
1. 切换 importer setting 后 artifact key 会变化
|
||||
2. `Reimport` 有明确语义
|
||||
3. Inspector 改完设置能稳定反映到导入结果
|
||||
|
||||
### 8.4 版本策略
|
||||
|
||||
建议:
|
||||
|
||||
1. `ModelImporter` 单独维护 importer version
|
||||
2. 当 `xcmodel` schema 或子资产布局变化时,显式提升版本号
|
||||
3. 不再使用“整个 AssetDatabase 共用一个笼统版本号”来覆盖全部导入器变化
|
||||
|
||||
---
|
||||
|
||||
## 9. 编辑器工作流计划
|
||||
|
||||
### 9.1 Project 面板语义
|
||||
|
||||
`.obj/.fbx/.gltf/.glb/...` 在 Project 面板中应统一显示为:
|
||||
|
||||
1. `Model`
|
||||
|
||||
而不是继续让用户默认把这些资源理解成“单个 mesh 文件”。
|
||||
|
||||
### 9.2 Model Importer Inspector
|
||||
|
||||
选中模型资源时,Inspector 需要出现真正的导入设置面板:
|
||||
|
||||
1. Import Settings
|
||||
2. Apply
|
||||
3. Revert
|
||||
4. Reimport
|
||||
|
||||
首批显示的设置至少包括:
|
||||
|
||||
1. Scale
|
||||
2. Axis Conversion
|
||||
3. Preserve Hierarchy
|
||||
4. Import Materials
|
||||
5. Generate Normals
|
||||
6. Generate Tangents
|
||||
7. Flip UVs
|
||||
|
||||
### 9.3 场景拖拽行为
|
||||
|
||||
把模型资源拖进场景时,不应只创建一个空物体加一个 `MeshFilter`。
|
||||
|
||||
推荐行为:
|
||||
|
||||
1. 读取 `Model`
|
||||
2. 生成对应 `GameObject` 树
|
||||
3. 按节点局部变换恢复 TRS
|
||||
4. 对带 mesh 的节点挂 `MeshFilter + MeshRenderer`
|
||||
5. 材质槽按 `Model` 内的绑定还原
|
||||
|
||||
这才接近 Unity 的“拖入模型得到层级实例”。
|
||||
|
||||
### 9.4 子资产访问
|
||||
|
||||
本轮不强制要求 Project 面板完整展开子资产树,但至少应保证:
|
||||
|
||||
1. `MeshFilter` 能引用模型产出的某个 `Mesh` 子资产
|
||||
2. 场景序列化后引用稳定
|
||||
3. 后续补 Project 子资产展开 UI 时不需要推倒重来
|
||||
|
||||
---
|
||||
|
||||
## 10. 场景实例化与运行时路径
|
||||
|
||||
### 10.1 不建议增加 `ModelComponent`
|
||||
|
||||
为了贴近 Unity,建议不要把“整个模型实例”抽成一个新的 `ModelComponent` 挂在单个对象上。
|
||||
|
||||
更合理的做法是:
|
||||
|
||||
1. `Model` 是资源
|
||||
2. “实例化模型”是一个 utility / service
|
||||
3. 实例化结果是 `GameObject` 层级
|
||||
|
||||
### 10.2 建议新增实例化工具层
|
||||
|
||||
可以新增例如:
|
||||
|
||||
1. `ModelInstantiationUtility`
|
||||
2. `InstantiateModelAsset(...)`
|
||||
|
||||
职责:
|
||||
|
||||
1. 根据 `Model` 创建场景层级
|
||||
2. 为每个节点恢复局部 TRS
|
||||
3. 绑定子 `Mesh`
|
||||
4. 绑定默认材质或导入材质
|
||||
|
||||
### 10.3 与现有渲染链的兼容策略
|
||||
|
||||
现有渲染链以 `MeshFilter + MeshRenderer` 为中心,这一层本轮不应推翻。
|
||||
|
||||
本轮应当:
|
||||
|
||||
1. 保持 runtime 渲染主链稳定
|
||||
2. 通过新的 `Model -> GameObject hierarchy` 实例化路径,把 `Model` 翻译回现有组件体系
|
||||
|
||||
这样风险最小,且后续加 `SkinnedMeshRenderer` 时也有自然落点。
|
||||
|
||||
---
|
||||
|
||||
## 11. 测试与验证计划
|
||||
|
||||
### 11.1 Fixture 规划
|
||||
|
||||
必须新增真实模型 fixture,不再只停留在字符串层面的 `CanLoad("test.fbx")`。
|
||||
|
||||
建议至少准备:
|
||||
|
||||
1. `single_mesh_static.obj`
|
||||
2. `single_mesh_static.fbx`
|
||||
3. `multi_node_static.fbx`
|
||||
4. `multi_material_static.fbx`
|
||||
5. `embedded_texture_static.fbx`
|
||||
6. `external_texture_static.fbx`
|
||||
|
||||
### 11.2 Unit Test
|
||||
|
||||
建议新增或扩展:
|
||||
|
||||
1. `ModelLoader` 基础加载测试
|
||||
2. `ModelImportSettings` 持久化测试
|
||||
3. `ModelArtifact` 写入/回读测试
|
||||
4. `LocalID` 稳定性测试
|
||||
5. `AssetDatabase` 主资产/子资产引用测试
|
||||
|
||||
### 11.3 Integration Test
|
||||
|
||||
建议新增:
|
||||
|
||||
1. `FBX -> xcmodel -> scene instantiate` 集成测试
|
||||
2. reimport 后 `AssetRef` 稳定性测试
|
||||
3. 多节点模型实例化后层级与局部变换恢复测试
|
||||
4. 多材质槽绑定测试
|
||||
|
||||
### 11.4 Editor Test
|
||||
|
||||
建议补:
|
||||
|
||||
1. Project 面板模型类型识别
|
||||
2. Model Importer Inspector 设置编辑
|
||||
3. Apply/Reimport 行为
|
||||
4. 拖模型到场景生成层级
|
||||
|
||||
### 11.5 验收原则
|
||||
|
||||
本轮不能以“能读进一个 FBX 文件”作为完成标准。
|
||||
|
||||
必须同时满足:
|
||||
|
||||
1. artifact 正确
|
||||
2. hierarchy 正确
|
||||
3. reimport 稳定
|
||||
4. editor 工作流成立
|
||||
|
||||
---
|
||||
|
||||
## 12. 分阶段执行计划
|
||||
|
||||
### Phase 1:`Model` 资源与 artifact 基础设施落地
|
||||
|
||||
目标:
|
||||
|
||||
1. 新增 `ResourceType::Model`
|
||||
2. 新增 `Model` 类与 `ModelLoader`
|
||||
3. 新增 `xcmodel` artifact 格式
|
||||
|
||||
任务:
|
||||
|
||||
1. 设计 `ModelNode / ModelMeshBinding / ModelMaterialBinding`
|
||||
2. 在 `ArtifactFormats` 中定义 `ModelArtifactHeader`
|
||||
3. 实现 `WriteModelArtifactFile / LoadModelArtifact`
|
||||
4. 让 `ResourceManager` 注册 `ModelLoader`
|
||||
|
||||
验收标准:
|
||||
|
||||
1. `xcmodel` 能写出与读回
|
||||
2. `Model` 可被 `ResourceManager` 正式加载
|
||||
|
||||
### Phase 2:source import 主链从 `Mesh` 迁移到 `Model`
|
||||
|
||||
目标:
|
||||
|
||||
1. 建立 `AssimpModelImporter`
|
||||
2. 将 `.obj/.fbx/...` 的正式导入主链切换到 `Model`
|
||||
|
||||
任务:
|
||||
|
||||
1. 建立 `ImportedModel` 中间结构
|
||||
2. 从 Assimp scene 提取节点层级、局部 TRS、mesh、material、texture
|
||||
3. 停止在导入主链中把 node transform 烘平到单个主 mesh
|
||||
4. 输出 `main.xcmodel + sub assets`
|
||||
|
||||
验收标准:
|
||||
|
||||
1. `OBJ` 被导入成简化 `Model`
|
||||
2. `FBX` 被导入成保留 hierarchy 的 `Model`
|
||||
|
||||
### Phase 3:`AssetDatabase` 子资产与稳定 `LocalID`
|
||||
|
||||
目标:
|
||||
|
||||
1. 完成主资产/子资产语义
|
||||
2. 建立稳定 `LocalID` 规则
|
||||
|
||||
任务:
|
||||
|
||||
1. 修改 `ModelImporter` 的主资源类型
|
||||
2. 实现模型子资产 `AssetRef`
|
||||
3. 让 `EnsureArtifact`、`TryGetAssetRef`、序列化链路理解 `Model` 主资产与子 `Mesh`
|
||||
4. 建立 reimport 稳定性测试
|
||||
|
||||
验收标准:
|
||||
|
||||
1. reimport 后子资产引用不漂移
|
||||
2. 场景中的 mesh 引用可稳定恢复
|
||||
|
||||
### Phase 4:`.meta` 与 Model Import Settings 正式化
|
||||
|
||||
目标:
|
||||
|
||||
1. 让模型导入参数进入正式工作流
|
||||
|
||||
任务:
|
||||
|
||||
1. 定义 `ModelImportSettings`
|
||||
2. 把 settings 写入 `.meta`
|
||||
3. 调整 `metaHash`
|
||||
4. 保证 settings 变化触发 reimport
|
||||
|
||||
验收标准:
|
||||
|
||||
1. 改 scale/axis/material 等设置会稳定影响导入结果
|
||||
2. artifact key 与导入设置一致变化
|
||||
|
||||
### Phase 5:编辑器 Inspector 与场景实例化工作流
|
||||
|
||||
目标:
|
||||
|
||||
1. 建立 Unity 风格的模型资源使用体验
|
||||
|
||||
任务:
|
||||
|
||||
1. Project 面板统一把模型文件识别为 `Model`
|
||||
2. 新增 Model Importer Inspector
|
||||
3. 实现 `Apply/Reimport`
|
||||
4. 实现拖模型到场景生成 `GameObject` 层级
|
||||
|
||||
验收标准:
|
||||
|
||||
1. 从 editor 可完整配置模型导入
|
||||
2. 拖入场景后层级与局部变换正确
|
||||
|
||||
### Phase 6:清理过渡路径与补齐文档测试
|
||||
|
||||
目标:
|
||||
|
||||
1. 收紧旧路径,避免双轨架构长期并存
|
||||
|
||||
任务:
|
||||
|
||||
1. 评估并逐步弱化“source file 直接由 `MeshLoader` 作为主入口”的旧路径
|
||||
2. 清理命名、文档、注释、测试目录结构
|
||||
3. 输出阶段总结
|
||||
|
||||
验收标准:
|
||||
|
||||
1. 主链路清晰,旧路径只保留必要兼容
|
||||
2. 文档与测试同步完成
|
||||
|
||||
---
|
||||
|
||||
## 13. 关键风险与应对
|
||||
|
||||
### 13.1 最大风险:`LocalID` 不稳定
|
||||
|
||||
风险:
|
||||
|
||||
1. reimport 后子资产重排
|
||||
2. 场景与 prefab 引用失效
|
||||
|
||||
应对:
|
||||
|
||||
1. 在 Phase 1 之前先写清 `LocalID` 规则
|
||||
2. 在 Phase 3 前就建立稳定性测试
|
||||
|
||||
### 13.2 第二风险:轴系与缩放规则前后不一致
|
||||
|
||||
风险:
|
||||
|
||||
1. 同一模型在 direct load、artifact load、scene instantiate 三条路径下结果不一致
|
||||
|
||||
应对:
|
||||
|
||||
1. 明确标准化规则只允许一个真值来源
|
||||
2. 写入 importer settings 并进入测试
|
||||
|
||||
### 13.3 第三风险:编辑器体验与底层数据不同步
|
||||
|
||||
风险:
|
||||
|
||||
1. Inspector 改了设置但 reimport 行为不稳定
|
||||
2. Project 面板显示的是 `Model`,内部实际仍按 `Mesh` 走
|
||||
|
||||
应对:
|
||||
|
||||
1. 先完成 Resource/AssetDatabase 语义,再接 editor UI
|
||||
2. 不允许 editor 先行伪装完成
|
||||
|
||||
### 13.4 第四风险:过渡期双轨逻辑长期共存
|
||||
|
||||
风险:
|
||||
|
||||
1. `MeshLoader` source import 与 `ModelImporter` source import 两套路径并行,长期维护成本失控
|
||||
|
||||
应对:
|
||||
|
||||
1. 在 Phase 6 明确收紧旧路径
|
||||
2. 把 source import 主入口统一到 `ModelImporter`
|
||||
|
||||
---
|
||||
|
||||
## 14. 本轮完成标志
|
||||
|
||||
当以下条件同时成立时,本轮才算真正完成:
|
||||
|
||||
1. `.obj/.fbx/.gltf/.glb/...` 的主资产统一为 `Model`
|
||||
2. `Model` artifact 已正式落地并进入 `ResourceManager`
|
||||
3. `OBJ` 能导入成简化 `Model`
|
||||
4. `FBX` 能导入成保留 hierarchy 的静态 `Model`
|
||||
5. 模型导入设置已写入 `.meta` 并进入 reimport 逻辑
|
||||
6. editor 中已具备 Model Importer Inspector
|
||||
7. 拖模型到场景时会生成 `GameObject` 层级,而非单个烘平 mesh
|
||||
8. 子资产 `LocalID` 在普通 reimport 下稳定
|
||||
9. 测试已覆盖真实 `FBX` fixture 的关键路径
|
||||
|
||||
---
|
||||
|
||||
## 15. 一句话结论
|
||||
|
||||
这一轮不是“给 FBX 补支持”,而是把 XCEngine 的外部模型资源体系从“以 `Mesh` 为主资产的静态导入器”升级成“以 `Model` 为主资产、以子资产和稳定 reimport 为基础、可持续扩展到骨骼动画的 Unity 风格模型工作流”。
|
||||
@@ -1,333 +0,0 @@
|
||||
# NewEditor 3D渲染主链正式接入计划
|
||||
|
||||
日期: `2026-04-12`
|
||||
|
||||
## 1. 文档定位
|
||||
|
||||
这份计划替代此前那份偏宽泛的《NewEditor 对标旧 Editor 迁移重建计划》。
|
||||
|
||||
当前主线已经很明确:
|
||||
|
||||
- `new_editor` 的 UI 基础壳已经足够继续往上承接。
|
||||
- 真正卡住后续重建编辑器的,不再是普通面板样式或 tab/dock 行为。
|
||||
- 当前最大的主阻塞,是 `Scene / Game` 还没有接上旧 `editor` 里已经跑通的真实 3D 渲染主链。
|
||||
|
||||
因此,接下来要先做的不是继续铺业务面板,而是:
|
||||
|
||||
1. 先把 `new_editor` 的宿主渲染链补齐。
|
||||
2. 再把旧 `editor` 的 viewport/rendering 主链正式迁入 `new_editor`。
|
||||
3. 等 `Scene / Game` 真正稳定输出真实 3D 画面后,再继续后续编辑器业务迁移。
|
||||
|
||||
## 2. 当前事实与根因判断
|
||||
|
||||
### 2.1 旧 editor 当前的真实可用主链
|
||||
|
||||
旧 `editor` 的 Scene/Game viewport 不是面板里临时拼的,它已经形成了明确主链:
|
||||
|
||||
`Application -> D3D12WindowRenderer -> ViewportHostService -> SceneRenderer -> ViewportRenderTargets -> ImGui texture presentation`
|
||||
|
||||
当前关键代码入口:
|
||||
|
||||
- `editor/src/Application.cpp`
|
||||
- `editor/src/Platform/D3D12WindowRenderer.h`
|
||||
- `editor/src/Viewport/ViewportHostService.h`
|
||||
- `editor/src/panels/SceneViewPanel.cpp`
|
||||
- `editor/src/panels/GameViewPanel.cpp`
|
||||
|
||||
### 2.2 new_editor 当前的真实状态
|
||||
|
||||
`new_editor` 现在已经有:
|
||||
|
||||
- `XCEditor` UI 基础层
|
||||
- Win32 + `NativeRenderer` 宿主层
|
||||
- `Hierarchy / Inspector / Console / Project` 这些 hosted content 面板外壳
|
||||
|
||||
但 `Scene / Game` 这条线并没有真正接上旧 editor 的 render path。
|
||||
|
||||
当前缺口是结构性的:
|
||||
|
||||
1. `new_editor/app/Shell/ProductShellAsset.cpp` 里,`scene` 和 `game` 仍然只是 `HostedContent`,还没有切到正式的 `ViewportShell` 主线。
|
||||
2. `new_editor/app/Workspace/ProductEditorWorkspace.cpp` 里,没有真正的 viewport service owner,也没有 scene/game render request 生命周期。
|
||||
3. `new_editor/app/Host/NativeRenderer.h/.cpp` 当前是 Direct2D/DirectWrite 宿主,只支持它自己的位图纹理路径。
|
||||
4. `engine/include/XCEngine/UI/Types.h` 虽然已经有 `UITextureHandleKind::ShaderResourceView`,但 `NativeRenderer` 目前并没有真正消费这类引擎 render target。
|
||||
|
||||
### 2.3 根因结论
|
||||
|
||||
当前问题的根因不是“Scene 面板还没抄过来”,而是:
|
||||
|
||||
- `new_editor` 宿主层还没有与引擎 `Rendering + RHI` 建立正式的 viewport 纹理桥接。
|
||||
- `XCEditor` 的 viewport 壳层虽然已经存在,但 `new_editor` 还没把它真正接到 GPU viewport frame 上。
|
||||
|
||||
所以这件事必须从宿主渲染架构开始修,不能从面板层糊。
|
||||
|
||||
## 3. 不可违背的执行原则
|
||||
|
||||
### 3.1 根因优先
|
||||
|
||||
- 禁止 CPU 截图回读后再贴回 UI。
|
||||
- 禁止用 PNG/中间 bitmap/调试贴图冒充正式 viewport 输出。
|
||||
- 禁止在 `Scene` 或 `Game` 面板内部偷偷持有一套临时渲染路径。
|
||||
|
||||
### 3.2 旧 editor 只作为基线,不照搬 ImGui 壳
|
||||
|
||||
- 要复用旧 editor 已经验证过的 render host、viewport service、render target、object id、overlay 这些真实主链能力。
|
||||
- 但不要把 `ImGui panel` 那一层硬抄到 `new_editor`。
|
||||
- 迁移时要抽出“引擎桥接能力”,接回 `XCEditor` 的 viewport shell。
|
||||
|
||||
### 3.3 Scene/Game 必须统一走正式 viewport 子系统
|
||||
|
||||
- `Scene` 和 `Game` 不能继续当普通 hosted content 面板处理。
|
||||
- 它们必须切到同一套 `ViewportShell -> ViewportService -> RenderTargets -> RenderFrame` 路径。
|
||||
- Scene/Game 的差异只能体现在 camera / overlay / input policy,不应该体现在宿主渲染基础设施层。
|
||||
|
||||
### 3.4 每阶段都能独立验证
|
||||
|
||||
每一阶段结束都必须满足:
|
||||
|
||||
- 能编译 `XCUIEditorApp`
|
||||
- 能运行 exe
|
||||
- 能给出明确的人工检查点
|
||||
|
||||
## 4. 目标架构
|
||||
|
||||
## 4.1 new_editor 最终应形成的 viewport 主链
|
||||
|
||||
目标主链:
|
||||
|
||||
`Win32 Application -> Host Window Renderer -> XCEditor ViewportShell -> ProductViewportHostService -> SceneRenderer -> RHI RenderTargets -> Viewport Texture Bridge -> XCEditor Compose -> Window Present`
|
||||
|
||||
分层责任:
|
||||
|
||||
- `Host`
|
||||
- 管窗口、swapchain、command queue、command list、descriptor heap、present
|
||||
- `XCEditor`
|
||||
- 管 viewport 壳层布局、top bar、bottom bar、input bridge、状态显示
|
||||
- `new_editor/app/Viewport`
|
||||
- 管 Scene/Game viewport 请求、render target 生命周期、editor scene camera、input 解释、selection/picking/overlay
|
||||
- `Rendering + RHI`
|
||||
- 管真正的 scene render requests 和 GPU 输出
|
||||
|
||||
## 4.2 宿主层方向
|
||||
|
||||
`NativeRenderer` 当前的 D2D-only `HwndRenderTarget` 不能作为长期正式宿主。
|
||||
|
||||
新的宿主方向应当是:
|
||||
|
||||
- 以 D3D12/RHI swapchain 作为主呈现链
|
||||
- 在这个主呈现链上承接 `XCEditor` UI 组合与 engine viewport 纹理
|
||||
|
||||
关于 2D UI 绘制策略,允许按实际情况调整实现,但边界必须固定:
|
||||
|
||||
- 可以保留 D2D/DWrite 作为 2D 绘制后端,但它只能作为从属 UI compositor,不能继续做整个窗口的唯一主呈现链
|
||||
- 如果 D2D 与 D3D12 的互操作复杂度失控,就切换为更直接的 GPU UI compositor
|
||||
- 无论选择哪条实现路径,都不能回退到 CPU 回读/贴图绕路
|
||||
|
||||
## 5. 执行阶段
|
||||
|
||||
## 阶段 A: 宿主渲染基础设施对齐
|
||||
|
||||
目标:
|
||||
|
||||
- 先把 `new_editor` 宿主从“D2D-only 窗口绘制器”升级为“真正的窗口 render host”
|
||||
|
||||
主要工作:
|
||||
|
||||
1. 在 `new_editor/app/Host` 下建立正式的 window renderer
|
||||
2. 对齐旧 `editor/src/Platform/D3D12WindowRenderer.h` 的能力边界
|
||||
3. 让 `Application` 能拿到:
|
||||
- `RHIDevice`
|
||||
- `RHICommandQueue`
|
||||
- `RHICommandList`
|
||||
- swapchain backbuffer surface
|
||||
- shader-visible descriptor heap
|
||||
- 每帧 begin/present 生命周期
|
||||
4. 保留并接回现有 DPI / resize / cursor / screenshot 生命周期
|
||||
|
||||
验收:
|
||||
|
||||
- `XCUIEditor.exe` 能用新宿主稳定打开
|
||||
- 调整窗口尺寸时不会再出现位图式整体拉伸
|
||||
- 空窗口 clear/present 稳定,无闪烁、无明显 resize 延迟
|
||||
|
||||
## 阶段 B: Viewport 纹理桥接正式化
|
||||
|
||||
目标:
|
||||
|
||||
- 让 `XCEditor` viewport slot 真正能展示来自引擎 RHI 的 render target
|
||||
|
||||
主要工作:
|
||||
|
||||
1. 明确 `UITextureHandle` 在 `new_editor` 中的正式 viewport 语义
|
||||
2. 补齐 `ShaderResourceView` 路径,而不是继续只支持文件位图
|
||||
3. 建立 render target -> UI texture handle 的生命周期管理
|
||||
4. 处理 descriptor/state/resize/recreate 规则
|
||||
|
||||
建议测试:
|
||||
|
||||
- 在 `tests/UI/Editor/integration` 下新增专门的 viewport GPU 纹理验证用例
|
||||
- 先用一个最小 GPU clear/checkerboard 纹理跑通 `ViewportShell`
|
||||
|
||||
验收:
|
||||
|
||||
- `ViewportShell` 可显示真实 GPU render target
|
||||
- viewport 尺寸变化时,纹理尺寸和显示内容立即同步
|
||||
- 整个链路不含 readback / screenshot / 中间文件
|
||||
|
||||
## 阶段 C: Scene/Game 从 HostedContent 切到 ViewportShell
|
||||
|
||||
目标:
|
||||
|
||||
- 让 `scene` 和 `game` 不再是伪面板,而是正式 viewport panel
|
||||
|
||||
主要工作:
|
||||
|
||||
1. 修改 `ProductShellAsset` 中 `scene/game` 的 presentation 模型
|
||||
2. 在 `new_editor/app` 建立正式的 viewport panel 装配点
|
||||
3. 建立 viewport request/response 数据模型:
|
||||
- requested size
|
||||
- presented frame
|
||||
- status text
|
||||
- capture/focus/input state
|
||||
|
||||
验收:
|
||||
|
||||
- `Scene` 和 `Game` 面板进入统一 viewport 壳层
|
||||
- 可以显示“真实 viewport frame”,不再是纯 placeholder/调试文案
|
||||
|
||||
## 阶段 D: Scene 真实渲染最小闭环
|
||||
|
||||
目标:
|
||||
|
||||
- 先让 `Scene` 面板输出旧 editor 那条真实 3D 场景渲染
|
||||
|
||||
主要工作:
|
||||
|
||||
1. 在 `new_editor/app/Viewport` 下建立 `ProductViewportHostService`
|
||||
2. 先迁移旧 `ViewportHostService` 的最小 spine:
|
||||
- scene editor camera state
|
||||
- scene viewport render targets
|
||||
- `SceneRenderer` 调用
|
||||
- status/failure policy
|
||||
3. 只先做“能稳定渲染”的最小闭环
|
||||
4. 暂时不带 gizmo,不带复杂 overlay,不带过多面板业务联动
|
||||
|
||||
验收:
|
||||
|
||||
- `Scene` 面板显示真实 3D 场景
|
||||
- resize 时 render target 立即更新
|
||||
- 画面不是占位实现,不是 2D 假画面
|
||||
|
||||
## 阶段 E: Game 真实渲染闭环
|
||||
|
||||
目标:
|
||||
|
||||
- 接上 `Game` 面板的真实 camera render path
|
||||
|
||||
主要工作:
|
||||
|
||||
1. 对齐旧 editor 的 game viewport 请求方式
|
||||
2. 使用 active scene camera 或旧 editor 当前约定的 camera 选择规则
|
||||
3. 接上 game viewport 状态显示和 resize 规则
|
||||
|
||||
验收:
|
||||
|
||||
- `Game` 面板显示真实场景相机输出
|
||||
- 与 `Scene` 共享宿主基础设施,但 camera 语义独立
|
||||
|
||||
## 阶段 F: Scene 输入、导航、拾取
|
||||
|
||||
目标:
|
||||
|
||||
- 在真实 3D 画面已经稳定的前提下,补回 Scene 交互
|
||||
|
||||
主要工作:
|
||||
|
||||
1. 迁移 scene camera navigation
|
||||
2. 迁移 focus selection
|
||||
3. 迁移 object id picking
|
||||
4. 接回 selection 路由
|
||||
|
||||
验收:
|
||||
|
||||
- 右键看、平移、缩放、聚焦等基础导航恢复
|
||||
- 点击对象能正确选中
|
||||
|
||||
## 阶段 G: Overlay / Gizmo / Editor 辅助渲染
|
||||
|
||||
目标:
|
||||
|
||||
- 继续对齐旧 editor 的 editor-only viewport 叠加能力
|
||||
|
||||
主要工作:
|
||||
|
||||
1. overlay frame cache
|
||||
2. overlay builder
|
||||
3. selection outline / orientation / transform gizmo
|
||||
4. Scene/Game 差异化 overlay policy
|
||||
|
||||
验收:
|
||||
|
||||
- Scene overlay 与 gizmo 基本达到旧 editor 可用水平
|
||||
- 不因 overlay 引入新的渲染路径分叉
|
||||
|
||||
## 6. 并行切分策略
|
||||
|
||||
这条主线不是完全串行,但前两阶段有明显关键路径。
|
||||
|
||||
### 必须串行的部分
|
||||
|
||||
1. 阶段 A 宿主 render host
|
||||
2. 阶段 B viewport 纹理桥接
|
||||
|
||||
这两步没完成,后面的 Scene/Game 真渲染都只能是假接入。
|
||||
|
||||
### 可以并行的部分
|
||||
|
||||
在 A/B 基本定型后,可并行拆为 3 组:
|
||||
|
||||
1. `Host`
|
||||
- window renderer
|
||||
- present/frame lifecycle
|
||||
- viewport texture bridge
|
||||
2. `app/Viewport`
|
||||
- render targets
|
||||
- scene/game render request owner
|
||||
- status/failure policy
|
||||
3. `XCEditor` / `app/Shell`
|
||||
- scene/game 切换到 `ViewportShell`
|
||||
- viewport 状态展示
|
||||
- 相关 integration tests
|
||||
|
||||
## 7. 明确不做的事
|
||||
|
||||
这份计划期间,不做以下偏移主线的工作:
|
||||
|
||||
- 不继续优先铺新的业务面板细节
|
||||
- 不先做 inspector/component editor 的深层业务联动
|
||||
- 不把 runtime UI 主题资源机制重新塞回 editor UI
|
||||
- 不用临时截图/静态贴图假装 viewport
|
||||
|
||||
## 8. 收口标准
|
||||
|
||||
满足以下条件,才算 `new_editor` 的 3D 渲染基础层正式收口:
|
||||
|
||||
1. `Scene` 和 `Game` 都显示真实 3D GPU 输出
|
||||
2. resize、DPI、focus、capture 行为稳定
|
||||
3. viewport 纹理链路不依赖 ImGui
|
||||
4. Scene 基础导航和 picking 恢复
|
||||
5. 后续继续重建 `new_editor` 时,不需要再回头推倒宿主渲染基础层
|
||||
|
||||
## 9. 旧计划归档说明
|
||||
|
||||
本轮归档:
|
||||
|
||||
- `docs/plan/used/NewEditor对标旧Editor迁移重建计划_2026-04-12.md`
|
||||
|
||||
保留为参考文档,不归档:
|
||||
|
||||
- `docs/plan/Editor架构说明.md`
|
||||
|
||||
原因:
|
||||
|
||||
- 它仍然是旧 editor 分层与边界的有效参考
|
||||
- 但当前主线已经从“泛迁移计划”切换为“viewport / rendering 主链正式接入计划”
|
||||
@@ -1,368 +0,0 @@
|
||||
# NewEditor Tab 脱离独立窗口重构计划
|
||||
|
||||
日期: `2026-04-14`
|
||||
|
||||
## 1. 目标
|
||||
|
||||
把 `new_editor` 当前“只能在主窗口内部重排 / dock”的 tab 系统,重构为支持:
|
||||
|
||||
1. tab 从主窗口拖出后,生成独立窗口
|
||||
2. 独立窗口中的 tab 可以继续拖回主窗口
|
||||
3. 独立窗口之间可以继续相互 dock / 合并
|
||||
4. 现有单窗口 DockHost 布局与 panel 内容代码尽量保持复用
|
||||
|
||||
核心原则:
|
||||
|
||||
1. 不在现有 `UIEditorWorkspaceNodeKind` 里硬塞 `FloatingWindow`
|
||||
2. 保持“一棵 workspace 树只描述一个窗口内部的 dock 布局”
|
||||
3. 浮动窗口是宿主层与窗口集合层的概念,不是 dock 树节点概念
|
||||
4. 先把结构做对,再接拖拽与窗口生命周期
|
||||
|
||||
## 2. 当前根因
|
||||
|
||||
当前不能把 tab 拖成独立窗口,不是交互细节 bug,而是架构缺层。
|
||||
|
||||
现状如下:
|
||||
|
||||
1. `UIEditorWorkspaceModel` 只描述一棵窗口内 dock tree
|
||||
2. `UIEditorDockHostInteraction` 只支持:
|
||||
- `ReorderTab(...)`
|
||||
- `MoveTabToStack(...)`
|
||||
- `DockTabRelative(...)`
|
||||
3. 指针离开 dock host 以后,只会清空 `dropPreview`,不会生成新的宿主窗口实体
|
||||
4. `Application` / `ProductEditorWorkspace` / `ProductEditorContext` 当前都只服务一个主窗口实例
|
||||
|
||||
所以必须先补上“窗口集合 + 每窗口独立 shell 状态 + 跨窗口拖拽转移”这一层。
|
||||
|
||||
## 3. 设计原则
|
||||
|
||||
### 3.1 保留单窗口 workspace 模型
|
||||
|
||||
保留当前这条边界:
|
||||
|
||||
- `UIEditorWorkspaceModel`
|
||||
- `UIEditorWorkspaceController`
|
||||
- `UIEditorDockHost`
|
||||
- `UIEditorDockHostInteraction`
|
||||
|
||||
它们继续只处理“一个窗口内部”的 dock、split、tab、panel。
|
||||
|
||||
### 3.2 新增窗口集合层
|
||||
|
||||
新增一层更高的宿主模型,例如:
|
||||
|
||||
- `UIEditorWindowWorkspaceState`
|
||||
- `UIEditorWindowWorkspaceController`
|
||||
- `UIEditorWindowWorkspaceSet`
|
||||
|
||||
职责是:
|
||||
|
||||
1. 持有主窗口 workspace
|
||||
2. 持有多个 detached window workspace
|
||||
3. 管理跨窗口 tab 转移
|
||||
4. 管理 detached window 的创建、关闭、回收
|
||||
|
||||
### 3.3 拖拽是全局会话,不是单窗口局部状态
|
||||
|
||||
当前 tab 拖拽状态挂在单个 `UIEditorDockHostInteractionState` 里,这只适用于单窗口。
|
||||
|
||||
重构后要拆成两层:
|
||||
|
||||
1. 窗口内局部状态
|
||||
- tab strip hover / active / splitter drag
|
||||
2. 跨窗口全局拖拽状态
|
||||
- 正在拖哪个 panel
|
||||
- 来源窗口 id / 来源 node id
|
||||
- 当前鼠标屏幕坐标
|
||||
- 当前命中的目标窗口 / 目标 tab stack
|
||||
- 是否已经触发“脱离为新窗口”
|
||||
|
||||
### 3.4 panel 内容与业务状态不跟随 HWND 绑死
|
||||
|
||||
`Hierarchy / Inspector / Project / Console / Scene / Game` 的内容逻辑仍然由 editor 业务层统一提供。
|
||||
|
||||
窗口只负责:
|
||||
|
||||
1. 展示哪些 panel
|
||||
2. 当前 panel 在这个窗口里的 dock 关系
|
||||
3. 这个窗口自己的输入、hover、capture、draw data
|
||||
|
||||
## 4. 目标架构
|
||||
|
||||
## 4.1 数据层
|
||||
|
||||
新增建议:
|
||||
|
||||
- `new_editor/include/XCEditor/Shell/UIEditorWindowWorkspaceModel.h`
|
||||
- `new_editor/src/Shell/UIEditorWindowWorkspaceModel.cpp`
|
||||
|
||||
建议结构:
|
||||
|
||||
```cpp
|
||||
struct UIEditorWindowWorkspaceState {
|
||||
std::string windowId;
|
||||
UIEditorWorkspaceModel workspace;
|
||||
};
|
||||
|
||||
struct UIEditorWindowWorkspaceSet {
|
||||
std::string primaryWindowId;
|
||||
std::vector<UIEditorWindowWorkspaceState> windows;
|
||||
std::string activeWindowId;
|
||||
};
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
1. 每个窗口持有一份自己的 `UIEditorWorkspaceModel`
|
||||
2. 主窗口只是 `primaryWindowId`
|
||||
3. detached window 只是 `windows` 里的非主窗口项
|
||||
|
||||
## 4.2 控制层
|
||||
|
||||
新增建议:
|
||||
|
||||
- `new_editor/include/XCEditor/Shell/UIEditorWindowWorkspaceController.h`
|
||||
- `new_editor/src/Shell/UIEditorWindowWorkspaceController.cpp`
|
||||
|
||||
职责:
|
||||
|
||||
1. 创建 detached window workspace
|
||||
2. 销毁空窗口
|
||||
3. 把 panel 从源窗口移到目标窗口
|
||||
4. 把单 panel 初始化成新窗口根 tab stack
|
||||
5. 支持:
|
||||
- 同窗口重排
|
||||
- 跨窗口移入已有 stack
|
||||
- 跨窗口 dock relative
|
||||
- 拖出生成新窗口
|
||||
|
||||
这里不要复制已有 dock 逻辑,而是复用现有 `UIEditorWorkspaceController` 的布局变换能力。
|
||||
|
||||
## 4.3 交互层
|
||||
|
||||
新增建议:
|
||||
|
||||
- `new_editor/include/XCEditor/Shell/UIEditorWindowDragSession.h`
|
||||
- `new_editor/src/Shell/UIEditorWindowDragSession.cpp`
|
||||
|
||||
全局拖拽状态建议:
|
||||
|
||||
```cpp
|
||||
struct UIEditorWindowTabDragSession {
|
||||
bool active = false;
|
||||
std::string sourceWindowId;
|
||||
std::string sourceNodeId;
|
||||
std::string sourcePanelId;
|
||||
UIPoint screenPointerPosition = {};
|
||||
bool detachedWindowCreated = false;
|
||||
};
|
||||
```
|
||||
|
||||
规则:
|
||||
|
||||
1. 在某个窗口内开始 tab drag 时,建立全局 drag session
|
||||
2. 鼠标还在某个 dock host 内时,按原有 drop preview 逻辑走
|
||||
3. 鼠标离开所有窗口且超过脱离阈值时,创建新 detached window
|
||||
4. 新窗口创建后,把拖拽中的 panel 挂到这个窗口
|
||||
5. 后续拖拽继续以新窗口为目标窗口参与命中
|
||||
|
||||
## 4.4 宿主层
|
||||
|
||||
当前 `Application` 只对应一个 HWND,需要补成“主窗口 + detached 窗口宿主实例集合”。
|
||||
|
||||
建议新增:
|
||||
|
||||
- `new_editor/app/Host/EditorHostWindow.h`
|
||||
- `new_editor/app/Host/EditorHostWindow.cpp`
|
||||
- `new_editor/app/Host/EditorHostWindowManager.h`
|
||||
- `new_editor/app/Host/EditorHostWindowManager.cpp`
|
||||
|
||||
职责拆分:
|
||||
|
||||
### `EditorHostWindow`
|
||||
|
||||
负责单个 HWND:
|
||||
|
||||
1. Win32 消息
|
||||
2. 单窗口 render loop
|
||||
3. 单窗口 workspace bounds
|
||||
4. 单窗口 shell interaction / draw / cursor / capture
|
||||
|
||||
### `EditorHostWindowManager`
|
||||
|
||||
负责多窗口:
|
||||
|
||||
1. 创建主窗口
|
||||
2. 创建 detached window
|
||||
3. 维护 `windowId -> host window instance`
|
||||
4. 在窗口关闭时回收 state
|
||||
5. 协调全局 tab drag session
|
||||
|
||||
## 5. 执行阶段
|
||||
|
||||
## 阶段 A:先补窗口集合模型,不改宿主
|
||||
|
||||
### 目标
|
||||
|
||||
先把“一个窗口集合里有多棵 workspace”建立起来,但仍然只跑主窗口。
|
||||
|
||||
### 任务
|
||||
|
||||
1. 新增 `UIEditorWindowWorkspaceSet`
|
||||
2. 新增集合级 controller
|
||||
3. 实现:
|
||||
- `DetachPanelToNewWindow(...)`
|
||||
- `MovePanelBetweenWindowsToStack(...)`
|
||||
- `DockPanelBetweenWindowsRelative(...)`
|
||||
4. 给这些操作补基础单元测试
|
||||
|
||||
### 验收
|
||||
|
||||
1. 不开第二个 HWND,也能在纯数据层完成 panel 跨窗口迁移
|
||||
2. 源窗口 panel 被正确移除
|
||||
3. 目标窗口 root 布局正确生成
|
||||
|
||||
## 阶段 B:把单窗口宿主抽成可复用的 window instance
|
||||
|
||||
### 目标
|
||||
|
||||
把当前 `Application` 里只适用于单 HWND 的状态拆出来,为多窗口做准备。
|
||||
|
||||
### 任务
|
||||
|
||||
1. 提取单窗口运行时状态
|
||||
2. 提取单窗口 render/update/append/input 流程
|
||||
3. 让主窗口也走 `EditorHostWindow`
|
||||
|
||||
### 验收
|
||||
|
||||
1. 主窗口行为不回退
|
||||
2. 代码里不再默认“全局只有一个 workspace / 一个 shell state / 一个 hwnd”
|
||||
|
||||
## 阶段 C:接入 detached window 的 HWND 生命周期
|
||||
|
||||
### 目标
|
||||
|
||||
真正把第二个窗口创建出来,但先不接完整跨窗口拖拽。
|
||||
|
||||
### 任务
|
||||
|
||||
1. `EditorHostWindowManager` 支持创建第二个 `EditorHostWindow`
|
||||
2. detached window 拥有自己的:
|
||||
- HWND
|
||||
- render loop
|
||||
- interaction state
|
||||
- draw pass
|
||||
3. 空窗口关闭回收
|
||||
|
||||
### 验收
|
||||
|
||||
1. 可以通过代码直接创建一个带单 panel 的 detached window
|
||||
2. 该窗口可独立显示、移动、关闭
|
||||
|
||||
## 阶段 D:接入 tab 拖出创建 detached window
|
||||
|
||||
### 目标
|
||||
|
||||
把“拖出”真正打通。
|
||||
|
||||
### 任务
|
||||
|
||||
1. tab drag 启动时创建全局 drag session
|
||||
2. 当指针离开全部 dock host 且满足阈值时:
|
||||
- 从源窗口移除 panel
|
||||
- 创建 detached window model
|
||||
- 创建 detached HWND
|
||||
3. 新窗口初始位置跟随拖拽起点与屏幕坐标
|
||||
|
||||
### 验收
|
||||
|
||||
1. 从主窗口拖出任意 tab,可变成独立窗口
|
||||
2. 不是复制,是迁移
|
||||
3. 原窗口布局自动 canonicalize,不留下空 stack / 空 split
|
||||
|
||||
## 阶段 E:接入跨窗口 re-dock
|
||||
|
||||
### 目标
|
||||
|
||||
支持 detached window 和主窗口双向回 dock。
|
||||
|
||||
### 任务
|
||||
|
||||
1. 命中其他窗口 dock host 时生成目标窗口 drop preview
|
||||
2. pointer up 时执行跨窗口:
|
||||
- move to stack
|
||||
- dock relative
|
||||
3. 如果源窗口被拖空,自动关闭该 detached window
|
||||
|
||||
### 验收
|
||||
|
||||
1. detached -> main 可回 dock
|
||||
2. detached -> detached 可互相 dock
|
||||
3. 空窗口自动销毁,非空窗口保持
|
||||
|
||||
## 阶段 F:补交互与收口
|
||||
|
||||
### 目标
|
||||
|
||||
把功能补到可长期使用,不留明显交互破洞。
|
||||
|
||||
### 任务
|
||||
|
||||
1. 处理激活窗口切换
|
||||
2. 处理 capture / focus / cursor 所有权
|
||||
3. 处理窗口关闭时的 panel 回收策略
|
||||
4. 预留布局持久化结构
|
||||
|
||||
### 验收
|
||||
|
||||
1. 多窗口拖拽不闪退
|
||||
2. capture 不串窗口
|
||||
3. focus / active panel 行为稳定
|
||||
|
||||
## 6. 关键风险
|
||||
|
||||
### 6.1 不能让 panel 业务实例被窗口复制
|
||||
|
||||
如果直接复制 `ProductProjectPanel / ProductHierarchyPanel` 这类对象,很容易出现双状态漂移。
|
||||
|
||||
要先确认:
|
||||
|
||||
1. 哪些状态是全局业务状态
|
||||
2. 哪些状态是窗口内展示状态
|
||||
|
||||
### 6.2 指针捕获要统一到宿主管理层
|
||||
|
||||
当前 capture 大多按单窗口处理。多窗口后如果还各管各的,很容易出现:
|
||||
|
||||
1. 源窗口还认为自己在 drag
|
||||
2. 目标窗口已经开始 preview
|
||||
3. 鼠标松开后状态残留
|
||||
|
||||
所以 drag session 与 capture 仲裁必须提升到 window manager。
|
||||
|
||||
### 6.3 不能把跨窗口逻辑塞回 DockHostInteraction
|
||||
|
||||
`UIEditorDockHostInteraction` 继续只处理单窗口内部命中与 preview。
|
||||
|
||||
跨窗口逻辑应放在更上层,否则很快会变成屎山。
|
||||
|
||||
## 7. 本轮执行顺序
|
||||
|
||||
这一轮按下面顺序推进:
|
||||
|
||||
1. 阶段 A:补窗口集合模型与 controller
|
||||
2. 阶段 B:提取单窗口 host instance
|
||||
3. 阶段 C:先用代码路径创建 detached window,打通多 HWND
|
||||
4. 阶段 D:接 tab 拖出创建新窗口
|
||||
5. 阶段 E:接跨窗口 re-dock
|
||||
|
||||
## 8. 收口标准
|
||||
|
||||
满足以下条件,才算这次重构收口:
|
||||
|
||||
1. tab 可以从主窗口拖出成为独立窗口
|
||||
2. 独立窗口可以拖回主窗口
|
||||
3. 独立窗口之间可以继续 dock
|
||||
4. 不出现空窗口残留、空 stack 残留、拖拽状态残留
|
||||
5. 不破坏当前主窗口已有的 tab 重排 / split / dock 功能
|
||||
@@ -1,180 +0,0 @@
|
||||
# NewEditor 宿主重构计划
|
||||
|
||||
## 目标
|
||||
|
||||
把 `new_editor` 当前的窗口宿主从“功能可运行的过渡方案”收敛成可长期演进的 Editor 宿主架构,核心目标如下:
|
||||
|
||||
1. 主显示链最终统一到纯 D3D12。
|
||||
2. 窗口线程只负责消息和状态,不承担 GPU 重活。
|
||||
3. live resize 必须真实更新,但不能再走同步阻塞窗口线程的路径。
|
||||
4. Editor shell 和 Scene/Game viewport 统一纳入宿主合成层。
|
||||
5. 当前 `D3D11On12 + D2D` 只允许作为过渡路径,不能继续加深耦合。
|
||||
|
||||
## 当前问题
|
||||
|
||||
### 1. 宿主职责混在 `Application`
|
||||
|
||||
当前 `Application` 同时承担:
|
||||
|
||||
- Win32 消息调度
|
||||
- 宿主运行时状态
|
||||
- resize / dpi / deferred render 调度
|
||||
- editor 状态更新
|
||||
- present 前后的宿主控制
|
||||
|
||||
这会导致宿主问题难以单独定位和演进。
|
||||
|
||||
### 2. 主显示链过厚
|
||||
|
||||
当前主路径仍然依赖:
|
||||
|
||||
- D3D12 viewport 渲染
|
||||
- swapchain backbuffer
|
||||
- D3D11On12 wrapped resource
|
||||
- D2D 绘制 shell
|
||||
- present
|
||||
|
||||
这条链在 live resize、frame pacing、backbuffer 生命周期上都偏重。
|
||||
|
||||
### 3. resize 热路径仍然偏保守
|
||||
|
||||
虽然已经把 `WM_SIZE` 从直接同步 resize 调整为 deferred render 触发,但 resize 热路径里仍存在:
|
||||
|
||||
- backbuffer interop target 重建
|
||||
- swapchain resize
|
||||
- 资源生命周期收束
|
||||
|
||||
这还不是最终架构。
|
||||
|
||||
## 重构阶段
|
||||
|
||||
## 阶段 1:宿主分层
|
||||
|
||||
### 目标
|
||||
|
||||
先把结构理顺,停止继续把宿主逻辑堆进 `Application`。
|
||||
|
||||
### 任务
|
||||
|
||||
1. 拆出宿主运行时状态对象。
|
||||
2. 拆出窗口消息调度与 deferred render 调度。
|
||||
3. 让 `Application` 只保留 editor 业务更新与高层协作职责。
|
||||
4. 为后续 HostRenderer / HostCompositor 留清晰边界。
|
||||
|
||||
### 完成标准
|
||||
|
||||
1. resize / dpi / deferred render / interactive resize 状态不再散落在 `Application` 成员里。
|
||||
2. `Application` 的宿主状态字段明显减少。
|
||||
3. 现有功能与布局不回退。
|
||||
|
||||
## 阶段 2:建立 HostRenderer / HostCompositor 边界
|
||||
|
||||
### 目标
|
||||
|
||||
把宿主渲染拆成明确两层:
|
||||
|
||||
1. `HostRenderer`
|
||||
责任:device / queue / swapchain / backbuffer / fence / present
|
||||
2. `HostCompositor`
|
||||
责任:把 shell draw data、viewport texture、icon/text 统一合成到 backbuffer
|
||||
|
||||
### 任务
|
||||
|
||||
1. 停止让 `NativeRenderer` 既像窗口绘制器又像过渡 compositor。
|
||||
2. 把“主窗口显示”和“UI 绘制命令解释”职责显式拆开。
|
||||
3. 为纯 D3D12 compositor 做接口准备。
|
||||
|
||||
### 完成标准
|
||||
|
||||
1. `HostRenderer` 不依赖 D2D 语义。
|
||||
2. `HostCompositor` 成为唯一的宿主 UI 合成入口。
|
||||
3. 现有 `NativeRenderer` 明确退化为过渡层或 fallback。
|
||||
|
||||
## 阶段 3:主显示链切换到纯 D3D12
|
||||
|
||||
### 目标
|
||||
|
||||
去掉 `D3D11On12 + D2D` 在主显示链中的核心地位。
|
||||
|
||||
### 任务
|
||||
|
||||
1. shell 矩形、线条、图像、文字统一进入 D3D12 UI compositor。
|
||||
2. Scene/Game viewport 作为普通 SRV 输入参与同一条 compositor pass。
|
||||
3. backbuffer 只通过 D3D12 呈现。
|
||||
|
||||
### 完成标准
|
||||
|
||||
1. 主窗口显示不再依赖 D2D。
|
||||
2. resize 时不再重建 D3D11On12 backbuffer interop target。
|
||||
3. `new_editor` 主显示链可在没有 D3D11On12 的条件下工作。
|
||||
|
||||
## 阶段 4:重写 resize 状态机
|
||||
|
||||
### 目标
|
||||
|
||||
做到真实 live resize,但不阻塞窗口线程。
|
||||
|
||||
### 任务
|
||||
|
||||
1. `WM_SIZE` 只更新最新目标尺寸。
|
||||
2. render tick 只消费最新尺寸,不处理过期尺寸。
|
||||
3. resize 不允许在消息处理里做 GPU 等待。
|
||||
4. resize / present / viewport surface 生命周期统一到宿主状态机。
|
||||
|
||||
### 完成标准
|
||||
|
||||
1. 拖动窗口边界时不黑屏。
|
||||
2. 不出现黑白垃圾区。
|
||||
3. 窗口拖动体感明显优于当前实现。
|
||||
|
||||
## 阶段 5:去掉 resize 路径里的全队列等待
|
||||
|
||||
### 目标
|
||||
|
||||
去掉当前最重的同步点。
|
||||
|
||||
### 任务
|
||||
|
||||
1. 改成 per-backbuffer / per-frame 生命周期管理。
|
||||
2. 只等待必须退休的资源代际。
|
||||
3. 禁止 resize 路径里的整队列 idle 等待。
|
||||
|
||||
### 完成标准
|
||||
|
||||
1. resize 期间 CPU/GPU 同步明显减少。
|
||||
2. live resize 手感继续改善。
|
||||
|
||||
## 阶段 6:viewport 生命周期收口
|
||||
|
||||
### 目标
|
||||
|
||||
让 Scene/Game viewport 与外层宿主真正解耦。
|
||||
|
||||
### 任务
|
||||
|
||||
1. viewport render target 长期存活,不跟着宿主链大拆大建。
|
||||
2. 宿主 compositor 只采样 viewport 结果,不干预其内部资源生命周期。
|
||||
3. Scene/Game 在 interactive resize 期间保持稳定。
|
||||
|
||||
### 完成标准
|
||||
|
||||
1. viewport 不再因宿主 resize 逻辑出现黑屏或闪烁。
|
||||
2. 宿主和 viewport 各自职责明确。
|
||||
|
||||
## 执行顺序
|
||||
|
||||
1. 先完成阶段 1。
|
||||
2. 然后搭好阶段 2 的 HostRenderer / HostCompositor 边界。
|
||||
3. 再推进阶段 3,切主显示链到纯 D3D12。
|
||||
4. 最后做阶段 4、5、6 的性能与生命周期收口。
|
||||
|
||||
## 当前落点
|
||||
|
||||
当前阶段 1 已完成,阶段 2 已开始收口:
|
||||
|
||||
1. 已新增 `HostRuntimeState`,把宿主 DPI / interactive resize / pending resize / deferred render 状态从 `Application` 中抽离。
|
||||
2. 已新增 `WindowMessageDispatcher`,把 `WndProc` 中的宿主消息调度与 deferred render 调度拆到 `Host` 层。
|
||||
3. 已把 `D3D12WindowRenderLoop` 从悬空 helper 升级为主窗口帧编排入口,开始统一 `BeginFrame / viewport render / UI present / fallback / resize interop` 这条链。
|
||||
4. 已把 viewport render target 资源工厂从 `ProductViewportRenderTargets.h` 收成独立 manager,`ProductViewportHostService` 只保留请求/返回 frame 的业务外壳。
|
||||
5. 已把 shader resource descriptor 分配职责从 `D3D12WindowRenderer` 抽到独立的 `D3D12ShaderResourceDescriptorAllocator`,减少窗口呈现器的非 swapchain 职责。
|
||||
6. 下一步进入阶段 2 主体:继续拆 `NativeRenderer` 中的窗口互操作 / present 组合路径,把 D2D UI 光栅化与 D3D11On12 窗口合成进一步分离。
|
||||
@@ -1,283 +0,0 @@
|
||||
# NewEditor 方案1无边框宿主采用计划
|
||||
|
||||
日期: `2026-04-14`
|
||||
|
||||
## 1. 目标
|
||||
|
||||
把 `new_editor` 从当前的原生 `WS_OVERLAPPEDWINDOW + DWM + HWND swapchain` 宿主模式,重构为:
|
||||
|
||||
- 无边框顶层窗口
|
||||
- 自绘标题栏与边框
|
||||
- 应用自己接管 move / resize / maximize / restore / hit-test
|
||||
- 宿主渲染链与窗口尺寸变化由同一套状态机驱动
|
||||
|
||||
核心目的只有一个:
|
||||
|
||||
尽可能消除当前原生窗口 live resize 期间那种“旧帧被系统先拉伸,再等新帧补上”的视觉变形。
|
||||
|
||||
## 2. 为什么必须走这条路
|
||||
|
||||
当前路径的问题不是 XCUI 布局树本身,而是宿主显示链顺序决定的:
|
||||
|
||||
1. Windows 先改变原生窗口外框尺寸。
|
||||
2. DWM 立即需要一张图去填新窗口区域。
|
||||
3. `new_editor` 再收到 `WM_SIZE`,之后才开始:
|
||||
- `ResizeBuffers`
|
||||
- backbuffer / interop target 处理
|
||||
- UI + viewport 合成
|
||||
- `Present`
|
||||
4. 这中间只要慢一个 compositor tick,就会看到旧尺寸帧被拉伸。
|
||||
|
||||
只要继续使用原生 non-client resize,这个问题就只能减轻,不能彻底归零。
|
||||
|
||||
## 3. 方案1的总思路
|
||||
|
||||
不要再让系统驱动 resize 交互。
|
||||
|
||||
改为:
|
||||
|
||||
1. 窗口本身使用无边框样式。
|
||||
2. 顶部标题栏、拖动区、8 个 resize grip 全部放到 client area。
|
||||
3. 鼠标拖动边界时,不进入系统的 `WM_ENTERSIZEMOVE` 模态循环。
|
||||
4. 应用自己维护一套 `WindowFrameController`:
|
||||
- 记录拖动起点
|
||||
- 计算目标外框矩形
|
||||
- 先驱动宿主渲染链切到目标尺寸
|
||||
- 再提交窗口矩形变化与新帧 present
|
||||
|
||||
这样窗口尺寸变化、swapchain 尺寸变化、UI 布局变化、present 节奏都由应用自己掌控,而不是被 Windows 原生外框拆成两段。
|
||||
|
||||
## 4. 重构边界
|
||||
|
||||
这次重构只动 `new_editor/app/Host` 宿主层,不把业务逻辑塞进去。
|
||||
|
||||
### 4.1 保留不动的层
|
||||
|
||||
- `XCEditor` 基础 UI 组件层
|
||||
- `new_editor/app/Workspace`
|
||||
- `new_editor/app/Panels`
|
||||
- `Viewport` 业务层
|
||||
|
||||
### 4.2 主要改造层
|
||||
|
||||
- [Application.cpp](D:/Xuanchi/Main/XCEngine/new_editor/app/Application.cpp)
|
||||
- [Application.h](D:/Xuanchi/Main/XCEngine/new_editor/app/Application.h)
|
||||
- [WindowMessageDispatcher.cpp](D:/Xuanchi/Main/XCEngine/new_editor/app/Host/WindowMessageDispatcher.cpp)
|
||||
- [WindowMessageDispatcher.h](D:/Xuanchi/Main/XCEngine/new_editor/app/Host/WindowMessageDispatcher.h)
|
||||
- [HostRuntimeState.h](D:/Xuanchi/Main/XCEngine/new_editor/app/Host/HostRuntimeState.h)
|
||||
- [D3D12WindowRenderLoop.cpp](D:/Xuanchi/Main/XCEngine/new_editor/app/Host/D3D12WindowRenderLoop.cpp)
|
||||
- [D3D12WindowRenderer.cpp](D:/Xuanchi/Main/XCEngine/new_editor/app/Host/D3D12WindowRenderer.cpp)
|
||||
- [D3D12WindowSwapChainPresenter.cpp](D:/Xuanchi/Main/XCEngine/new_editor/app/Host/D3D12WindowSwapChainPresenter.cpp)
|
||||
|
||||
### 4.3 新增宿主对象
|
||||
|
||||
建议新增以下文件:
|
||||
|
||||
- `new_editor/app/Host/WindowFrameMetrics.h`
|
||||
- `new_editor/app/Host/WindowFrameController.h`
|
||||
- `new_editor/app/Host/WindowFrameController.cpp`
|
||||
- `new_editor/app/Host/WindowFrameInteractionState.h`
|
||||
- `new_editor/app/Host/BorderlessWindowStyle.h`
|
||||
|
||||
职责划分:
|
||||
|
||||
- `WindowFrameMetrics`
|
||||
- 统一管理标题栏高度、resize 边缘厚度、阴影扩展、caption button 区域
|
||||
- `WindowFrameInteractionState`
|
||||
- 记录当前是否在 move / resize
|
||||
- 记录激活边、起始窗口矩形、起始鼠标屏幕坐标
|
||||
- `WindowFrameController`
|
||||
- 处理 hit-test、开始拖动、更新拖动、结束拖动
|
||||
- 计算目标窗口矩形
|
||||
- 输出“本帧宿主需要切到什么尺寸”
|
||||
- `BorderlessWindowStyle`
|
||||
- 集中处理 `WS_POPUP / WS_THICKFRAME / WS_CAPTION` 等样式组合与 DWM 扩展
|
||||
|
||||
## 5. 分阶段执行
|
||||
|
||||
## 阶段 A:把窗口宿主从原生外框切到无边框
|
||||
|
||||
### 目标
|
||||
|
||||
先完成“视觉上还是一个正常窗口,但 non-client 已经不再由系统绘制”。
|
||||
|
||||
### 任务
|
||||
|
||||
1. 创建窗口时移除 `WS_OVERLAPPEDWINDOW`,改为适合无边框的样式组合。
|
||||
2. 顶部工具栏正式承担标题栏职责。
|
||||
3. 处理:
|
||||
- 最小化
|
||||
- 最大化
|
||||
- 还原
|
||||
- 关闭
|
||||
4. 保留 Windows 阴影、任务栏行为、Alt+Tab 行为。
|
||||
|
||||
### 验收
|
||||
|
||||
1. 窗口外框由 XCUI 自己绘制。
|
||||
2. 顶部区域可拖动移动窗口。
|
||||
3. 基本窗口控制按钮可用。
|
||||
|
||||
## 阶段 B:接管 hit-test 与 8 向 resize 手势
|
||||
|
||||
### 目标
|
||||
|
||||
不再依赖系统 non-client resize。
|
||||
|
||||
### 任务
|
||||
|
||||
1. 在 client area 内定义:
|
||||
- 左 / 右 / 上 / 下
|
||||
- 左上 / 右上 / 左下 / 右下
|
||||
的 resize 热区。
|
||||
2. 鼠标 hover 时稳定切换对应 cursor。
|
||||
3. 鼠标按下后进入 `WindowFrameInteractionState`。
|
||||
4. 鼠标移动时由 `WindowFrameController` 计算目标外框矩形。
|
||||
|
||||
### 验收
|
||||
|
||||
1. 8 个方向 resize 都能工作。
|
||||
2. cursor 不闪烁。
|
||||
3. 不再进入 `WM_ENTERSIZEMOVE / WM_EXITSIZEMOVE` 原生模态链。
|
||||
|
||||
## 阶段 C:把窗口尺寸变化改成“应用驱动”
|
||||
|
||||
### 目标
|
||||
|
||||
让窗口矩形变化和新尺寸帧提交进入同一条应用控制链。
|
||||
|
||||
### 任务
|
||||
|
||||
1. 取消当前“完全依赖 `WM_SIZE` 才处理 resize”的模式。
|
||||
2. 鼠标拖动过程中,先由 `WindowFrameController` 产出目标 client size。
|
||||
3. 宿主渲染层按目标 size:
|
||||
- resize swapchain
|
||||
- rebuild backbuffer view
|
||||
- 重新布局 UI
|
||||
- render + present
|
||||
4. 然后再提交窗口矩形更新。
|
||||
|
||||
这里的关键不是“永远先后顺序绝对固定”,而是宿主要从“被动响应 Windows resize”改成“主动推进目标尺寸帧”。
|
||||
|
||||
### 验收
|
||||
|
||||
1. live resize 期间不再有明显的整窗拉伸。
|
||||
2. 内部 UI 不再跟随旧帧一起被整体放大缩小。
|
||||
3. resize 时不黑屏、不闪退。
|
||||
|
||||
## 阶段 D:把 Scene / Game viewport 也纳入同一节奏
|
||||
|
||||
### 目标
|
||||
|
||||
避免窗口外层尺寸变化和 viewport target 更新脱节。
|
||||
|
||||
### 任务
|
||||
|
||||
1. 宿主 resize 状态机输出统一尺寸变更事件。
|
||||
2. `ProductViewportHostService` 消费同一目标尺寸。
|
||||
3. viewport render target 与 host swapchain 的 resize 节奏统一。
|
||||
|
||||
### 验收
|
||||
|
||||
1. 调外层窗口尺寸时,Scene / Game 内部画布不再滞后。
|
||||
2. 不再出现外层变了、内部蓝底画布慢一拍才追上的情况。
|
||||
|
||||
## 阶段 E:补齐无边框窗口的系统行为
|
||||
|
||||
### 目标
|
||||
|
||||
把“能用”补到“能长期替代正式编辑器宿主”。
|
||||
|
||||
### 任务
|
||||
|
||||
1. 双击标题栏最大化 / 还原。
|
||||
2. 拖到屏幕顶部最大化。
|
||||
3. 屏幕边缘吸附。
|
||||
4. 多显示器 DPI / work area 正确处理。
|
||||
5. 最小窗口尺寸约束。
|
||||
6. 系统菜单与快捷键兼容。
|
||||
|
||||
### 验收
|
||||
|
||||
1. 宿主交互接近常规桌面应用。
|
||||
2. 不因无边框而丢失基本桌面体验。
|
||||
|
||||
## 6. 架构原则
|
||||
|
||||
### 6.1 不允许把窗口交互逻辑混回 `Application`
|
||||
|
||||
`Application` 只能做:
|
||||
|
||||
- 应用生命周期
|
||||
- 编辑器业务装配
|
||||
- 驱动一帧更新与渲染
|
||||
|
||||
窗口移动、边框 hit-test、resize 手势状态机都必须沉淀到 `Host`。
|
||||
|
||||
### 6.2 不允许为了“先跑通”堆事件补丁
|
||||
|
||||
禁止继续沿这些方向堆补丁:
|
||||
|
||||
- `WM_SIZE` 后疯狂补 render
|
||||
- `ValidateRect` / `InvalidateRect` 来回试
|
||||
- `DwmFlush` 之类的消息尾部补丁
|
||||
- 在 resize 过程中乱加全局 GPU idle
|
||||
|
||||
这些都只能缓解,不能把宿主控制权拿回来。
|
||||
|
||||
### 6.3 宿主渲染链必须单向清晰
|
||||
|
||||
目标链路必须收敛成:
|
||||
|
||||
`WindowFrameController -> Host resize state -> swapchain/backbuffer resize -> UI + viewport compose -> present`
|
||||
|
||||
而不是:
|
||||
|
||||
`Windows non-client -> WM_SIZE -> 若干临时补丁 -> 侥幸赶上 compositor`
|
||||
|
||||
## 7. 风险点
|
||||
|
||||
### 7.1 这不是小修
|
||||
|
||||
这是宿主交互模型切换,不是单点 bugfix。
|
||||
|
||||
### 7.2 需要额外补齐桌面窗口语义
|
||||
|
||||
无边框之后,很多系统行为都要自己接:
|
||||
|
||||
- caption drag
|
||||
- 双击最大化
|
||||
- hit-test
|
||||
- snap
|
||||
- monitor work area
|
||||
- DPI 变更
|
||||
|
||||
### 7.3 需要严格做阶段验收
|
||||
|
||||
每一阶段都必须编译并人工验证,不然很容易把宿主架构搞乱。
|
||||
|
||||
## 8. 推荐执行顺序
|
||||
|
||||
1. 阶段 A:无边框窗口切换
|
||||
2. 阶段 B:hit-test / resize 手势
|
||||
3. 阶段 C:应用驱动 resize 主链
|
||||
4. 阶段 D:viewport resize 节奏统一
|
||||
5. 阶段 E:补系统级桌面行为
|
||||
|
||||
## 9. 收口标准
|
||||
|
||||
满足以下条件,才算方案1真正落地:
|
||||
|
||||
1. `new_editor` 已彻底脱离原生 non-client resize。
|
||||
2. 窗口拖边 resize 时,整窗拉伸变形基本消失。
|
||||
3. Scene / Game viewport 尺寸变化与外层窗口同步。
|
||||
4. resize 过程中无黑屏、无崩溃、无 cursor 闪烁。
|
||||
5. 顶部标题栏、最大化、吸附、DPI 行为达到正式编辑器可用水平。
|
||||
|
||||
## 10. 结论
|
||||
|
||||
如果目标是“尽可能彻底消除 resize 变形”,就不该继续在当前原生外框链路上修修补补。
|
||||
|
||||
正确主线是:
|
||||
|
||||
把 `new_editor` 宿主改成无边框、自管标题栏、自管 resize、自管 present 节奏的 editor shell。
|
||||
@@ -1,600 +0,0 @@
|
||||
# NewEditor 对标旧 Editor 迁移重建计划
|
||||
|
||||
日期: `2026-04-12`
|
||||
|
||||
## 1. 文档定位
|
||||
|
||||
这份计划用于正式切换主线:
|
||||
|
||||
- 旧 `editor/` 继续作为参考实现与行为基线。
|
||||
- `new_editor/` 从“XCEditor 基础层试验宿主”升级为“新编辑器正式重建宿主”。
|
||||
- 后续工作重点不再是单独补 `XCEditor` 的孤立控件,而是参考旧 `editor/`,在 `new_editor/` 内逐步重建完整编辑器应用。
|
||||
|
||||
但有一个硬约束必须始终遵守:
|
||||
|
||||
- 如果在重建 `new_editor` 的过程中暴露出 `XCEditor`、宿主层或输入/布局/viewport 基础设施的结构问题,必须先回到底层修根因,再继续往上迁移。
|
||||
- 不允许在 `new_editor` 业务层堆临时兼容逻辑来掩盖底层问题。
|
||||
|
||||
这份计划替代此前“先单独收口 dock/UI 基础层,再暂停业务”的阶段性计划。当前主线已经进入 `new_editor` 正式重建阶段。
|
||||
|
||||
## 2. 不可违背的设计原则
|
||||
|
||||
### 2.1 根因优先
|
||||
|
||||
- 任何交互、布局、DPI、capture、拖拽、文本测量、渲染清晰度问题,优先在 `XCEditor` / `Host` / shared editor infrastructure 修。
|
||||
- 禁止在某个 panel 内写只为绕过去的局部 hack。
|
||||
|
||||
### 2.2 旧 Editor 是参考基线,不是直接复制目标
|
||||
|
||||
- 旧 `editor/` 的行为、工作流、信息架构、可用性和视觉结果是当前最可靠的参考。
|
||||
- 旧 `editor/` 里凡是 ImGui 特有的壳代码、临时 helper、历史包袱,不应机械照搬。
|
||||
- 迁移过程中允许顺手做架构收敛,但必须保持行为兼容,不允许一边“优化”一边偏离旧版交互。
|
||||
|
||||
### 2.3 `XCEditor` 只承载 Editor UI 基础层,不承载 Editor 业务
|
||||
|
||||
- `new_editor/include/XCEditor/**` + `new_editor/src/**` 负责 editor-only 的 UI primitive、shell、dock、field、tree/list、menu、viewport slot、workspace 等基础能力。
|
||||
- `new_editor` 的正式编辑器业务必须放在应用层,不得继续把业务逻辑塞回 `XCEditor` 库层。
|
||||
|
||||
### 2.4 Editor 样式固定写死在代码里
|
||||
|
||||
- `Runtime UI` 保留资源化/主题化能力,服务游戏开发者。
|
||||
- `Editor UI` 当前不走资源驱动主线,样式、palette、metrics、chrome 由代码固定维护。
|
||||
- 不再给 `Editor UI` 扩一套厚重的主题资源解释系统。
|
||||
|
||||
### 2.5 测试体系与产品宿主分离
|
||||
|
||||
- `tests/UI/Core|Runtime|Editor` 继续作为 UI 模块验证入口。
|
||||
- `new_editor/` 是产品宿主,不是测试场景堆放区。
|
||||
- 某项能力先在对应层的 `tests/UI` 里做 unit/integration 回归,再接入 `new_editor`。
|
||||
|
||||
## 3. 当前基线判断
|
||||
|
||||
## 3.1 已经完成并可复用的部分
|
||||
|
||||
当前 `new_editor` 已经具备一套可继续向上承接的 Editor UI 基础层:
|
||||
|
||||
- `XCEditor` 库层已经有:
|
||||
- `Fields`
|
||||
- `Tree/List/Scroll/TabStrip`
|
||||
- `MenuBar/MenuPopup/StatusBar`
|
||||
- `DockHost/Workspace/PanelHost`
|
||||
- `ViewportSlot/ViewportShell`
|
||||
- shortcut、command registry、workspace persistence
|
||||
- `Host` 层已经有:
|
||||
- Win32 宿主
|
||||
- Direct2D/DirectWrite 文本与图像绘制
|
||||
- DPI 感知
|
||||
- 自动截图
|
||||
- 自有 exe 截图输出
|
||||
- `new_editor` 当前已经验证过:
|
||||
- Unity 风格的基础 chrome
|
||||
- tab 拖拽重排与停靠
|
||||
- project 左树与右侧浏览器的基础外壳
|
||||
- hierarchy / project 图标与文本对齐
|
||||
- 多项 `tests/UI/Editor` unit / integration 回归
|
||||
|
||||
结论:
|
||||
|
||||
- `XCEditor` 不再是“完全不能承接产品”的状态。
|
||||
- 当前真正缺的不是几个零散 widget,而是 `new_editor` 应用层本身还没有长成旧 `editor/` 那样完整的编辑器架构。
|
||||
|
||||
## 3.2 当前仍然缺失的关键能力
|
||||
|
||||
距离“可以真正替代旧 `editor/` 开始长期迭代”的状态,当前还缺:
|
||||
|
||||
1. `new_editor` 自己的应用层骨架还不完整。
|
||||
2. 缺少类似旧 `editor/src/Core + Managers + Actions + Commands + Panels + Viewport + ComponentEditors + Scripting` 的正式分层。
|
||||
3. `Hierarchy` 仍是 demo/static 数据,不是场景真实数据。
|
||||
4. `Project` 虽然外壳已成型,但还不是旧 editor 的完整资产工作流。
|
||||
5. `Inspector` 及 `ComponentEditorRegistry` 体系尚未接回。
|
||||
6. `Console` 与日志桥接尚未接回。
|
||||
7. `Scene/Game viewport` 还没有接回旧 editor 的真实渲染/交互主链。
|
||||
8. project / scene / undo / selection / action route / runtime mode 这些编辑器全局状态在 `new_editor` 里还没有正式 owner。
|
||||
9. 脚本、运行模式、保存/打开、项目切换、Library/Asset 流程都还未接回。
|
||||
|
||||
## 4. 旧 Editor 与 NewEditor 的真实差距
|
||||
|
||||
## 4.1 旧 Editor 的实际分层
|
||||
|
||||
旧 `editor/` 当前已经形成的主干是:
|
||||
|
||||
`Application -> EditorLayer -> EditorWorkspace -> Panels/Viewport -> Actions -> Commands -> Managers/Core`
|
||||
|
||||
横向还包含:
|
||||
|
||||
- `UI`
|
||||
- `ComponentEditors`
|
||||
- `Layout`
|
||||
- `Scripting`
|
||||
- `Platform`
|
||||
|
||||
这意味着旧 editor 已经不是“只有一堆 panel”,而是一套完整的编辑器应用结构。
|
||||
|
||||
## 4.2 NewEditor 当前的真实分层
|
||||
|
||||
`new_editor/` 当前更接近:
|
||||
|
||||
`Application + Host + XCEditorLib + 少量 Product 面板`
|
||||
|
||||
其中:
|
||||
|
||||
- `include/XCEditor/**` + `src/**` 是 Editor UI 库层。
|
||||
- `Host/**` 是平台与绘制宿主。
|
||||
- `app/**` 目前还只是轻量应用壳与少量试制 panel。
|
||||
|
||||
缺口在于:
|
||||
|
||||
- 旧 editor 的“应用层中间层”几乎还没完整迁过来。
|
||||
- 当前 `new_editor` 的 panel 仍然偏 prototype,不是正式产品模块。
|
||||
|
||||
## 4.3 模块映射与结论
|
||||
|
||||
| 旧 editor 模块 | 当前状态 | new_editor 目标落点 |
|
||||
| --- | --- | --- |
|
||||
| `editor/src/UI/**` | 大部分语义已被 `XCEditor` 吸收 | 继续沉淀在 `include/XCEditor/**` + `src/**` |
|
||||
| `editor/src/Layout/**` | 旧版依赖 ImGui docking | 由 `XCEditor/Shell/**` 的 workspace/dock host 接替 |
|
||||
| `editor/src/Application.*` | 旧版完整 | `new_editor` 应保留为宿主壳,避免塞业务 |
|
||||
| `editor/src/Core/**` | 旧版完整 | `new_editor` 需要建立对应 app-level Core |
|
||||
| `editor/src/Managers/**` | 旧版完整 | `new_editor` 需要建立对应 app-level Managers |
|
||||
| `editor/src/Actions/**` | 旧版完整 | `new_editor` 需要正式迁入 |
|
||||
| `editor/src/Commands/**` | 旧版完整 | `new_editor` 需要正式迁入 |
|
||||
| `editor/src/panels/**` | 旧版完整 | `new_editor` 需要按新 shell 重写,但行为对齐旧版 |
|
||||
| `editor/src/ComponentEditors/**` | 旧版完整 | `new_editor` 需要迁入并适配 `XCEditor` property grid/field |
|
||||
| `editor/src/Viewport/**` | 旧版完整 | `new_editor` 需要重新桥接到 `XCEditor` viewport slot/shell |
|
||||
| `editor/src/Scripting/**` | 旧版完整 | `new_editor` 后期需要接回 |
|
||||
|
||||
结论:
|
||||
|
||||
- `XCEditor` 已经覆盖了大量旧 `editor/src/UI/**` 与 `Layout` 的职责。
|
||||
- 但 `new_editor` 还没有真正补上旧 editor 的应用层与工作流层。
|
||||
- 因此接下来的重点不是“继续造更多基础控件”,而是“用旧 editor 的结构和行为为参照,把新 editor 的应用层补齐”。
|
||||
|
||||
## 5. 迁移总策略
|
||||
|
||||
迁移策略固定为两条线并行推进:
|
||||
|
||||
### 5.1 主线:重建 NewEditor 应用层
|
||||
|
||||
- 以旧 `editor/` 为参考,在 `new_editor` 下逐步建立正式的:
|
||||
- `Core`
|
||||
- `Managers`
|
||||
- `Actions`
|
||||
- `Commands`
|
||||
- `Panels`
|
||||
- `Viewport`
|
||||
- `ComponentEditors`
|
||||
- `Scripting`
|
||||
|
||||
### 5.2 副线:按需回补 XCEditor / Host
|
||||
|
||||
- 当主线重建暴露底层能力缺口时,再回补:
|
||||
- `XCEditor`
|
||||
- `Host`
|
||||
- `tests/UI/Editor`
|
||||
|
||||
副线只为解决主线遇到的真实阻塞,不再无边界扩 editor-only widget。
|
||||
|
||||
## 6. 目标架构
|
||||
|
||||
## 6.1 `XCEditor` 的职责边界
|
||||
|
||||
保留在库层的内容:
|
||||
|
||||
- fixed-code editor theme / metrics / palette
|
||||
- menu / popup / dock / workspace / tab strip
|
||||
- tree / list / scroll / inline rename / property grid / fields
|
||||
- viewport slot / viewport shell
|
||||
- editor UI input model、session、interaction state machine
|
||||
|
||||
不放进库层的内容:
|
||||
|
||||
- project 资产语义
|
||||
- scene/entity/component 语义
|
||||
- console/log bridge
|
||||
- project/scene open/save 工作流
|
||||
- inspector 组件注册表
|
||||
- editor 菜单业务动作
|
||||
|
||||
## 6.2 `new_editor` 应用层目标结构
|
||||
|
||||
应用层建议逐步收敛到与旧 `editor/src` 接近的形态:
|
||||
|
||||
```text
|
||||
new_editor/
|
||||
Host/
|
||||
include/XCEditor/
|
||||
src/
|
||||
Core/
|
||||
Managers/
|
||||
Actions/
|
||||
Commands/
|
||||
Panels/
|
||||
Viewport/
|
||||
ComponentEditors/
|
||||
Scripting/
|
||||
Shell/
|
||||
Icons/
|
||||
Application/
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `include/XCEditor/**` + `src/**` 中的库层文件继续保留并演进。
|
||||
- `new_editor` 的产品应用代码不应长期散落在轻量 `app/*` 原型目录里。
|
||||
- 迁移早期可以暂时复用现有 `app/*`,但必须尽快收敛到正式应用层目录,避免“基础层代码”和“产品层代码”混杂。
|
||||
|
||||
## 7. 分阶段执行计划
|
||||
|
||||
## Phase 0:文档与目录主线切换
|
||||
|
||||
### 目标
|
||||
|
||||
把主线明确切到 `new_editor` 正式重建,清理过期计划入口。
|
||||
|
||||
### 任务
|
||||
|
||||
- 归档旧的阶段性 dock 收口计划。
|
||||
- 保留 `Editor架构说明.md` 作为旧 editor 参考文档,不归档。
|
||||
- 新建本迁移计划,作为当前唯一 editor 重建主线。
|
||||
- 在计划中正式写死:
|
||||
- `old editor = reference`
|
||||
- `new_editor = product host`
|
||||
- `XCEditor = editor ui library`
|
||||
- `tests/UI = module verification entry`
|
||||
|
||||
### 完成标准
|
||||
|
||||
- 后续不再以旧 dock 收口计划作为主线驱动文档。
|
||||
|
||||
## Phase 1:收敛 NewEditor 应用层骨架
|
||||
|
||||
### 目标
|
||||
|
||||
先把 `new_editor` 从“壳 + 若干 product panel”收敛成“真正的编辑器应用结构”。
|
||||
|
||||
### 任务
|
||||
|
||||
- 建立 `new_editor` 自己的应用层目录与命名边界。
|
||||
- 提炼 `Application` 的纯宿主职责:
|
||||
- window / DPI / renderer / input pump / screenshot / main loop
|
||||
- 建立 `EditorWorkspace` 式的应用装配层:
|
||||
- panel registry
|
||||
- workspace compose
|
||||
- panel attach/detach/update/render
|
||||
- 建立 `EditorContext` / `IEditorContext` 式的全局状态容器。
|
||||
- 定义新 editor 的状态所有权:
|
||||
- selection owner
|
||||
- scene owner
|
||||
- project owner
|
||||
- undo owner
|
||||
- active action route owner
|
||||
- runtime mode owner
|
||||
|
||||
### 根因要求
|
||||
|
||||
- 不允许继续让 `Application` 直接知道越来越多 project/hierarchy 细节。
|
||||
- 任何产品语义都必须逐步从 `Application` 下沉到 context / managers / panels。
|
||||
|
||||
### 完成标准
|
||||
|
||||
- `new_editor` 具备清晰的 app-level `Core/Workspace/Panels` 骨架。
|
||||
- 现有 `ProductHierarchyPanel` / `ProductProjectPanel` 不再是孤立 demo 对象,而是正式 panel 接口的一部分。
|
||||
|
||||
## Phase 2:迁入全局动作路由与命令层
|
||||
|
||||
### 目标
|
||||
|
||||
把旧 editor 的 “menu / shortcut / context menu / toolbar -> action/router -> command” 主链迁进来。
|
||||
|
||||
### 任务
|
||||
|
||||
- 对照旧 `editor/src/Actions/**` 梳理新 editor 的动作集:
|
||||
- `File`
|
||||
- `Edit`
|
||||
- `Assets`
|
||||
- `Run`
|
||||
- `Scripts`
|
||||
- `View`
|
||||
- `Help`
|
||||
- 建立新的 action route 机制:
|
||||
- global actions
|
||||
- focused panel actions
|
||||
- active route dispatch
|
||||
- 将真正修改数据的行为放入 `Commands/**`。
|
||||
- 让菜单、快捷键、右键菜单、toolbar 共享同一套动作定义。
|
||||
|
||||
### 根因要求
|
||||
|
||||
- 不允许 menu、shortcut、context menu 各自复制一套业务逻辑。
|
||||
- 不允许 panel 直接偷偷修改 scene/project 状态绕开 command。
|
||||
|
||||
### 完成标准
|
||||
|
||||
- 所有 editor 主动作都有稳定 owner。
|
||||
- UI 入口与业务执行不再混杂。
|
||||
|
||||
## Phase 3:接回 Hierarchy 正式数据模型
|
||||
|
||||
### 目标
|
||||
|
||||
把 `Hierarchy` 从 demo tree 改成真实 scene-backed 面板。
|
||||
|
||||
### 任务
|
||||
|
||||
- 用真实场景层级替换当前静态 `m_treeItems`。
|
||||
- 建立 hierarchy 展平与增量同步路径。
|
||||
- 接回 selection 同步。
|
||||
- 接回 rename。
|
||||
- 接回 create/delete/duplicate。
|
||||
- 接回拖拽 reparent:
|
||||
- drop on entity => 成为子节点
|
||||
- drop on empty area => 回到 root
|
||||
- 接回 context menu。
|
||||
- 接回旧 editor 的层级树图标/展开/焦点/多选策略。
|
||||
|
||||
### 优先参考文件
|
||||
|
||||
- `editor/src/panels/HierarchyPanel.*`
|
||||
- `editor/src/Actions/HierarchyActionRouter.h`
|
||||
- `editor/src/Commands/EntityCommands.h`
|
||||
- `editor/src/Managers/SceneManager.*`
|
||||
|
||||
### 根因要求
|
||||
|
||||
- 先建立可变 hierarchy source model,再做拖拽。
|
||||
- 如拖拽/capture 冲突,需要在 shared hosted-content capture 机制上统一修复,不允许再写 panel 特判。
|
||||
|
||||
### 完成标准
|
||||
|
||||
- `Hierarchy` 具备旧 editor 的核心编辑语义,而不是展示假数据。
|
||||
|
||||
## Phase 4:接回 Project 正式资产工作流
|
||||
|
||||
### 目标
|
||||
|
||||
把已经有外壳的 `Project` 面板接回真实 project/Assets 工作流。
|
||||
|
||||
### 任务
|
||||
|
||||
- 用正式 `ProjectManager`/Asset data source 替换当前轻量扫描逻辑。
|
||||
- 保持已完成的外观与交互风格。
|
||||
- 接回:
|
||||
- folder tree
|
||||
- breadcrumb navigation
|
||||
- asset grid selection
|
||||
- open / double click
|
||||
- rename
|
||||
- create folder
|
||||
- delete
|
||||
- drag move
|
||||
- context menu
|
||||
- refresh / watcher
|
||||
- 对齐旧 editor 的 `.meta` / `Library` / 资源管理语义。
|
||||
|
||||
### 优先参考文件
|
||||
|
||||
- `editor/src/panels/ProjectPanel.*`
|
||||
- `editor/src/Actions/ProjectActionRouter.h`
|
||||
- `editor/src/Commands/ProjectCommands.h`
|
||||
- `editor/src/Managers/ProjectManager.*`
|
||||
|
||||
### 根因要求
|
||||
|
||||
- Project 右侧 grid 的事件必须继续保持语义化输出,不要退回 raw hit test 乱写业务。
|
||||
- 资产操作必须收敛到 command / manager,不能把文件系统操作塞在 UI 绘制逻辑里。
|
||||
|
||||
### 完成标准
|
||||
|
||||
- `Project` 成为真正可用的资产浏览与操作入口。
|
||||
|
||||
## Phase 5:接回 Inspector 与 ComponentEditorRegistry
|
||||
|
||||
### 目标
|
||||
|
||||
把 `XCEditor` 已有的 field/property grid 真正用于 Inspector,而不是停留在基础控件演示。
|
||||
|
||||
### 任务
|
||||
|
||||
- 建立新的 `ComponentEditors/**` 注册表。
|
||||
- 接回 `InspectorPanel`。
|
||||
- 首批接回:
|
||||
- Transform
|
||||
- Camera
|
||||
- Light
|
||||
- MeshFilter
|
||||
- MeshRenderer
|
||||
- Script
|
||||
- 接回 object/asset reference field。
|
||||
- 处理 interactive undo 边界。
|
||||
- 对齐旧 editor 的 Add Component 入口与规则。
|
||||
|
||||
### 优先参考文件
|
||||
|
||||
- `editor/src/panels/InspectorPanel.*`
|
||||
- `editor/src/ComponentEditors/**`
|
||||
- `editor/src/Commands/ComponentCommands.h`
|
||||
|
||||
### 根因要求
|
||||
|
||||
- 通用字段行为沉淀在 `XCEditor/Fields/**`。
|
||||
- 组件语义停留在 app-level `ComponentEditors/**`。
|
||||
- 不允许把具体组件判断重新塞回 shared field 层。
|
||||
|
||||
### 完成标准
|
||||
|
||||
- `Inspector` 可以对真实选中对象执行稳定编辑。
|
||||
|
||||
## Phase 6:接回 Console 与编辑器日志桥接
|
||||
|
||||
### 目标
|
||||
|
||||
补齐旧 editor 的 console 工作流。
|
||||
|
||||
### 任务
|
||||
|
||||
- 迁入 console data model、过滤状态与 sink。
|
||||
- 接回日志分级、清空、过滤、点击定位等基础行为。
|
||||
- 与菜单/快捷键/上下文操作对齐。
|
||||
|
||||
### 优先参考文件
|
||||
|
||||
- `editor/src/panels/ConsolePanel.*`
|
||||
- `editor/src/UI/ConsoleFilterState.h`
|
||||
- `editor/src/Core/EditorConsoleSink.*`
|
||||
- `editor/src/Actions/ConsoleActionRouter.h`
|
||||
|
||||
### 完成标准
|
||||
|
||||
- `Console` 不再是空 panel,能承担真实调试反馈。
|
||||
|
||||
## Phase 7:接回 Scene / Game Viewport 正式主链
|
||||
|
||||
### 目标
|
||||
|
||||
这是替代旧 editor 的真正硬门槛。
|
||||
|
||||
### 任务
|
||||
|
||||
- 将旧 editor 的 viewport host/render path 重新桥接到 `XCEditorViewportSlot / XCEditorViewportShell`。
|
||||
- 接回:
|
||||
- scene viewport 离屏渲染
|
||||
- game viewport 渲染
|
||||
- viewport resize
|
||||
- navigation
|
||||
- gizmo
|
||||
- overlay
|
||||
- selection / picking
|
||||
- edit / play mode 切换
|
||||
- 处理 viewport 与 shell 输入焦点、capture、cursor 的统一。
|
||||
|
||||
### 优先参考文件
|
||||
|
||||
- `editor/src/panels/SceneViewPanel.*`
|
||||
- `editor/src/panels/GameViewPanel.*`
|
||||
- `editor/src/Viewport/**`
|
||||
- `editor/src/Application.*`
|
||||
- `editor/src/Platform/D3D12WindowRenderer*`
|
||||
|
||||
### 根因要求
|
||||
|
||||
- viewport 相关问题优先在 app viewport layer / host bridge 修。
|
||||
- 不允许在 panel 里私拼第二套渲染路径。
|
||||
|
||||
### 完成标准
|
||||
|
||||
- `Scene/Game` 具备旧 editor 的基础可用性。
|
||||
|
||||
## Phase 8:接回项目生命周期、运行模式与脚本工作流
|
||||
|
||||
### 目标
|
||||
|
||||
把编辑器从“几个面板能显示”推进到“有完整项目工作流”。
|
||||
|
||||
### 任务
|
||||
|
||||
- project 打开 / 切换 / 保存状态
|
||||
- scene 打开 / 保存 / Save As
|
||||
- runtime mode / play session controller
|
||||
- 脚本程序集重建与状态显示
|
||||
- Library/bootstrap/import 状态展示
|
||||
- window title 与 dirty state
|
||||
|
||||
### 优先参考文件
|
||||
|
||||
- `editor/src/Core/PlaySessionController.*`
|
||||
- `editor/src/Core/EditorWindowTitle.h`
|
||||
- `editor/src/Scripting/**`
|
||||
- `editor/src/Application.*`
|
||||
|
||||
### 完成标准
|
||||
|
||||
- `new_editor` 能跑通真实项目编辑主流程,而不是只展示 UI 壳。
|
||||
|
||||
## Phase 9:视觉一致性、回归与旧 Editor 退场条件
|
||||
|
||||
### 目标
|
||||
|
||||
在核心工作流都接回后,统一做收口。
|
||||
|
||||
### 任务
|
||||
|
||||
- 对关键界面做逐项比对:
|
||||
- menu bar
|
||||
- dock/tab
|
||||
- hierarchy
|
||||
- project
|
||||
- inspector
|
||||
- console
|
||||
- scene/game
|
||||
- 修正与旧 editor 的视觉与交互偏差。
|
||||
- 清理 `new_editor` 中所有 demo 数据、临时状态、过渡适配层。
|
||||
- 给每一块关键能力补齐:
|
||||
- `tests/UI/Editor`
|
||||
- product-level smoke validation
|
||||
|
||||
### 最终收口标准
|
||||
|
||||
满足以下条件后,才算真正达到“可替代旧 editor”的程度:
|
||||
|
||||
1. `new_editor` 已接回旧 editor 的核心面板与主工作流。
|
||||
2. `Scene/Game` viewport 可稳定工作。
|
||||
3. `Hierarchy/Project/Inspector/Console` 都是正式数据源,不再有 demo 假数据。
|
||||
4. menu / shortcut / context / toolbar 已共用动作层。
|
||||
5. undo / selection / runtime mode / active route 有清晰 owner。
|
||||
6. 没有为了赶进度堆出来的 panel-local hack。
|
||||
|
||||
## 8. 并行拆分建议
|
||||
|
||||
可以并行,但必须分主从关系:
|
||||
|
||||
### 主依赖顺序
|
||||
|
||||
1. `Phase 1` 应用层骨架
|
||||
2. `Phase 2` 动作与命令层
|
||||
3. `Phase 3/4/5/6` 面板业务回接
|
||||
4. `Phase 7` viewport 主链
|
||||
5. `Phase 8/9` 生命周期与总收口
|
||||
|
||||
### 可并行子线
|
||||
|
||||
1. `Core/Managers/Context` 收敛
|
||||
2. `Actions/Commands` 迁移
|
||||
3. `Hierarchy + SceneManager` 接回
|
||||
4. `Project + ProjectManager` 接回
|
||||
5. `Inspector + ComponentEditors` 接回
|
||||
6. `Console + tests/UI/Editor` 回归补齐
|
||||
|
||||
说明:
|
||||
|
||||
- `Viewport` 尽量单独作为高风险主线,不和别的大改混在一起。
|
||||
- 一旦并行子线发现 `XCEditor` 基础问题,优先暂停子线、回底层修复。
|
||||
|
||||
## 9. 立即执行顺序
|
||||
|
||||
当前建议的第一批执行顺序是:
|
||||
|
||||
1. 先收敛 `new_editor` 应用层骨架与目录边界。
|
||||
2. 立刻建立新的 `EditorContext / Managers / Workspace`。
|
||||
3. 然后先接 `Hierarchy` 和 `Project` 的真实数据源,因为这两块当前已有可见 UI 外壳。
|
||||
4. 再接 `Inspector` 与 `Console`。
|
||||
5. 最后接 `Scene/Game viewport` 与运行模式主链。
|
||||
|
||||
原因:
|
||||
|
||||
- `Hierarchy` / `Project` 已经有可见壳层,最适合先把产品语义接回来。
|
||||
- `Viewport` 风险最高,应在应用层骨架稳定后单独推进。
|
||||
|
||||
## 10. 当前需要归档的旧计划
|
||||
|
||||
本轮建议归档到 `docs/plan/used/` 的文档:
|
||||
|
||||
- `XCEditor_Dock统一与Tab拖拽停靠收口计划_2026-04-10.md`
|
||||
|
||||
保留在 `docs/plan/` 的参考文档:
|
||||
|
||||
- `Editor架构说明.md`
|
||||
|
||||
原因:
|
||||
|
||||
- 前者属于阶段性基础层收口计划,主线已被当前迁移重建计划替代。
|
||||
- 后者不是过期计划,而是旧 editor 的分层参考资料,后续迁移时仍需频繁对照。
|
||||
@@ -1,505 +0,0 @@
|
||||
# Renderer C++层第三阶段计划:Render Graph 骨架与资源调度
|
||||
|
||||
日期:`2026-04-14`
|
||||
|
||||
## 1. 文档定位
|
||||
|
||||
第二阶段已经收口,当前 native 渲染层已经完成了两件关键事情:
|
||||
|
||||
- `request -> frame plan -> execution` 主链基本收干净
|
||||
- `BuiltinForwardPipeline` 已经从“大杂烩”开始拆成更清晰的 builtin renderer 雏形
|
||||
|
||||
所以下一阶段不应该继续围着 `BuiltinForwardPipeline` 做零散瘦身,而是要正式进入:
|
||||
|
||||
`Render Graph`
|
||||
|
||||
这一阶段的目标不是立刻做完整 `Deferred Renderer`,也不是立刻做 `C# SRP`,而是先在 `C++ native` 层建立真正可长期演进的图式调度内核。
|
||||
|
||||
---
|
||||
|
||||
## 2. 什么是 Render Graph
|
||||
|
||||
Render Graph 不是“一个新 pass 管理器”,也不是“把现有 stage 改个名字”。
|
||||
|
||||
它本质上是:
|
||||
|
||||
- 一套按帧构建的 pass / resource 依赖描述
|
||||
- 一套根据读写关系编译执行顺序的系统
|
||||
- 一套统一管理 transient 资源、资源生命周期和 barrier 的系统
|
||||
|
||||
也就是说,pass 不再手写:
|
||||
|
||||
- 我自己创建哪张中间 RT
|
||||
- 我自己决定什么时候切状态
|
||||
- 我自己告诉下一个 pass 用哪张 source/destination surface
|
||||
|
||||
而是改成声明:
|
||||
|
||||
- 我读什么
|
||||
- 我写什么
|
||||
- 我输出到哪类 attachment
|
||||
- 我需要什么输入上下文
|
||||
|
||||
然后由 graph 编译器统一决定:
|
||||
|
||||
- 顺序
|
||||
- 资源创建/复用
|
||||
- barrier
|
||||
- 最终执行计划
|
||||
|
||||
一句话说,当前是“手写命令式渲染编排”,Render Graph 是“声明式依赖编排 + 编译执行”。
|
||||
|
||||
---
|
||||
|
||||
## 3. 为什么现在该做
|
||||
|
||||
当前这套渲染层已经到了一个临界点:
|
||||
|
||||
- `CameraFramePlan` 已经把 camera 级执行入口整理出来了
|
||||
- `SceneRenderFeatureHost` 已经把 feature 注入点整理出来了
|
||||
- `BuiltinForwardPipeline` 已经拆出 frame / lifecycle / resources / scene phases / surface
|
||||
|
||||
这意味着“谁来做什么”已经比之前清楚很多了。
|
||||
|
||||
但现在仍然有三个核心问题没解决:
|
||||
|
||||
### 3.1 资源流还是手工传递
|
||||
|
||||
现在很多阶段仍然是:
|
||||
|
||||
- `RenderSurface`
|
||||
- `sourceColorView`
|
||||
- `sourceSurface`
|
||||
- `destinationSurface`
|
||||
|
||||
靠手工在 `CameraFramePlan` 和 `CameraRenderer` 之间传。
|
||||
|
||||
这对少量固定阶段还能忍,但一旦要上:
|
||||
|
||||
- 更长的 post-process 链
|
||||
- object id / overlay / outline 混合
|
||||
- deferred gbuffer
|
||||
- SSAO / SSR / TAA / bloom / DoF
|
||||
- feature 自定义中间纹理
|
||||
|
||||
就会越来越乱。
|
||||
|
||||
### 3.2 依赖关系还是隐式的
|
||||
|
||||
当前 feature 注入点已经有了,但依赖还是隐式的。
|
||||
|
||||
例如一个 feature pass 到底:
|
||||
|
||||
- 读 scene color
|
||||
- 读 depth
|
||||
- 读 shadow map
|
||||
- 写 camera color
|
||||
- 写独立 intermediate
|
||||
|
||||
现在不是 native 核心显式知道的,而是散落在调用代码里。
|
||||
|
||||
### 3.3 Deferred 还没有合适宿主
|
||||
|
||||
Deferred 不应该直接加在现在这套手工 surface 编排上。
|
||||
|
||||
因为 deferred 天生会带来:
|
||||
|
||||
- gbuffer A/B/C/depth
|
||||
- lighting buffer
|
||||
- transparent / skybox / post-process 组合
|
||||
- optional prepass / depth pyramid / SSAO
|
||||
|
||||
这些东西如果没有 Render Graph,代码很快又会炸回“大 pipeline 手工串 stage”的旧路。
|
||||
|
||||
所以顺序必须是:
|
||||
|
||||
1. 先做 Render Graph
|
||||
2. 再在 graph 上接 deferred
|
||||
|
||||
---
|
||||
|
||||
## 4. 这一阶段的总目标
|
||||
|
||||
这一阶段结束后,native 层要达到下面这个结构:
|
||||
|
||||
`RHI -> Render Graph Kernel -> Builtin Renderer Graph Builder -> Feature Injection -> Camera Execution`
|
||||
|
||||
更具体一点:
|
||||
|
||||
- `RHI` 继续负责底层资源、命令列表、PSO、descriptor、render pass
|
||||
- `Render Graph Kernel` 负责 pass/resource/依赖/barrier/lifetime
|
||||
- `Builtin Renderer` 负责“这一帧要往 graph 里注册哪些 scene pass”
|
||||
- `Feature` 负责在指定注入点向 graph 追加 pass
|
||||
- `CameraRenderer` 只负责 build scene data -> build graph -> execute graph
|
||||
|
||||
---
|
||||
|
||||
## 5. 和你当前代码怎么对接
|
||||
|
||||
### 5.1 先保留 CameraFramePlan,但降级为“高层帧意图”
|
||||
|
||||
现在的 `CameraFramePlan` 里还带着不少具体 surface/sourceColor 细节。
|
||||
|
||||
Render Graph 上来之后,`CameraFramePlan` 更应该表达:
|
||||
|
||||
- 这台 camera 本帧需不需要 shadow
|
||||
- 需不需要 object id
|
||||
- 需不需要 post-process
|
||||
- 需不需要 final output
|
||||
- 需不需要 overlay
|
||||
- 允许哪些 feature 注入
|
||||
|
||||
而不是继续手工保存一串中间 surface 流。
|
||||
|
||||
也就是说:
|
||||
|
||||
- `CameraFramePlan` 保留
|
||||
- 但它从“半执行脚本”收成“高层执行意图”
|
||||
|
||||
### 5.2 CameraRenderer 改成 build graph,而不是手工串 stage
|
||||
|
||||
当前 `CameraRenderer` 还是在做:
|
||||
|
||||
- build scene data
|
||||
- 执行 shadow
|
||||
- 执行 main scene
|
||||
- 执行 post-process
|
||||
- 执行 final output
|
||||
- 执行 object id / overlay
|
||||
|
||||
下一阶段要改成:
|
||||
|
||||
1. `BuildSceneData`
|
||||
2. `BuildRendererLists`
|
||||
3. `BuildCameraRenderGraph`
|
||||
4. `ExecuteRenderGraph`
|
||||
|
||||
也就是说它变成 graph 驱动器,而不是手工编排器。
|
||||
|
||||
### 5.3 BuiltinForwardPipeline 不再直接代表“一整帧”
|
||||
|
||||
这一步很关键。
|
||||
|
||||
当前 `BuiltinForwardPipeline` 虽然已经清爽很多,但本质上还是:
|
||||
|
||||
- 一个 camera main scene renderer
|
||||
|
||||
Render Graph 之后,它更应该变成:
|
||||
|
||||
- 一个向 graph 注册 forward scene pass 的 builtin renderer
|
||||
|
||||
也就是它的职责改成:
|
||||
|
||||
- 注册 opaque pass
|
||||
- 注册 skybox pass
|
||||
- 注册 transparent pass
|
||||
- 在合适注入点让 feature host 往 graph 塞 pass
|
||||
|
||||
而不是自己继续拥有整帧级别的中间表面和编排职责。
|
||||
|
||||
### 5.4 SceneRenderFeatureHost 保留,但执行方式改掉
|
||||
|
||||
`SceneRenderFeatureHost` 现在是直接 `Prepare/Execute`。
|
||||
|
||||
上 Render Graph 后,它更应该变成:
|
||||
|
||||
- 在 `BeforeOpaque / AfterOpaque / BeforeTransparent / AfterTransparent` 等注入点
|
||||
- 由 feature 向 graph builder 注册 pass
|
||||
|
||||
所以 concept 保留,执行方式要改成:
|
||||
|
||||
- 现在:`feature.Execute(passContext)`
|
||||
- 以后:`feature.Record(renderGraphBuilder, injectionPoint, context)`
|
||||
|
||||
这会非常接近 Unity URP 的 `RendererFeature -> AddRenderPasses` 那个味道。
|
||||
|
||||
### 5.5 RenderSurface 只保留 external/import 场景
|
||||
|
||||
Graph 上来之后,不应该继续让内部 pass 大量互相传裸 `RenderSurface`。
|
||||
|
||||
`RenderSurface` 主要应该用于:
|
||||
|
||||
- swapchain backbuffer
|
||||
- editor viewport offscreen target
|
||||
- object id target
|
||||
- 已有外部资源 import 进 graph
|
||||
|
||||
而 graph 内部中间纹理应该改成:
|
||||
|
||||
- graph texture handle
|
||||
- graph imported texture
|
||||
- graph transient texture
|
||||
|
||||
---
|
||||
|
||||
## 6. 这一阶段的实现策略
|
||||
|
||||
### 6.1 先做最小可用 Render Graph,不求一步到位
|
||||
|
||||
第一版 graph 只做下面这些:
|
||||
|
||||
- texture resource
|
||||
- imported texture
|
||||
- transient texture
|
||||
- raster pass
|
||||
- compute pass
|
||||
- read/write dependency
|
||||
- 简单拓扑排序
|
||||
- 简单 barrier 推导
|
||||
- 按帧创建与释放 transient 资源
|
||||
|
||||
第一版明确先不做:
|
||||
|
||||
- 复杂 aliasing
|
||||
- pass merge
|
||||
- async compute 调度
|
||||
- memory budget 优化器
|
||||
- 跨 queue graph
|
||||
|
||||
先把“能正确替代手工 surface 编排”做出来。
|
||||
|
||||
### 6.2 先 graph 化 camera 级 pass,不先 graph 化单个 draw call
|
||||
|
||||
这一步也很重要。
|
||||
|
||||
先 graph 化的是:
|
||||
|
||||
- shadow caster
|
||||
- main scene opaque/skybox/transparent
|
||||
- object id
|
||||
- post-process
|
||||
- final output
|
||||
- overlay / outline / grid
|
||||
|
||||
不是一上来就把 mesh draw 拆成图节点。
|
||||
|
||||
也就是说,graph 的粒度先是“渲染 pass 级”,不是“每个物体 draw 级”。
|
||||
|
||||
这是成本最低、风险最小、收益最大的切法。
|
||||
|
||||
### 6.3 先替掉中间 surface 管理,再替掉 feature 执行模型
|
||||
|
||||
推荐顺序:
|
||||
|
||||
1. 先让 post-process / final output / object-id / overlay 改成 graph 资源流
|
||||
2. 再让 builtin forward main scene 改成 graph pass
|
||||
3. 最后让 feature host 改成 graph 注入
|
||||
|
||||
原因很简单:
|
||||
|
||||
- 最乱的其实是中间资源流
|
||||
- 资源流一旦 graph 化,后面的 feature / deferred 才有稳定宿主
|
||||
|
||||
---
|
||||
|
||||
## 7. 建议新增的 native 模块
|
||||
|
||||
建议直接新开一个 `Rendering/Graph/` 模块。
|
||||
|
||||
第一版建议至少有:
|
||||
|
||||
- `RenderGraph.h`
|
||||
- `RenderGraphBuilder.h`
|
||||
- `RenderGraphPass.h`
|
||||
- `RenderGraphResource.h`
|
||||
- `RenderGraphTypes.h`
|
||||
- `RenderGraphCompiler.h`
|
||||
- `RenderGraphExecutor.h`
|
||||
- `RenderGraphBlackboard.h`
|
||||
|
||||
第一版资源类型建议先只做:
|
||||
|
||||
- `RenderGraphTextureHandle`
|
||||
- `ImportedTextureDesc`
|
||||
- `TransientTextureDesc`
|
||||
|
||||
第一版 pass builder 建议至少支持:
|
||||
|
||||
- `ReadTexture`
|
||||
- `WriteColor`
|
||||
- `WriteDepth`
|
||||
- `ReadDepth`
|
||||
- `CreateTransientTexture`
|
||||
- `ImportTexture`
|
||||
- `SetExecuteCallback`
|
||||
|
||||
---
|
||||
|
||||
## 8. 对当前文件结构的具体改造方向
|
||||
|
||||
### 8.1 CameraRenderer
|
||||
|
||||
从:
|
||||
|
||||
- 手工执行 frame stage
|
||||
|
||||
改成:
|
||||
|
||||
- build scene data
|
||||
- build renderer lists
|
||||
- build render graph
|
||||
- execute render graph
|
||||
|
||||
### 8.2 CameraFramePlan
|
||||
|
||||
从:
|
||||
|
||||
- 带大量具体 source/destination surface 细节
|
||||
|
||||
改成:
|
||||
|
||||
- 表达这一帧需要哪些逻辑阶段和输出能力
|
||||
|
||||
### 8.3 BuiltinForwardPipeline
|
||||
|
||||
从:
|
||||
|
||||
- 一个直接渲染 camera main scene 的 pipeline
|
||||
|
||||
改成:
|
||||
|
||||
- 一个 forward renderer graph builder / pass registrar
|
||||
|
||||
### 8.4 FullscreenPassSurfaceCache
|
||||
|
||||
从:
|
||||
|
||||
- runtime 手工中间表面缓存
|
||||
|
||||
改成:
|
||||
|
||||
- graph import/export 辅助
|
||||
- 后续逐步淡出
|
||||
|
||||
### 8.5 SceneRenderFeaturePass / Host
|
||||
|
||||
从:
|
||||
|
||||
- runtime execute
|
||||
|
||||
改成:
|
||||
|
||||
- graph record / graph contribute
|
||||
|
||||
---
|
||||
|
||||
## 9. 分阶段执行
|
||||
|
||||
## 阶段 A:Render Graph Core
|
||||
|
||||
目标:
|
||||
|
||||
- 建立 graph 基础数据结构和最小编译/执行器
|
||||
|
||||
交付:
|
||||
|
||||
- pass/resource/handle/builder/compiler/executor
|
||||
- 支持 imported + transient texture
|
||||
- 支持 raster + compute pass
|
||||
|
||||
验收:
|
||||
|
||||
- 有独立 unit tests
|
||||
- 能构造最小 graph 并正确执行顺序与 barrier
|
||||
|
||||
## 阶段 B:Camera 级资源流 graph 化
|
||||
|
||||
目标:
|
||||
|
||||
- 把 post-process / final output / object id / overlay 的中间 surface 手工管理替成 graph
|
||||
|
||||
交付:
|
||||
|
||||
- `CameraRenderer` 开始 build graph
|
||||
- `FullscreenPassSurfaceCache` 职责收缩
|
||||
|
||||
验收:
|
||||
|
||||
- 现有 viewport / object id / final color 路径不回退
|
||||
|
||||
## 阶段 C:Builtin Forward Main Scene graph 化
|
||||
|
||||
目标:
|
||||
|
||||
- 把 main scene 从手工 frame 执行切到 graph raster pass
|
||||
|
||||
交付:
|
||||
|
||||
- opaque / skybox / transparent 作为 graph pass 注册
|
||||
- forward scene 仍保留当前 renderer list / draw settings 逻辑
|
||||
|
||||
验收:
|
||||
|
||||
- 当前 forward 主链功能不回退
|
||||
- `BuiltinForwardPipeline` 不再继续持有整帧调度职责
|
||||
|
||||
## 阶段 D:Feature 注入 graph 化
|
||||
|
||||
目标:
|
||||
|
||||
- 让 `SceneRenderFeatureHost` 从直接执行改成向 graph 注入
|
||||
|
||||
交付:
|
||||
|
||||
- feature pass graph record contract
|
||||
- 注入点继续沿用当前 `SceneRenderInjectionPoint`
|
||||
|
||||
验收:
|
||||
|
||||
- gaussian / volumetric / editor feature 能继续挂入
|
||||
|
||||
## 阶段 E:为 Deferred 做宿主准备
|
||||
|
||||
目标:
|
||||
|
||||
- 不做 deferred 本身,只把 graph 宿主和 renderer contract 整理到可以接 deferred
|
||||
|
||||
交付:
|
||||
|
||||
- scene color/depth/object id/shadow/final output 都成为正式 graph resource
|
||||
- renderer feature 和 builtin renderer 关系稳定
|
||||
|
||||
验收:
|
||||
|
||||
- 下一阶段可以直接进入 deferred / gbuffer 设计
|
||||
|
||||
---
|
||||
|
||||
## 10. 本阶段明确不做
|
||||
|
||||
- 不在这一阶段直接落完整 deferred
|
||||
- 不在这一阶段做 C# SRP API
|
||||
- 不在这一阶段做全量资源 aliasing 优化
|
||||
- 不在这一阶段做 async compute graph
|
||||
- 不在这一阶段推倒重写 RHI
|
||||
|
||||
---
|
||||
|
||||
## 11. 这一阶段完成后的状态
|
||||
|
||||
如果这一阶段做完,native 渲染层应该变成下面这样:
|
||||
|
||||
- `CameraFramePlan` 负责高层帧意图
|
||||
- `CameraRenderer` 负责 graph build + execute
|
||||
- `RenderGraph` 负责资源生命周期与依赖调度
|
||||
- `BuiltinForwardRenderer` 负责向 graph 注册 forward scene pass
|
||||
- `FeatureHost` 负责在 injection point 向 graph 贡献 pass
|
||||
|
||||
到这一步,再做:
|
||||
|
||||
- deferred
|
||||
- universal renderer
|
||||
- C# 自定义 renderer feature
|
||||
- C# 自定义 pipeline
|
||||
|
||||
才是顺的。
|
||||
|
||||
---
|
||||
|
||||
## 12. 一句话结论
|
||||
|
||||
下一阶段不是继续修补 `BuiltinForwardPipeline`,而是要把你现在这套已经整理好的 native 渲染主链,正式提升成:
|
||||
|
||||
`Render Graph 驱动的 Render Kernel`
|
||||
|
||||
这一步一旦做实,后面的 deferred 和 Unity 式 SRP/URP 才有真正稳定的底座。
|
||||
@@ -1,211 +0,0 @@
|
||||
# Renderer C++层第二阶段计划:Builtin Renderer 与 Feature Contract
|
||||
|
||||
日期:`2026-04-14`
|
||||
|
||||
## 1. 文档定位
|
||||
|
||||
第一阶段已经把最乱的执行契约收干净了:
|
||||
|
||||
- `request -> frame plan -> execution` 已经分层
|
||||
- `SceneRenderer / CameraRenderer` 的公开执行入口已经收敛到 `CameraFramePlan`
|
||||
|
||||
第二阶段不做 `Render Graph`,也不做 `Deferred Renderer`。
|
||||
第二阶段要做的是:
|
||||
|
||||
`先把 native C++ 层整理成一个真正能承接 URP-like 包层的内核`
|
||||
|
||||
也就是先把“内建 renderer、feature 注入点、pass 编排契约”做对。
|
||||
|
||||
## 2. 为什么下一步不是先搞 Shadow
|
||||
|
||||
`Shadow` 后面当然会进入 `URP-like` 层参与编排,但那说的是:
|
||||
|
||||
- cascade 策略
|
||||
- filter 策略
|
||||
- screen-space shadow
|
||||
- additional light shadow
|
||||
- debug / feature 开关
|
||||
|
||||
这些“策略和管线组织”应该放在包层。
|
||||
|
||||
但 native C++ 层里仍然必须保留最小阴影执行能力:
|
||||
|
||||
- shadow map / atlas 资源
|
||||
- shadow caster pass 执行
|
||||
- light-space 数据布局
|
||||
- resource state / barrier / cache
|
||||
- 主场景采样阴影所依赖的底层 contract
|
||||
|
||||
所以现在如果先把 `shadow` 当第一优先去扩,会把顺序做反。
|
||||
更正确的路线是:
|
||||
|
||||
1. 先把 `renderer / feature / pass` 契约做稳定
|
||||
2. 再让 `shadow` 挂到这个契约上
|
||||
3. 再往 `URP-like` 层放阴影策略
|
||||
|
||||
## 3. 本阶段总目标
|
||||
|
||||
把当前 `BuiltinForwardPipeline + SceneRenderer + editor 注入点` 这一坨,
|
||||
整理成更接近下面这条线的形态:
|
||||
|
||||
`RHI -> Native Render Kernel -> Builtin Renderer Contract -> URP-like Renderer Layer`
|
||||
|
||||
这一阶段结束后,native 层要能回答清楚三件事:
|
||||
|
||||
- 一个 builtin renderer 的正式输入是什么
|
||||
- 一个 renderer feature 怎么注入 pass
|
||||
- 哪些东西永远属于 native 执行层,哪些东西以后应该上 URP-like 包层
|
||||
|
||||
## 4. 这一阶段真正该做什么
|
||||
|
||||
### 4.1 先正式化 Builtin Renderer Contract
|
||||
|
||||
目标:
|
||||
|
||||
- 不再让 `BuiltinForwardPipeline` 既像 pipeline、又像 renderer、又像 feature 垃圾桶
|
||||
|
||||
这一轮要先说清楚:
|
||||
|
||||
- renderer runtime 的输入 contract
|
||||
- main scene phase 的组织方式
|
||||
- fullscreen / object-id / editor extension 的挂接边界
|
||||
- feature pass 和 renderer 自身职责边界
|
||||
|
||||
预期结果:
|
||||
|
||||
- `BuiltinForwardPipeline` 更像一个内建 renderer 雏形
|
||||
- 后面无论叫 `UniversalRenderer` 还是别的名字,都有 native 对照物
|
||||
|
||||
### 4.2 正式化 Feature / Pass 注入契约
|
||||
|
||||
目标:
|
||||
|
||||
- 把现在已经存在的各种 pass 注入点,收成一个以后能类比 `URP Renderer Feature` 的 native contract
|
||||
|
||||
这一轮重点不是把所有功能迁走,而是先把“怎么挂”定义清楚。
|
||||
|
||||
至少要覆盖:
|
||||
|
||||
- pre-scene
|
||||
- main-scene 前后扩展点
|
||||
- object-id
|
||||
- post-process
|
||||
- final-output
|
||||
- editor overlay / outline / grid
|
||||
|
||||
预期结果:
|
||||
|
||||
- feature 注入点不再依赖隐式约定
|
||||
- `CameraFramePlan` 对阶段的描述更稳定
|
||||
- 以后 C# 包层要做 renderer feature 时,native 侧已经有对应的宿主契约
|
||||
|
||||
### 4.3 BuiltinForwardPipeline 继续瘦身,但方向改成“内建 renderer 化”
|
||||
|
||||
目标:
|
||||
|
||||
- 不是继续散着拆 helper
|
||||
- 而是按“renderer 自身 / feature / 资源绑定 / scene draw”这几个方向收
|
||||
|
||||
这一轮优先处理:
|
||||
|
||||
- scene phase 调度
|
||||
- feature pass 调度
|
||||
- renderer 级资源绑定
|
||||
- 与 shadow / skybox / gaussian / volumetric 的宿主边界
|
||||
|
||||
预期结果:
|
||||
|
||||
- `BuiltinForwardPipeline` 主类继续变薄
|
||||
- 新增渲染能力时,优先新增 feature 或独立模块,而不是继续堆进主 cpp
|
||||
|
||||
### 4.4 Shadow 在本阶段只保留“最小 native service”
|
||||
|
||||
目标:
|
||||
|
||||
- 先不扩 shadow 策略层
|
||||
- 只把 native 必需能力收成清晰 service
|
||||
|
||||
也就是只做这些:
|
||||
|
||||
- shadow resource ownership
|
||||
- shadow caster execution contract
|
||||
- 主场景采样所需共享数据
|
||||
- 与 builtin renderer 的边界
|
||||
|
||||
明确不做这些:
|
||||
|
||||
- cascade 新策略
|
||||
- additional light shadows
|
||||
- screen-space shadow
|
||||
- 各种阴影 feature 开关扩展
|
||||
|
||||
这些以后都应该挂到 `URP-like` 层。
|
||||
|
||||
### 4.5 Rendering 目录第一轮低风险收口
|
||||
|
||||
目标:
|
||||
|
||||
- 只在职责边界已经清楚的前提下收目录
|
||||
|
||||
优先考虑:
|
||||
|
||||
- 把 `BuiltinForwardPipeline*` 相关实现收成更明确的 builtin renderer 子目录
|
||||
- 让 `Passes` 不再无限平铺
|
||||
- 给 feature / editor / fullscreen 形成更清晰的落点
|
||||
|
||||
原则:
|
||||
|
||||
- 先拆职责,再收目录
|
||||
- 不为“好看”做纯搬家
|
||||
- 每次目录调整都必须带编译验证
|
||||
|
||||
## 5. 明确不做的事
|
||||
|
||||
这一阶段明确不做:
|
||||
|
||||
- 不引入真正运行时 `Render Graph`
|
||||
- 不做完整 `Deferred Renderer`
|
||||
- 不做 `C# SRP` 暴露
|
||||
- 不把 Gaussian / Volumetric / Shadow 整块直接搬到包层
|
||||
- 不为了目录整齐做大搬家
|
||||
|
||||
## 6. 推荐执行顺序
|
||||
|
||||
1. 先做 `Builtin Renderer Contract`
|
||||
2. 再做 `Feature / Pass 注入契约`
|
||||
3. 再做 `BuiltinForwardPipeline` 的 renderer 化瘦身
|
||||
4. 同步把 `Shadow` 收成最小 native service
|
||||
5. 最后做第一轮目录收口
|
||||
|
||||
这个顺序的原因很简单:
|
||||
|
||||
- 没有 renderer contract,feature 就没有宿主
|
||||
- 没有 feature contract,URP-like 层以后只能继续硬绑 native 细节
|
||||
- 没有 builtin renderer 化,forward pipeline 还会继续长歪
|
||||
- shadow 应该挂在契约上收,而不是反过来主导这一阶段
|
||||
|
||||
## 7. 交付标准
|
||||
|
||||
满足下面这些条件,就可以认为第二阶段基本收口:
|
||||
|
||||
- builtin renderer 的输入和执行边界能一句话说清
|
||||
- feature / pass 注入点形成稳定 native contract
|
||||
- `BuiltinForwardPipeline` 更像 builtin renderer,而不是继续当大杂烩
|
||||
- shadow 留在 native 层的部分被收成最小 service
|
||||
- 目录结构开始反映真实模块边界
|
||||
- `XCEditor`、`rendering_unit_tests`、`editor_tests`、相关 rendering integration target 持续通过
|
||||
|
||||
## 8. 这一阶段完成后的下一步
|
||||
|
||||
当这一阶段做完,下一步才适合正式进入:
|
||||
|
||||
`C++ Render Graph + URP-like Renderer Layer`
|
||||
|
||||
到那时再接:
|
||||
|
||||
- `Render Graph`
|
||||
- `Universal Renderer`
|
||||
- `Renderer Feature`
|
||||
- `C# Custom Pipeline`
|
||||
|
||||
顺序才是对的。
|
||||
@@ -1,152 +0,0 @@
|
||||
# Renderer C++层第五阶段计划:SRP Host v1骨架与 Builtin Forward 复用
|
||||
|
||||
日期:`2026-04-15`
|
||||
|
||||
## 1. 阶段定位
|
||||
|
||||
第四阶段已经把 `native planning -> graph build` 这条主线基本收口:
|
||||
|
||||
- `CameraFramePlanBuilder` 的 fullscreen/color-chain 规划已拆出
|
||||
- `CameraFramePlan` 已从 public 头里下沉主要实现
|
||||
- `BuiltinForwardPipeline` 的 main-scene graph 录制已抽出 internal builder
|
||||
- `CameraFrame` / `SceneRenderFeatureHost` / `BuiltinForward` 共用的 graph recording context 已集中到统一 builder
|
||||
|
||||
现在可以正式进入下一阶段:
|
||||
|
||||
`SRP Host v1`
|
||||
|
||||
这一阶段不是直接做完整 URP,也不是直接开放最终用户级 API。
|
||||
这一阶段的目标是先把 native host、renderer builder、C# 管线入口三者接稳。
|
||||
|
||||
## 2. 这一阶段要解决的核心问题
|
||||
|
||||
### 2.1 目前还没有正式的 SRP host
|
||||
|
||||
当前引擎已经有:
|
||||
|
||||
- `SceneRenderer`
|
||||
- `CameraRenderer`
|
||||
- `RenderGraph`
|
||||
- `BuiltinForwardPipeline`
|
||||
|
||||
但还没有一个明确的“脚本侧组织 renderer / feature / pass,native 侧负责承载与执行”的正式宿主层。
|
||||
|
||||
### 2.2 当前 builtin forward 仍然是“内建管线实现”,不是“可被 SRP host 复用的 builtin renderer”
|
||||
|
||||
虽然第四阶段已经把 main-scene graph builder 抽出来了,但 `BuiltinForwardPipeline` 仍然更像一个完整管线对象。
|
||||
SRP host 要求它至少能被看成:
|
||||
|
||||
- 一个可复用的 native renderer
|
||||
- 一个可被 host 调度的 graph contributor
|
||||
- 一个默认 builtin implementation
|
||||
|
||||
而不是 host 本身。
|
||||
|
||||
### 2.3 C# 入口现在还缺少正式边界
|
||||
|
||||
后面如果要像 Unity 一样让用户用 C# 组织 renderer / feature / pass,最先需要的不是完整功能,而是稳定边界:
|
||||
|
||||
- C# 能创建/持有一条 render pipeline asset
|
||||
- native 能向脚本暴露受控的 renderer host 入口
|
||||
- host 能回落复用 builtin forward renderer
|
||||
|
||||
## 3. 本阶段总目标
|
||||
|
||||
这一阶段结束后,主线应接近:
|
||||
|
||||
`C# Pipeline Asset / Native Pipeline Asset -> SRP Host -> Builtin Renderer / Renderer Feature -> RenderGraph Host -> Execute`
|
||||
|
||||
也就是:
|
||||
|
||||
- `RenderGraph` 仍然留在 C++ 层
|
||||
- `SRP Host` 负责组织一帧 renderer graph contribution
|
||||
- `BuiltinForward` 首先作为默认 builtin renderer 被 host 复用
|
||||
- 后续 `URP-like package` 再放到更高层,不直接塞回 C++ host
|
||||
|
||||
## 4. 明确边界
|
||||
|
||||
### 4.1 这一阶段明确不做
|
||||
|
||||
- 不做完整 deferred renderer
|
||||
- 不做完整 URP 包
|
||||
- 不做完整 renderer feature 生态
|
||||
- 不做最终用户可自由扩展的全部 C# API
|
||||
|
||||
### 4.2 这一阶段必须做成
|
||||
|
||||
- 一个正式的 `SRP Host v1`
|
||||
- 一个可被 host 调度的 builtin forward renderer 入口
|
||||
- 一个最小可运行的 C# pipeline asset / host bridge
|
||||
- host 能把 builtin forward 作为默认 fallback 跑通
|
||||
|
||||
## 5. 具体执行顺序
|
||||
|
||||
### 5.1 先把 builtin forward 从“管线实现”整理成“host 可复用 renderer”
|
||||
|
||||
目标:
|
||||
|
||||
- 明确 builtin forward 的 renderer 身份
|
||||
- 减少 host 未来直接依赖 `BuiltinForwardPipeline` 大对象内部细节
|
||||
- 为后续 deferred / custom renderer 留统一接缝
|
||||
|
||||
建议收口方向:
|
||||
|
||||
- `BuiltinForwardRenderer` 或等价 internal builder host
|
||||
- `RenderPipeline` 与 `Renderer Builder` 边界再清一次
|
||||
|
||||
### 5.2 引入 `SRP Host v1` native 宿主
|
||||
|
||||
目标:
|
||||
|
||||
- host 持有一帧 renderer graph contribution 列表
|
||||
- host 负责组织 main scene / feature / fullscreen stages 的 graph 录制
|
||||
- 默认仍可回落到 builtin forward renderer
|
||||
|
||||
第一版不追求花哨能力,先把“host 存在且稳定”做出来。
|
||||
|
||||
### 5.3 打通最小 C# 管线入口
|
||||
|
||||
目标:
|
||||
|
||||
- C# 侧能描述“使用哪条 pipeline asset / renderer”
|
||||
- native 侧能从脚本入口落到 `SRP Host v1`
|
||||
- 至少存在一条 builtin forward 的脚本可达路径
|
||||
|
||||
这一层只做最小闭环,不追求完整编辑器 UX。
|
||||
|
||||
### 5.4 最后再决定是否开 `URP-like builtin package`
|
||||
|
||||
当下面三件事成立,再开下一阶段:
|
||||
|
||||
1. `SRP Host v1` 已稳定
|
||||
2. `BuiltinForward` 已经是可复用 builtin renderer,而不是一坨特殊 case
|
||||
3. C# 入口已经能稳定驱动默认 renderer
|
||||
|
||||
## 6. 完成标准
|
||||
|
||||
满足下面这些条件,就可以认定第五阶段收口:
|
||||
|
||||
- native 已存在正式的 `SRP Host v1`
|
||||
- builtin forward 已能作为 host 下的默认 builtin renderer 运行
|
||||
- 脚本侧至少能以最小路径创建并驱动默认 pipeline
|
||||
- `CameraRenderer` 不会重新长成新的总调度中心
|
||||
- `rendering_unit_tests / editor_tests / XCEditor smoke` 继续稳定
|
||||
|
||||
## 7. 阶段后下一步
|
||||
|
||||
第五阶段完成后,才进入:
|
||||
|
||||
`URP-like Builtin Package v1`
|
||||
|
||||
也就是:
|
||||
|
||||
- C# 侧 builtin package
|
||||
- renderer feature / pass 组合能力
|
||||
- forward first,deferred later
|
||||
|
||||
正确顺序仍然是:
|
||||
|
||||
1. `SRP Host v1`
|
||||
2. `URP-like builtin package`
|
||||
3. `Deferred renderer`
|
||||
4. 更复杂的 feature 生态
|
||||
@@ -1,180 +0,0 @@
|
||||
# Renderer C++层第四阶段计划:RenderGraph规划层收口与SRP启动前条件
|
||||
|
||||
日期:`2026-04-15`
|
||||
|
||||
## 1. 文档定位
|
||||
|
||||
第三阶段已经把 RenderGraph native host 的骨架、阶段上下文、运行时分发、stage surface/source 解析、fullscreen color chain 意图、internal policy 边界,连续收了一轮。
|
||||
|
||||
这一阶段不直接开做面向用户的 `C# SRP`。
|
||||
|
||||
这一阶段要做的是:
|
||||
|
||||
- 把 `CameraFramePlanBuilder` 和 planning 层继续收干净。
|
||||
- 让 `CameraFramePlan` 更像高层 frame intent,而不是执行细节载体。
|
||||
- 给后面的 `native renderer builder / SRP host seam` 做稳定落点。
|
||||
- 明确“什么时候可以正式开始做 SRP”。
|
||||
|
||||
一句话:
|
||||
先把 `native planning -> graph build` 这条线收口,再开 SRP。
|
||||
|
||||
## 2. 当前进展基线
|
||||
|
||||
截至当前主线,已经完成并推送:
|
||||
|
||||
- `8232f59` `Extract camera frame render-graph recording session`
|
||||
- `d92afa2` `Extract camera frame render-graph stage record context`
|
||||
- `5edc4ed` `Extract camera frame render-graph stage pass runtime`
|
||||
- `ac836ae` `Extract camera frame stage surface resolver`
|
||||
- `00fa6ff` `Group camera frame fullscreen color chain intent`
|
||||
- `0afcaa0` `Move render-graph stage policy into internal host`
|
||||
|
||||
当前验证基线:
|
||||
|
||||
- `rendering_unit_tests`: `209 passed / 1 failed`
|
||||
- 唯一剩余失败:`BuiltinForwardPipeline_Test.OpenGLRuntimeTranspilesForwardShadowVariantToLegacyClipConventions`
|
||||
- `editor_tests`: `191 passed`
|
||||
- `XCEditor` 12s smoke:通过
|
||||
|
||||
## 3. 当前还没收口的核心问题
|
||||
|
||||
### 3.1 `CameraFramePlanBuilder` 仍然过重
|
||||
|
||||
现在 `AttachFullscreenStageRequests` 还在同时做:
|
||||
|
||||
- camera 后处理/最终输出需求判断
|
||||
- graph-managed color chain 规划
|
||||
- sequence 绑定
|
||||
- destination/source 语义拼装
|
||||
|
||||
这说明 planning 还是有点像“半执行期拼装器”。
|
||||
|
||||
### 3.2 `CameraFramePlan` 还没有完全变成高层意图对象
|
||||
|
||||
虽然已经收掉了一批低层 getter,也把 fullscreen chain 收成了 `colorChain`,但 plan 里仍然保留着一些偏执行期的结构和默认推导痕迹。
|
||||
|
||||
后面如果直接在这上面做 SRP,暴露出去的 API 很容易绑定到当前 native 内部实现细节。
|
||||
|
||||
### 3.3 还缺一个稳定的 native renderer builder 接缝
|
||||
|
||||
现在的 RenderGraph host 已经能工作,但还没有一个非常明确的 “renderer 向 graph 注册本帧 pass” 的正式层。
|
||||
|
||||
这层不稳定,后面:
|
||||
|
||||
- forward renderer
|
||||
- deferred renderer
|
||||
- feature injection
|
||||
- C# SRP host
|
||||
|
||||
都会继续直接碰当前 host 细节。
|
||||
|
||||
## 4. 本阶段总目标
|
||||
|
||||
这一阶段结束后,native 渲染主线要更接近:
|
||||
|
||||
`Scene/Camera Planning -> CameraFramePlan -> Native Renderer Builder -> RenderGraph Host -> Execute`
|
||||
|
||||
也就是:
|
||||
|
||||
- `Planning` 只负责“这一帧需要什么”。
|
||||
- `Renderer Builder` 只负责“把这些意图翻译成 graph passes/resources”。
|
||||
- `RenderGraph Host` 只负责“记录、编译、执行图”。
|
||||
|
||||
## 5. 具体执行顺序
|
||||
|
||||
### 5.1 先拆 `CameraFramePlanBuilder`
|
||||
|
||||
优先拆出与 fullscreen chain 相关的独立 planner / helper,目标是让 `SceneRenderer` 和 `CameraFramePlanBuilder` 不再直接持有一坨后处理/最终输出拼装逻辑。
|
||||
|
||||
建议收口方向:
|
||||
|
||||
- `CameraFrameFullscreenStagePlanner`
|
||||
- `CameraFrameColorChainPlanner`
|
||||
- `CameraFramePlanValidation` 或等价 helper
|
||||
|
||||
### 5.2 再把 plan 进一步高层化
|
||||
|
||||
继续减少 plan 里和具体 surface/source/sequence 拼装绑定过深的部分,让 plan 更像:
|
||||
|
||||
- 有哪些 stage
|
||||
- stage 之间是什么来源关系
|
||||
- 哪些输出是 graph-managed
|
||||
- 哪些是 external/imported target
|
||||
|
||||
而不是继续堆更多执行期细节。
|
||||
|
||||
### 5.3 引入 native renderer builder 接缝
|
||||
|
||||
在 native 侧明确一层“renderer 向 RenderGraph 贡献 pass”的正式接口。
|
||||
|
||||
这一层的目标不是立刻做成用户 API,而是先给:
|
||||
|
||||
- `BuiltinForwardPipeline`
|
||||
- 未来 `DeferredRenderer`
|
||||
- 未来 `RendererFeature`
|
||||
|
||||
提供统一宿主。
|
||||
|
||||
### 5.4 最后判断是否进入 SRP
|
||||
|
||||
当且仅当下面三件事成立,才正式开始做 SRP:
|
||||
|
||||
- `Planning` 和 `Execution` 边界稳定。
|
||||
- `Renderer Builder` 这一层稳定。
|
||||
- 新增渲染能力时,不需要再直接改 `CameraRenderer` 主线大函数。
|
||||
|
||||
## 6. 何时可以开始做 SRP
|
||||
|
||||
当前结论仍然是:
|
||||
|
||||
还不能正式开始做面向用户的 `C# SRP`。
|
||||
|
||||
可以开始 SRP 的条件不是“已经有 RenderGraph 了”,而是:
|
||||
|
||||
1. `CameraFramePlanBuilder` 已收口。
|
||||
2. `CameraFramePlan` 已足够高层稳定。
|
||||
3. native `renderer builder` 接缝已存在。
|
||||
4. `BuiltinForwardPipeline` 已经可以被看成一个 builtin renderer,而不是一坨 host 逻辑。
|
||||
|
||||
满足这四条之后,就可以开始第一版 SRP。
|
||||
|
||||
我的判断是:
|
||||
|
||||
- 如果第四阶段顺利,SRP 就已经进入可启动状态。
|
||||
- 也就是说,SRP 不是现在开。
|
||||
- SRP 是这一个 native 收口阶段之后开。
|
||||
|
||||
## 7. 本阶段完成标准
|
||||
|
||||
满足下面这些条件,就可以认定第四阶段收口:
|
||||
|
||||
- `CameraFramePlanBuilder` 明显变薄,fullscreen/color-chain planning 被拆出。
|
||||
- `CameraFramePlan` 不再继续回流低层执行细节。
|
||||
- native 出现稳定的 renderer builder 接缝。
|
||||
- `CameraRenderer` 继续变薄,没有重新长回大调度函数。
|
||||
- `rendering_unit_tests / editor_tests / XCEditor smoke` 继续稳定通过。
|
||||
|
||||
## 8. 阶段后下一步
|
||||
|
||||
第四阶段完成后,下一步就是正式开:
|
||||
|
||||
`SRP Host v1`
|
||||
|
||||
但第一版 SRP 仍然只建议做到:
|
||||
|
||||
- native host + C# 管线入口
|
||||
- C# 侧可组织 renderer / feature / pass
|
||||
- 先复用 builtin forward renderer
|
||||
|
||||
不建议一上来就同时做:
|
||||
|
||||
- 完整 deferred
|
||||
- 完整 URP 包
|
||||
- 全量 renderer feature 生态
|
||||
|
||||
正确顺序仍然是:
|
||||
|
||||
1. 先 native 收口
|
||||
2. 再 SRP host
|
||||
3. 再 URP-like builtin package
|
||||
4. 最后再 deferred / 更复杂 feature
|
||||
@@ -1,364 +0,0 @@
|
||||
# XCEditor Dock统一与Tab拖拽停靠收口计划
|
||||
|
||||
日期:`2026-04-10`
|
||||
|
||||
## 1. 文档定位
|
||||
|
||||
这份计划只解决 `XCEditor` 当前 dock 基础层的两个核心问题:
|
||||
|
||||
1. `Hierarchy / Inspector` 与 `Scene / Game / Console / Project` 顶部 chrome 不是同一套。
|
||||
2. tab 不能像旧 `editor/` 的 ImGui docking 那样拖拽重排与调整停靠位置。
|
||||
|
||||
这两个问题本质上是同一个根问题:当前 `DockHost` 的叶子语义和渲染路径没有统一,导致视觉、命中、交互、布局变更都被拆成两套,后续再堆业务面板只会继续在错误基础上加复杂度。
|
||||
|
||||
本计划属于 `Editor` 基础层收口,不属于业务面板重建计划。
|
||||
在这份计划完成前,不继续推进 `new_editor` 的 `Project / Hierarchy / Inspector / Console` 业务重建。
|
||||
|
||||
## 2. 当前问题与根因
|
||||
|
||||
## 2.1 当前现象
|
||||
|
||||
- `Hierarchy / Inspector` 的 header 仍然走 standalone panel 外壳。
|
||||
- `Scene / Game / Console / Project` 走 tab stack 外壳。
|
||||
- 用户看到的直接结果是:tab 高度、内边距、标题区结构、可交互区域都不一致。
|
||||
- 用户尝试拖 tab 时,没有任何重排、合并、分裂停靠反馈。
|
||||
|
||||
## 2.2 当前真实根因
|
||||
|
||||
当前实现里同时存在两种叶子形态:
|
||||
|
||||
- `Panel`
|
||||
- `TabStack`
|
||||
|
||||
这使得 `DockHost` 的整条链路都被拆成两套:
|
||||
|
||||
- 布局输出分叉
|
||||
- 绘制分叉
|
||||
- hit test 分叉
|
||||
- 交互分叉
|
||||
- 未来的 docking mutation 也无从统一落点
|
||||
|
||||
当前代码里的直接证据:
|
||||
|
||||
- `new_editor/app/Shell/ProductShellAsset.cpp`
|
||||
- `new_editor/include/XCEditor/Shell/UIEditorDockHost.h`
|
||||
- `new_editor/src/Shell/UIEditorDockHost.cpp`
|
||||
- `new_editor/include/XCEditor/Shell/UIEditorDockHostInteraction.h`
|
||||
- `new_editor/src/Shell/UIEditorDockHostInteraction.cpp`
|
||||
- `new_editor/include/XCEditor/Collections/UIEditorTabStripInteraction.h`
|
||||
- `new_editor/src/Collections/UIEditorTabStripInteraction.cpp`
|
||||
- `new_editor/include/XCEditor/Shell/UIEditorWorkspaceController.h`
|
||||
- `new_editor/src/Shell/UIEditorWorkspaceController.cpp`
|
||||
- `new_editor/src/Shell/UIEditorWorkspaceLayoutPersistence.cpp`
|
||||
|
||||
当前控制器层只具备:
|
||||
|
||||
- `OpenPanel`
|
||||
- `ClosePanel`
|
||||
- `ShowPanel`
|
||||
- `HidePanel`
|
||||
- `ActivatePanel`
|
||||
- `ResetWorkspace`
|
||||
- `SetSplitRatio`
|
||||
|
||||
还没有真正支撑 docking 的命令与树变更能力:
|
||||
|
||||
- `ReorderTab`
|
||||
- `MoveTabToStack`
|
||||
- `DockTabRelative`
|
||||
- `ExtractTab`
|
||||
- `MergeTabStack`
|
||||
|
||||
## 3. 改造目标
|
||||
|
||||
本轮收口后的目标状态如下:
|
||||
|
||||
1. 运行态叶子节点只保留一种语义:`TabStack`。
|
||||
2. 单面板也被视为“只有一个 tab 的 tab stack”。
|
||||
3. `DockHost` 只保留一套统一的 `DockHeader / TabWell / ContentBody` 视觉结构。
|
||||
4. `Hierarchy / Inspector` 与 `Scene / Game / Console / Project` 必须走同一套 header/tab primitive。
|
||||
5. tab 至少支持:
|
||||
- 同 stack 重排
|
||||
- 跨 stack 合并
|
||||
- 向目标 leaf 的 `left/right/top/bottom/center` 停靠
|
||||
6. 拖拽过程中必须有明确 preview,不允许“拖了但没有反馈”。
|
||||
7. workspace 布局持久化必须覆盖新结构,并兼容旧布局升级。
|
||||
8. 在 `tests/UI/Editor` 中补齐单元测试与集成测试后,才允许继续推进业务面板。
|
||||
|
||||
## 4. 范围边界
|
||||
|
||||
## 4.1 本轮必须做
|
||||
|
||||
- `XCEditor` 的 dock 叶子语义统一
|
||||
- dock chrome 统一
|
||||
- tab 拖拽状态机
|
||||
- docking drop target 与 preview overlay
|
||||
- workspace tree surgery
|
||||
- layout persistence 升级
|
||||
- `tests/UI/Editor` 的回归补齐
|
||||
|
||||
## 4.2 本轮明确不做
|
||||
|
||||
- 多原生窗口 detached docking
|
||||
- 浮动窗口系统
|
||||
- 业务面板内部复杂逻辑重建
|
||||
- `Runtime UI` 相关能力
|
||||
- 为 `Editor` 再做一套资源化主题体系
|
||||
|
||||
`Editor` 当前继续采用固定代码样式,不走 UI 资源那套。
|
||||
|
||||
## 5. 目标结构
|
||||
|
||||
## 5.1 统一后的 workspace 叶子模型
|
||||
|
||||
运行态只保留:
|
||||
|
||||
- `SplitNode`
|
||||
- `TabStackNode`
|
||||
|
||||
其中 `TabStackNode` 内部包含:
|
||||
|
||||
- `tabs`
|
||||
- `selectedTabId`
|
||||
- `activePanelId`
|
||||
|
||||
不再保留“裸 `Panel` 叶子节点”这种视觉语义。
|
||||
|
||||
## 5.2 统一后的 dock 布局输出
|
||||
|
||||
`DockHost` 最终应面向统一 leaf 输出:
|
||||
|
||||
- `tabWellRect`
|
||||
- `contentBodyRect`
|
||||
- `selectedPanelId`
|
||||
- `tabItems`
|
||||
- `dropPreview`
|
||||
|
||||
不再分成:
|
||||
|
||||
- `panelLayouts`
|
||||
- `tabStackLayouts`
|
||||
|
||||
两套平行分支。
|
||||
|
||||
## 5.3 统一后的交互分层
|
||||
|
||||
交互链路收口为:
|
||||
|
||||
1. `UIEditorTabStripInteraction`
|
||||
- 负责 tab press / armed / drag / release / cancel
|
||||
2. `UIEditorDockHostInteraction`
|
||||
- 负责把 tab 拖拽映射为 docking preview 与 docking command
|
||||
3. `UIEditorWorkspaceController`
|
||||
- 负责真正修改 workspace tree
|
||||
4. `UIEditorWorkspaceLayoutPersistence`
|
||||
- 负责新旧布局读写与升级
|
||||
|
||||
## 6. 分阶段执行计划
|
||||
|
||||
## Phase A:统一叶子语义
|
||||
|
||||
### 目标
|
||||
|
||||
把 workspace 运行态的叶子语义统一到 `TabStackNode`,彻底消除 standalone panel 叶子。
|
||||
|
||||
### 任务
|
||||
|
||||
- 调整 `UIEditorWorkspaceModel`,明确叶子节点只允许 `TabStackNode`。
|
||||
- 调整 `ProductShellAsset` 与默认 workspace 构建逻辑,让单面板默认也生成单-tab stack。
|
||||
- 调整 `UIEditorWorkspaceSession`,保证 active/selected 状态都围绕 tab stack 工作。
|
||||
- 调整 `UIEditorWorkspaceLayoutPersistence`,读旧格式时自动升级为统一 leaf 结构。
|
||||
- 增加 degenerate tree cleanup:
|
||||
- 空 stack 删除
|
||||
- 单子 split 折叠
|
||||
- 非法 selectedTab 修正
|
||||
|
||||
### 完成标准
|
||||
|
||||
- 运行态 workspace 中不再出现 standalone panel 叶子。
|
||||
- 旧布局能被自动升级并正常显示。
|
||||
|
||||
## Phase B:统一 dock chrome 与布局输出
|
||||
|
||||
### 目标
|
||||
|
||||
让所有 panel 顶部都走同一套 dock header / tab well primitive。
|
||||
|
||||
### 任务
|
||||
|
||||
- 重构 `UIEditorDockHost` 的 layout 输出结构,改为统一 leaf 布局。
|
||||
- 删除 standalone panel 与 tab stack 的渲染分叉。
|
||||
- `UIEditorPanelFrame` 缩回“边框与 body 外壳”职责,不再自带独立 header 风格。
|
||||
- `UIEditorTabStrip` 成为唯一 tab/header 渲染入口。
|
||||
- `UIEditorPanelContentHost` 只根据统一 leaf layout 定位 panel body。
|
||||
- 统一 hit target 语义,保证 header/tab/body 命中都来自同一套结构。
|
||||
|
||||
### 完成标准
|
||||
|
||||
- `Hierarchy / Inspector / Scene / Game / Console / Project` 顶部结构完全统一。
|
||||
- tab 高度、padding、命中区域、激活态样式只由一套 metric/palette 控制。
|
||||
|
||||
## Phase C:同 stack tab 拖拽重排
|
||||
|
||||
### 目标
|
||||
|
||||
先把最小闭环做稳:同一个 stack 内 tab 可拖拽重排。
|
||||
|
||||
### 任务
|
||||
|
||||
- 在 `UIEditorTabStripInteraction` 增加拖拽状态机:
|
||||
- `pressed`
|
||||
- `armed`
|
||||
- `dragging`
|
||||
- `cancelled`
|
||||
- `committed`
|
||||
- 增加 drag threshold、pointer capture、Esc cancel、release commit。
|
||||
- 在同 stack 内计算插入位置与 preview insertion marker。
|
||||
- 在 `UIEditorWorkspaceController` 增加 `ReorderTab(...)`。
|
||||
- 保证 selected/active/focus 状态在重排后仍然正确。
|
||||
|
||||
### 完成标准
|
||||
|
||||
- 同一 tab strip 内可拖拽重排。
|
||||
- 有明确插入线 preview。
|
||||
- 无闪烁、无丢焦、无错误激活。
|
||||
|
||||
## Phase D:跨 stack 合并与 split docking
|
||||
|
||||
### 目标
|
||||
|
||||
把 tab 从“只能在本组重排”扩展到“可跨组移动并形成新停靠布局”。
|
||||
|
||||
### 任务
|
||||
|
||||
- 在 `DockHostInteraction` 中引入 drop target 解析:
|
||||
- `center`
|
||||
- `left`
|
||||
- `right`
|
||||
- `top`
|
||||
- `bottom`
|
||||
- `root empty area`
|
||||
- 增加 preview overlay:
|
||||
- center merge 预览
|
||||
- edge split 高亮预览
|
||||
- 同 stack reorder 线性预览
|
||||
- 在 `WorkspaceController` 中增加:
|
||||
- `MoveTabToStack(...)`
|
||||
- `DockTabRelative(...)`
|
||||
- `ExtractTab(...)`
|
||||
- `MergeTabStack(...)`
|
||||
- 增加 tree surgery:
|
||||
- 从源 stack 抽 tab
|
||||
- 插入目标 stack
|
||||
- 围绕目标 leaf 生成 split
|
||||
- 空 stack 清理
|
||||
- 单子 split 折叠
|
||||
|
||||
### 完成标准
|
||||
|
||||
- tab 可从一个 stack 拖到另一个 stack。
|
||||
- 可通过 `left/right/top/bottom/center` 形成新布局。
|
||||
- 交互有实时 preview。
|
||||
|
||||
## Phase E:持久化、回归与测试体系补齐
|
||||
|
||||
### 目标
|
||||
|
||||
把新 docking 结构正式纳入 `tests/UI/Editor` 的标准回归。
|
||||
|
||||
### 任务
|
||||
|
||||
- 更新 layout serialization,稳定写回统一 leaf 结构。
|
||||
- 旧布局读取时自动升级。
|
||||
- 补齐 `tests/UI/Editor/unit`:
|
||||
- 旧布局升级
|
||||
- 同 stack reorder
|
||||
- 跨 stack merge
|
||||
- split docking
|
||||
- cleanup collapse
|
||||
- active/selected 同步
|
||||
- persistence round-trip
|
||||
- 补齐 `tests/UI/Editor/integration`:
|
||||
- `shell/dock_header_unified`
|
||||
- `shell/dock_tab_reorder_same_stack`
|
||||
- `shell/dock_tab_move_between_stacks`
|
||||
- `shell/dock_tab_split_targets`
|
||||
- `state/dock_layout_persistence`
|
||||
- 每个集成测试 exe 顶部写清楚当前验证目标,不再只写模糊状态文本。
|
||||
|
||||
### 完成标准
|
||||
|
||||
- `tests/UI/Editor` 对新 docking 具备完整回归入口。
|
||||
- 后续业务面板接入时,不需要再倒回头修基础 docking 架构。
|
||||
|
||||
## 7. 代码落点
|
||||
|
||||
本轮预计主要改动路径:
|
||||
|
||||
- `new_editor/include/XCEditor/Shell/UIEditorWorkspaceModel.h`
|
||||
- `new_editor/src/Shell/UIEditorWorkspaceModel.cpp`
|
||||
- `new_editor/include/XCEditor/Shell/UIEditorWorkspaceController.h`
|
||||
- `new_editor/src/Shell/UIEditorWorkspaceController.cpp`
|
||||
- `new_editor/include/XCEditor/Shell/UIEditorWorkspaceLayoutPersistence.h`
|
||||
- `new_editor/src/Shell/UIEditorWorkspaceLayoutPersistence.cpp`
|
||||
- `new_editor/include/XCEditor/Shell/UIEditorWorkspaceSession.h`
|
||||
- `new_editor/src/Shell/UIEditorWorkspaceSession.cpp`
|
||||
- `new_editor/include/XCEditor/Shell/UIEditorDockHost.h`
|
||||
- `new_editor/src/Shell/UIEditorDockHost.cpp`
|
||||
- `new_editor/include/XCEditor/Shell/UIEditorDockHostInteraction.h`
|
||||
- `new_editor/src/Shell/UIEditorDockHostInteraction.cpp`
|
||||
- `new_editor/include/XCEditor/Collections/UIEditorTabStripInteraction.h`
|
||||
- `new_editor/src/Collections/UIEditorTabStripInteraction.cpp`
|
||||
- `new_editor/include/XCEditor/Shell/UIEditorPanelFrame.h`
|
||||
- `new_editor/src/Shell/UIEditorPanelFrame.cpp`
|
||||
- `new_editor/include/XCEditor/Shell/UIEditorPanelContentHost.h`
|
||||
- `new_editor/src/Shell/UIEditorPanelContentHost.cpp`
|
||||
- `new_editor/app/Shell/ProductShellAsset.cpp`
|
||||
- `tests/UI/Editor/unit/*dock*`
|
||||
- `tests/UI/Editor/unit/*workspace*`
|
||||
- `tests/UI/Editor/integration/shell/*dock*`
|
||||
- `tests/UI/Editor/integration/state/layout_persistence/*`
|
||||
|
||||
## 8. 并行拆分建议
|
||||
|
||||
这轮改造可以拆成 4 条可并行子线,但必须按主从顺序集成:
|
||||
|
||||
1. `WorkspaceModel / Controller / Persistence`
|
||||
2. `DockHost layout / render / hit-test 统一`
|
||||
3. `TabStripInteraction / DockHostInteraction` 拖拽状态机
|
||||
4. `tests/UI/Editor` 单元与集成回归补齐
|
||||
|
||||
并行原则:
|
||||
|
||||
- 先以 `Phase A` 的统一 leaf 语义为总前提。
|
||||
- `Phase B` 与 `Phase C` 可以在统一模型落定后并行推进。
|
||||
- `Phase E` 可以在 `Phase C / D` 功能接口稳定后并行补齐。
|
||||
|
||||
## 9. 风险与控制
|
||||
|
||||
## 9.1 最大风险
|
||||
|
||||
- 旧布局兼容被打断
|
||||
- 统一叶子后现有 panel body 定位错位
|
||||
- 拖拽状态机与 focus/capture 冲突
|
||||
- split tree surgery 产生退化树或悬空 active panel
|
||||
|
||||
## 9.2 控制方式
|
||||
|
||||
- 先做模型统一,再做交互,不反过来堆补丁
|
||||
- 每个 mutation 先补 `unit` 再补 `integration`
|
||||
- 任何旧布局兼容问题都在 persistence 层处理,不在渲染层写兼容分叉
|
||||
- 任何单面板特殊视觉都回收为单-tab stack,不再恢复 standalone panel 路径
|
||||
|
||||
## 10. 收口判定
|
||||
|
||||
只有同时满足以下条件,才算这轮 dock 基础层真正收口:
|
||||
|
||||
1. 所有 dock 叶子统一为 `TabStackNode`。
|
||||
2. `Hierarchy / Inspector` 与 `Scene / Game / Console / Project` 头部视觉完全统一。
|
||||
3. tab 可同组重排、跨组合并、左右上下停靠。
|
||||
4. 拖拽过程有稳定 preview,释放后结果正确。
|
||||
5. 布局可持久化,旧布局可升级。
|
||||
6. `tests/UI/Editor/unit + integration` 已覆盖关键回归。
|
||||
|
||||
在这 6 条完成前,不进入下一轮业务面板重建。
|
||||
@@ -1,144 +0,0 @@
|
||||
# 毕设第四五六章重构计划
|
||||
|
||||
## 1. 重构背景
|
||||
|
||||
当前论文第一、二、三、七章的主线已经基本明确:
|
||||
|
||||
1. 课题主体是渲染引擎,而不是孤立的体积渲染 demo。
|
||||
2. 第三章负责体积渲染理论基础,应当服务于第七章的实现分析。
|
||||
3. 第七章已经明确采用“体积渲染已正式接入当前引擎”的写法,不再保留原型验证叙事。
|
||||
|
||||
在这一前提下,第四、五、六章仍存在章节边界不够清晰、局部重复、个别表述与第七章不一致等问题,需要统一重构。
|
||||
|
||||
## 2. 重构目标
|
||||
|
||||
本轮重构的目标不是简单润色,而是完成以下结构性调整:
|
||||
|
||||
1. 让第四章只承担“总体架构说明”的职责,不再混入过多实现细节,也不再保留与第七章冲突的旧叙事。
|
||||
2. 让第五章只承担“运行时核心模块设计与实现”的职责,内部顺序符合工程逻辑,避免前后倒置。
|
||||
3. 让第六章从“面板介绍”转向“工作流与验证平台”叙事,更符合工程设计类毕设口径。
|
||||
4. 保证第四、五、六章与第一、二、三、七章在术语、定位、时间状态和叙述重心上保持一致。
|
||||
|
||||
## 3. 当前主要问题
|
||||
|
||||
### 3.1 第四章问题
|
||||
|
||||
1. 4.4 仍将体积渲染写成“独立原型后续并入主链”的状态,与第七章“当前正式接入实现”冲突。
|
||||
2. 4.3 标题为“模块协同与数据流”,但正文偏概括,链路感不够强,容易显得空泛。
|
||||
3. 4.1 设计目标过薄,没有把架构设计目标明确拆解出来。
|
||||
|
||||
### 3.2 第五章问题
|
||||
|
||||
1. 5.4 渲染主链放在 5.5 模型、材质、着色器之前,阅读顺序存在倒置。
|
||||
2. 5.6.3 已经偏向测试与验证内容,章节职责与第八章有潜在重叠。
|
||||
3. 个别段落仍偏“模块罗列”,需要强化“为什么这样组织、它在引擎里解决什么问题”的表达。
|
||||
|
||||
### 3.3 第六章问题
|
||||
|
||||
1. 当前结构仍偏“编辑器有哪些面板”,工作流主线不够突出。
|
||||
2. 6.2 与 6.4 在面板联动、对象选择等内容上存在一定重复。
|
||||
3. 6.5.3 同时塞入脚本程序集、Inspector 检查和 Console 调试,边界不够清楚。
|
||||
|
||||
## 4. 重构后的章节职责
|
||||
|
||||
### 4.1 第四章职责
|
||||
|
||||
第四章负责回答两个问题:
|
||||
|
||||
1. 当前渲染引擎整体如何分层、如何划分核心模块。
|
||||
2. 体积渲染模块在这一总体架构中处于什么位置、依赖哪些已有能力。
|
||||
|
||||
本章不负责展开具体模块实现细节,不负责展示详细测试结果,也不再保留“未来并入”的历史性表述。
|
||||
|
||||
### 4.2 第五章职责
|
||||
|
||||
第五章负责回答:
|
||||
|
||||
1. 运行时核心模块分别如何设计与实现。
|
||||
2. 这些模块如何共同构成当前渲染引擎主体能力。
|
||||
|
||||
本章重点是运行时主体,不再把编辑器工作流和实验验证大量混入本章。
|
||||
|
||||
### 4.3 第六章职责
|
||||
|
||||
第六章负责回答:
|
||||
|
||||
1. 编辑器如何作为引擎的统一工作界面存在。
|
||||
2. 编辑器如何支撑场景编辑、资源浏览、脚本工作流、运行验证和调试输出。
|
||||
|
||||
本章重点不是罗列界面元素,而是强调编辑器如何把资源系统、场景系统、渲染系统和脚本系统连接成可操作、可验证的工程闭环。
|
||||
|
||||
## 5. 具体改动方案
|
||||
|
||||
### 5.1 第四章改动方案
|
||||
|
||||
计划保留五节结构,但重写其中两处重点内容:
|
||||
|
||||
1. 4.1 扩写为更明确的三项目标表达:
|
||||
- 建立统一的底层图形抽象与运行环境;
|
||||
- 建立资源、场景到渲染的完整组织路径;
|
||||
- 为脚本、编辑器与高级渲染特性接入预留稳定扩展边界。
|
||||
2. 4.3 从“泛概述”调整为“主链路说明”:
|
||||
- 资源导入链路;
|
||||
- 场景到渲染数据提取链路;
|
||||
- 编辑器视口接入链路;
|
||||
- 脚本驱动场景更新链路。
|
||||
3. 4.4 改写为“当前体积渲染模块在总体架构中的接入位置”,删除“独立原型”“后续并入主链”等与当前状态不一致的表述。
|
||||
|
||||
### 5.2 第五章改动方案
|
||||
|
||||
第五章重构后采用如下顺序:
|
||||
|
||||
1. 5.1 RHI 抽象层设计与实现
|
||||
2. 5.2 资源系统设计与实现
|
||||
3. 5.3 场景与组件系统设计与实现
|
||||
4. 5.4 模型、材质与着色器系统
|
||||
5. 5.5 渲染主链设计与实现
|
||||
6. 5.6 多光源与简单阴影实现
|
||||
7. 5.7 C# 脚本系统设计与实现
|
||||
8. 5.8 本章小结
|
||||
|
||||
对应处理如下:
|
||||
|
||||
1. 将当前“5.5 模型、材质与着色器系统”整体提前到“渲染主链”之前。
|
||||
2. 将当前“5.4 渲染主链设计与实现”整体后移为新 5.5,并检查与前文衔接语句。
|
||||
3. 压缩或删除 5.6.3 中偏测试展示的内容,避免与实验结果章重复。
|
||||
4. 检查 5.1、5.2、5.3、5.4、5.5 之间是否存在概念重复,必要时对过于泛化的段落做收束。
|
||||
|
||||
### 5.3 第六章改动方案
|
||||
|
||||
第六章重构后采用如下结构:
|
||||
|
||||
1. 6.1 编辑器在引擎中的定位与整体界面
|
||||
2. 6.2 Scene 与 Game 双视口实现
|
||||
3. 6.3 场景编辑交互与辅助显示
|
||||
4. 6.4 资源与脚本工作流支撑
|
||||
5. 6.5 运行控制与调试支撑
|
||||
6. 6.6 本章小结
|
||||
|
||||
对应处理如下:
|
||||
|
||||
1. 将当前 6.1 与 6.2.1 中的整体界面内容适度合并,使“定位”和“界面”一起建立认知。
|
||||
2. 保留双视口作为单独一节,突出其工程意义和与渲染主链的一致性。
|
||||
3. 将对象选择、Gizmo、辅助显示统一放入“场景编辑交互”。
|
||||
4. 将 Project、SceneManager、脚本程序集重载等内容放入“资源与脚本工作流”。
|
||||
5. 将 Play 控制、Console 调试等内容整理为“运行控制与调试支撑”,避免与 6.4 混写。
|
||||
|
||||
## 6. 执行顺序
|
||||
|
||||
本轮具体执行顺序如下:
|
||||
|
||||
1. 先改第四章,统一全文架构基线。
|
||||
2. 再改第五章,调整运行时模块顺序并清理章节职责。
|
||||
3. 最后改第六章,按工作流视角重组编辑器部分。
|
||||
4. 修改完成后通读第四至第七章,检查是否仍存在前后冲突表述。
|
||||
|
||||
## 7. 重构完成后的检查标准
|
||||
|
||||
重构完成后,应满足以下标准:
|
||||
|
||||
1. 第四章不再出现与第七章冲突的体积渲染状态描述。
|
||||
2. 第五章内部顺序符合“资源表达先于主链执行”的工程逻辑。
|
||||
3. 第六章能够体现编辑器作为工程工作界面与验证平台的定位,而不是简单面板罗列。
|
||||
4. 第四、五、六、七章之间不存在明显重复和职责混乱。
|
||||
5. 章节标题与正文内容一一对应,导师可以快速复述每章在全文中的作用。
|
||||
Reference in New Issue
Block a user