docs: archive old plans

This commit is contained in:
2026-04-17 22:43:27 +08:00
parent a10d1d80b0
commit ed9b5178f8
30 changed files with 356 additions and 227 deletions

View File

@@ -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”这条路是通的。

View File

@@ -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`,确认是否已经收口,再决定是否继续接下一块。

View File

@@ -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`
### 协作验收
- 每个阶段完成后立即提交推送。
- 任务板状态同步更新,避免重复领取。

View File

@@ -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 CRendering 目录结构归位
- 把所有错位的顶层 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`
只有在上一阶段已经提交推送后,才进入下一阶段。

View File

@@ -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/**`

View File

@@ -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` 相关头文件;真正执行重构时优先选择干净路径,避免和其他会话冲突
- 如果某个任务块执行过程中发现真实源码再次变动,应先回到本任务板更新状态,不要硬做

View File

@@ -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/**` 再发生结构变动,应直接基于当前树增量同步,不要回退到“先补目录骨架”的阶段。

View File

@@ -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. 继续清理旧树里的历史空目录、重复入口和剩余结构噪音。

View File

@@ -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 5RT-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. 阶段完成后及时推送,避免大堆积

View File

@@ -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 重构稳定后,再补组件字段的可视化选择器。

View File

@@ -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 内部堆逻辑的旧路线。

View File

@@ -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 1bias 设置正式化并接入 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 阴影才算真正脱离“占位实现”。

View File

@@ -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 1Model实例化基础链路
目标:
-`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 3Genshin 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 基础色是否进一步收敛

View File

@@ -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. 阶段 BXCEditor 库层热点拆分收口
### 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 的产品工作流迁移
在这之前,所有主线工作都应服务于“收结构债”,而不是继续发散。

View File

@@ -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 整理成一个真正可扩展的内核。`

View File

@@ -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. 工作包拆分
## 工作包 Arequest / 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 的边界可以一句话说清
## 工作包 Bscene 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 时,不需要再发明第二套“可见对象数组解释逻辑”
## 工作包 Cpipeline 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 的边界清楚
## 工作包 DBuiltinForwardPipeline 瘦身
目标:
`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
## 工作包 Eeditor 注入点正式化
目标:
保留当前 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` 才会接得稳。

View File

@@ -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。

View File

@@ -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 2source 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 风格模型工作流”。

View File

@@ -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 主链正式接入计划”

View File

@@ -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 功能

View File

@@ -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 手感继续改善。
## 阶段 6viewport 生命周期收口
### 目标
让 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 窗口合成进一步分离。

View File

@@ -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. 阶段 Bhit-test / resize 手势
3. 阶段 C应用驱动 resize 主链
4. 阶段 Dviewport 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。

View File

@@ -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 的分层参考资料,后续迁移时仍需频繁对照。

View File

@@ -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. 分阶段执行
## 阶段 ARender Graph Core
目标:
- 建立 graph 基础数据结构和最小编译/执行器
交付:
- pass/resource/handle/builder/compiler/executor
- 支持 imported + transient texture
- 支持 raster + compute pass
验收:
- 有独立 unit tests
- 能构造最小 graph 并正确执行顺序与 barrier
## 阶段 BCamera 级资源流 graph 化
目标:
- 把 post-process / final output / object id / overlay 的中间 surface 手工管理替成 graph
交付:
- `CameraRenderer` 开始 build graph
- `FullscreenPassSurfaceCache` 职责收缩
验收:
- 现有 viewport / object id / final color 路径不回退
## 阶段 CBuiltin Forward Main Scene graph 化
目标:
- 把 main scene 从手工 frame 执行切到 graph raster pass
交付:
- opaque / skybox / transparent 作为 graph pass 注册
- forward scene 仍保留当前 renderer list / draw settings 逻辑
验收:
- 当前 forward 主链功能不回退
- `BuiltinForwardPipeline` 不再继续持有整帧调度职责
## 阶段 DFeature 注入 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 才有真正稳定的底座。

View File

@@ -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 contractfeature 就没有宿主
- 没有 feature contractURP-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`
顺序才是对的。

View File

@@ -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 / passnative 侧负责承载与执行”的正式宿主层。
### 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 firstdeferred later
正确顺序仍然是:
1. `SRP Host v1`
2. `URP-like builtin package`
3. `Deferred renderer`
4. 更复杂的 feature 生态

View File

@@ -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

View File

@@ -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 条完成前,不进入下一轮业务面板重建。

View File

@@ -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. 章节标题与正文内容一一对应,导师可以快速复述每章在全文中的作用。