docs: sync api and planning docs

This commit is contained in:
2026-04-08 16:07:03 +08:00
parent 08c3278e10
commit 31756847ab
1826 changed files with 44502 additions and 29645 deletions

View File

@@ -0,0 +1,776 @@
# API文档实时同步任务池2026-04-03第三轮
## 文档定位
这份任务池接替已归档的第二轮计划:
- `docs/plan/used/API文档实时同步任务池_2026-04-03_第二轮归档.md`
前两轮已经完成的重点包括:
- canonical API 目录结构收口
- 大批缺页补齐
- 多轮模板页清理与内容重写
- 结构层审计修复到全绿
第三轮不再以“结构补齐”为主,而是专门处理“源码/测试已经变化,但 API 文档内容还没有跟上”的增量漂移。
## 当前复核快照
- 最近一次结构审计时间:`2026-04-07 01:26:32`
- 审计命令:`python -B docs/api/_tools/audit_api_docs.py`
- 当前结果:
- `Public headers: 304`
- `Editor source headers: 142`
- `Valid header refs (canonical): 304`
- `Invalid header refs: 0`
- `Invalid source refs: 0`
- `Valid source refs (Editor canonical): 142`
- `Broken .md links: 0`
- `Missing directory index pages: 0`
- `Stale canonical doc tokens: 0`
- `Stale editor doc tokens: 0`
- `Stale editor canonical pages: 0`
这说明当前 canonical public header 覆盖与全部 Editor source-backed API 都已恢复全绿;此前集中在 `engine/include/XCEngine/UI/**` 的缺口已经收口完成。
### 已复核、暂不新开任务的区域
- `Resources/Material` / `RenderMaterialUtility` / `BuiltinForwardPipeline`
- `Components/MeshFilterComponent` / `MeshRendererComponent`
- `Scene` 中 builtin mesh / material 路径 round-trip
- `Components/GameObject` 辅助访问器与层级辅助页
这些区域本轮已对照当前源码和测试抽查,暂时没有发现新的明确失配。
## 认领规则
- 一次只认领 `1` 个任务块。
- 先把 `状态` 改成 `DOING`,再写 `认领人`
- 只允许修改自己任务块声明的 `写入范围`
- 所有改动都必须基于“当前头文件 + 当前实现 + 当前测试 + 当前真实调用链”。
- 如果需要同步 `_guides` 或模块总览页,必须在对应任务块内明确列出,避免多人撞写。
- 做完后必须补一次最小复核,至少确认相关链接和交叉引用没有坏掉。
## 任务池
## T01 Core / Asset `AssetDatabase` 显式重导入接口补页
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P0`
- 写入范围:
- `docs/api/XCEngine/Core/Asset/AssetDatabase/**`
- 主要源码依据:
- `engine/include/XCEngine/Core/Asset/AssetDatabase.h`
- `engine/src/Core/Asset/AssetDatabase.cpp`
- `tests/Core/Asset/test_resource_manager.cpp`
- 已确认问题:
- 头文件已新增 `TryGetImportableResourceType()``ReimportAsset()``ReimportAllAssets()`,但 canonical 目录下没有对应方法页。
- `AssetDatabase.md` 的公开方法表仍停在旧集合,没有把“可导入类型探测 / 单资产重导入 / 批量重导入”纳入公开能力。
- `kCurrentImporterVersion` 已升到 `5`,总览页需要同步当前 importer 版本口径。
- 产出要求:
- 新增 `TryGetImportableResourceType.md``ReimportAsset.md``ReimportAllAssets.md`
- 更新 `AssetDatabase.md`,必要时同步 `ResolvedAsset.md` 的交叉引用。
- 文档必须写清以下真实边界:
- 只接受项目 `Assets/...` 内、存在且非目录的 source asset。
- `TryGetImportableResourceType()` 只返回当前 importer 的 primary `ResourceType``Unknown` 直接失败。
- `ReimportAsset()` 会重建单个 artifact、更新 source/artifact DB并返回可直接消费的 `ResolvedAsset`
- `ReimportAllAssets()` 会遍历全部可导入 source record单个条目失败不会中断全量循环但最终返回总体成功位。
## T02 Core / Asset `AssetImportService` Library 工具接口与 `ImportedAsset` 语义同步
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P0`
- 写入范围:
- `docs/api/XCEngine/Core/Asset/AssetImportService/**`
- 主要源码依据:
- `engine/include/XCEngine/Core/Asset/AssetImportService.h`
- `engine/src/Core/Asset/AssetImportService.cpp`
- `tests/Core/Asset/test_resource_manager.cpp`
- 已确认问题:
- 缺少 `ClearLibraryCache.md``ReimportAllAssets.md``ReimportAsset.md``TryGetImportableResourceType.md`
- `AssetImportService.md` 还没有把这批显式工具接口纳入生命周期和能力说明。
- `ImportedAsset` 页虽然已存在,但需要按当前 `ConvertResolvedAsset()` 口径复核 `runtimeLoadPath``artifactDirectory``mainLocalID` 和成功路径语义。
- 产出要求:
- 新增缺失方法页,并更新 `AssetImportService.md`、必要时同步 `ImportedAsset.md``EnsureArtifact.md`
- 文档必须写清以下真实边界:
- `ClearLibraryCache()` 会关停数据库、删除整个 `Library` 目录、再重新初始化;它本身不会批量重导入所有资产。
- `RebuildLibraryCache()` 等于 `ClearLibraryCache() + ReimportAllAssets()`
- `ReimportAsset()` 会先 `Refresh()`,再强制重导入指定路径,返回 `ImportedAsset`
- `TryGetImportableResourceType()` 只是服务层转发;项目根无效时必须返回失败并把输出设为 `Unknown`
- `AssetImportService_Test.RebuildLibraryCacheKeepsStableAssetRefs` 证明:重建 `Library` 不应破坏现有 `.meta` 驱动的稳定 `AssetRef`
## T03 Core / Asset `ResourceManager` 项目资产工具入口同步
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P0`
- 写入范围:
- `docs/api/XCEngine/Core/Asset/ResourceManager/**`
- 主要源码依据:
- `engine/include/XCEngine/Core/Asset/ResourceManager.h`
- `engine/src/Core/Asset/ResourceManager.cpp`
- `tests/Core/Asset/test_resource_manager.cpp`
- 已确认问题:
- 缺少 `CanReimportProjectAsset.md``ReimportProjectAsset.md``ClearProjectLibraryCache.md`
- `ResourceManager.md` 还没有覆盖当前项目资产工具入口,也没有把这些接口和 `UnloadAll()` / `ProjectAssetIndex::RefreshFrom()` 的关系写清。
- `RebuildProjectAssetCache.md``GetProjectLibraryRoot.md` 需要和新接口形成正确对比与交叉链接。
- 产出要求:
- 新增缺失方法页,更新 `ResourceManager.md`,必要时补交叉链接。
- 文档必须写清以下真实边界:
- 这批接口都要求 `m_resourceRoot` 非空;否则直接失败。
- `CanReimportProjectAsset()` 只做“当前路径是否可导入”的无副作用判断。
- `ReimportProjectAsset()` 会先 `UnloadAll()`,再重导入单路径资产,随后刷新 `ProjectAssetIndex`,成功时补记 `RememberResolvedPath(...)`
- `ClearProjectLibraryCache()` 会先卸载运行时资源,再清空 `Library`,然后刷新 snapshot但不会自动批量重导入。
- `ResourceManager_Test.ReimportProjectAssetBuildsArtifactForSelectedPath``RebuildProjectAssetCacheRefreshesLookupState` 是当前最直接的行为锚点。
## T04 Scripting / Mono `[SerializeField] private` 字段发现与持久化语义同步
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P0`
- 写入范围:
- `docs/api/XCEngine/Scripting/Mono/Mono.md`
- `docs/api/XCEngine/Scripting/Mono/MonoScriptRuntime/**`
- `docs/api/_guides/Scripting/Scripting-Runtime-And-Field-Model.md`
- `docs/api/_guides/Scripting/Project-Script-Assembly-And-Field-Sync.md`
- 主要源码依据:
- `engine/include/XCEngine/Scripting/Mono/MonoScriptRuntime.h`
- `engine/src/Scripting/Mono/MonoScriptRuntime.cpp`
- `managed/XCEngine.ScriptCore/SerializeField.cs`
- `managed/GameScripts/FieldMetadataProbe.cs`
- `managed/GameScripts/SerializeFieldProbe.cs`
- `tests/Scripting/test_mono_script_runtime.cpp`
- `tests/Scripting/test_project_script_assembly.cpp`
- 已确认问题:
- `Mono.md``TryGetClassFieldMetadata.md`、两篇 scripting guide 仍在沿用“只收录 public 实例字段”的旧口径。
- 当前真实实现已经变成:
- 过滤掉 `static` / `literal` / `init-only`
- 然后接受“public 字段”或“标了 `[SerializeField]` 的 private 字段”
- 最后再按支持类型过滤
- 测试已经明确覆盖 `HiddenFlag``HiddenCounter``HiddenEnabled` 这类 `[SerializeField] private` 字段的元数据发现、默认值读取、运行时写回与场景 round-trip。
- 未标 `[SerializeField]` 的 private 字段仍应保持忽略,但当前文档没有把这条边界讲清。
- 产出要求:
- 至少同步 `Mono.md``MonoScriptRuntime.md``TryGetClassFieldMetadata.md``TryGetClassFieldDefaultValues.md`
- 两篇 guide 需要补上 Unity 风格设计解释:
- 为什么支持 `[SerializeField] private`
- 这样做对 Inspector、字段持久化、重构安全性有什么好处
- 哪些 private 字段仍不会进序列化层
- 文档必须明确当前排除项:
- `static`
- `const/literal`
- `readonly/init-only`
- 不支持的字段类型
- 未标 `[SerializeField]` 的 private 字段
## T05 Editor / Viewport `SceneViewportOverlayBuilder` provider-registry 口径同步
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P1`
- 写入范围:
- `docs/api/XCEngine/Editor/Viewport/SceneViewportOverlayBuilder/**`
- `docs/api/XCEngine/Editor/Viewport/Viewport.md`
- `docs/api/XCEngine/Editor/Viewport/ViewportHostService/**`
- 主要源码依据:
- `editor/src/Viewport/SceneViewportOverlayBuilder.h`
- `editor/src/Viewport/SceneViewportOverlayBuilder.cpp`
- `editor/src/Viewport/SceneViewportOverlayProviders.h`
- `editor/src/Viewport/SceneViewportOverlayProviders.cpp`
- `editor/src/Viewport/ViewportHostService.h`
- `tests/Editor/test_scene_viewport_overlay_providers.cpp`
- 已确认问题:
- `SceneViewportOverlayBuilder.md``Build.md` 仍沿用旧版“静态 / 无状态 / 单体 builder”口径没有同步当前实例 builder + provider registry 模型。
- `SceneViewportOverlayBuilder` 目录缺少 `Constructor.md``GetProviderRegistry.md`,导致新公开入口没有 canonical 页面。
- `Viewport.md``ViewportHostService.md``SceneView-Overlay-Frame-Data.md` 仍把基础 editor overlay 的来源写成 `SceneViewportOverlayBuilder::Build(...)`,没有同步宿主当前持有成员 `m_sceneViewportOverlayBuilder` 且默认聚合 camera / light provider 的事实。
- 完成记录:
- 已重写 `SceneViewportOverlayBuilder.md``Build.md`,改成当前实例 builder + registry 分发语义。
- 已新增 `Constructor.md``GetProviderRegistry.md`
- 已同步 `Viewport.md``ViewportHostService.md``SceneView-Overlay-Frame-Data.md` 的上层调用链表述。
- 已重新运行 `python -B docs/api/_tools/audit_api_docs.py`,并确认 `Broken .md links: 0``Stale editor doc tokens: 0``Stale editor canonical pages: 0`
## T06 Editor / Viewport HUD / interaction-actions / canonical overlay-state 口径同步
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P1`
- 写入范围:
- `docs/api/XCEngine/Editor/Viewport/Viewport.md`
- `docs/api/XCEngine/Editor/Viewport/IViewportHostService/**`
- `docs/api/XCEngine/Editor/Viewport/ViewportHostService/**`
- `docs/api/XCEngine/Editor/Viewport/SceneViewportHudOverlay/**`
- `docs/api/XCEngine/Editor/Viewport/SceneViewportInteractionResolver/**`
- `docs/api/XCEngine/Editor/Viewport/SceneViewportInteractionActions/**`
- `docs/api/XCEngine/Editor/Viewport/SceneViewportTransformGizmoCoordinator/**`
- `docs/api/XCEngine/Editor/Viewport/SceneViewportOverlayBuilder/**`
- `docs/api/XCEngine/Editor/Viewport/SceneViewportOverlayProviders/**`
- `docs/api/XCEngine/Editor/Viewport/SceneViewportEditorOverlayData/**`
- `docs/api/XCEngine/Editor/Viewport/SceneViewportOverlayHitTester/**`
- `docs/api/XCEngine/Editor/Viewport/Passes/SceneViewportEditorOverlayPass/**`
- `docs/api/XCEngine/Editor/panels/SceneViewPanel/**`
- `docs/api/XCEngine/Editor/Viewport/SceneViewportOverlayHandleBuilder/**`
- `docs/api/XCEngine/Editor/Viewport/SceneViewportMoveGizmo/**`
- `docs/api/XCEngine/Editor/Viewport/SceneViewportRotateGizmo/**`
- `docs/api/XCEngine/Editor/Viewport/SceneViewportScaleGizmo/**`
- 主要源码依据:
- `editor/src/Viewport/SceneViewportHudOverlay.h`
- `editor/src/Viewport/SceneViewportHudOverlay.cpp`
- `editor/src/Viewport/SceneViewportInteractionResolver.h`
- `editor/src/Viewport/SceneViewportInteractionResolver.cpp`
- `editor/src/Viewport/SceneViewportInteractionActions.h`
- `editor/src/Viewport/SceneViewportInteractionActions.cpp`
- `editor/src/Viewport/SceneViewportTransformGizmoCoordinator.h`
- `editor/src/Viewport/SceneViewportTransformGizmoCoordinator.cpp`
- `editor/src/Viewport/IViewportHostService.h`
- `editor/src/Viewport/ViewportHostService.h`
- `editor/src/Viewport/SceneViewportOverlayBuilder.h`
- `editor/src/Viewport/SceneViewportOverlayProviders.h`
- `editor/src/Viewport/SceneViewportOverlayProviders.cpp`
- `editor/src/Panels/SceneViewPanel.cpp`
- `editor/src/Viewport/SceneViewportOverlayHandleBuilder.h`
- `editor/src/Viewport/SceneViewportMoveGizmo.h`
- `editor/src/Viewport/SceneViewportRotateGizmo.h`
- `editor/src/Viewport/SceneViewportScaleGizmo.h`
- `tests/Editor/test_scene_viewport_interaction_actions.cpp`
- `tests/Editor/test_scene_viewport_transform_gizmo_coordinator.cpp`
- `tests/Editor/test_scene_viewport_interaction_resolver.cpp`
- `tests/Editor/test_scene_viewport_overlay_providers.cpp`
- 已确认问题:
- `IViewportHostService` / `ViewportHostService` / `SceneViewPanel` 文档仍在使用 `GetSceneViewInteractionOverlayFrameData(...)``SetSceneViewTransientTransformGizmoOverlayData(...)` 的旧双轨口径,但当前真实接口只剩 `SetSceneViewTransformGizmoOverlayState(...)` + `GetSceneViewEditorOverlayFrameData(...)`
- `SceneViewportOverlayBuilder` / `SceneViewportOverlayProviders` 文档没有同步当前 optional `transformGizmoOverlayState``CreateSceneViewportTransformGizmoOverlayProvider()`,以及默认 registry 已注册 camera / light / transform gizmo provider 的事实。
- `SceneViewportEditorOverlayData` / `SceneViewportEditorOverlayPass` / `SceneViewportOverlayHitTester` 文档仍把 canonical frame 当成“仅世界线和图标”,没有同步 `screenTriangles``handleRecords` 已并入统一 frame data。
- 缺少 `SceneViewportInteractionActions.h` 的 canonical 目录,导致交互动作规范层没有文档入口。
- 缺少 `SceneViewportTransformGizmoCoordinator.h` 的 canonical 目录,且 `SceneViewPanel` 文档没有同步当前 overlay submission / lifecycle command helper 链路。
- move / rotate / scale gizmo 的 draw-data 与 state-query 页面仍在传播“面板直接把 `GetDrawData()` 变成临时 render overlay”的旧口径未同步统一 gizmo state + provider 模式。
- 完成记录:
- 已新增 `SceneViewportInteractionActions/**`,补齐 hover-state / click-action / dispatch API 页面。
- 已新增 `SceneViewportTransformGizmoCoordinator/**`,补齐 overlay submission 与 gizmo lifecycle command 页面。
- 已重写 `Viewport.md``IViewportHostService/**``ViewportHostService/**``SceneViewPanel/**`,统一到当前 `SetSceneViewTransformGizmoOverlayState(...)` + canonical `SceneViewportOverlayFrameData` 链路。
- 已同步 `SceneViewportOverlayBuilder/**``SceneViewportOverlayProviders/**``SceneViewportEditorOverlayData/**``SceneViewportOverlayHitTester/**``SceneViewportEditorOverlayPass/**` 到当前 provider-registry + 统一 gizmo state 架构。
- 已同步 move / rotate / scale gizmo 的 draw-data / state-query 页面到当前统一 state 消费口径。
- 已重新运行 `python -B docs/api/_tools/audit_api_docs.py`,结果为:`Valid source refs (Editor canonical): 129``Invalid header refs: 0``Invalid source refs: 0``Broken .md links: 0``Stale editor canonical pages: 0`
## T07 Scripting guide / 项目脚本程序集测试输出目录口径修正
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P1`
- 写入范围:
- `docs/api/_guides/Scripting/Project-Script-Assembly-And-Field-Sync.md`
- 主要源码依据:
- `managed/CMakeLists.txt`
- `tests/Scripting/CMakeLists.txt`
- `tests/Scripting/test_project_script_assembly.cpp`
- 已确认问题:
- guide 仍把 `tests/Scripting/test_project_script_assembly.cpp` 描述成“直接把 `assemblyDirectory` 指向 `project/Library/ScriptAssemblies`”。
- 当前真实测试口径已经改成优先使用 `XCENGINE_TEST_PROJECT_MANAGED_OUTPUT_DIR`,由 `xcengine_test_project_managed_assemblies` target 提供测试专用输出目录;未配置时 fallback 到 `build/managed/ProjectScriptAssemblies`
- `project/Library/ScriptAssemblies/` 仍是 editor/runtime 项目程序集的真实输出目录,但它和测试专用输出目录不能混写成同一个概念。
- 完成记录:
- 已改写 `Project-Script-Assembly-And-Field-Sync.md`,把“真实项目输出目录”和“测试专用输出目录”拆开描述。
- 已明确 `test_project_script_assembly.cpp` 验证的是“项目 `Assets/**/*.cs` 被编译成可发现的 `GameScripts.dll`”这条链路,而不是直接依赖工作树里的 `project/Library/ScriptAssemblies/` 快照。
- 已重新运行 `python -B docs/api/_tools/audit_api_docs.py`,结果为:`Public headers: 244``Editor source headers: 129``Broken .md links: 0``Stale canonical doc tokens: 0``Stale editor canonical pages: 0`
## T08 Rendering / `RenderMaterialUtility` builtin-pass 元数据与资源绑定契约补页
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P1`
- 写入范围:
- `docs/api/XCEngine/Rendering/RenderMaterialUtility/**`
- `docs/api/XCEngine/Rendering/Pipelines/BuiltinForwardPipeline/**`
- `docs/api/XCEngine/Rendering/Passes/BuiltinObjectIdPass/**`
- 主要源码依据:
- `engine/include/XCEngine/Rendering/RenderMaterialUtility.h`
- `engine/src/Rendering/Pipelines/BuiltinForwardPipeline.cpp`
- `engine/src/Rendering/Passes/BuiltinObjectIdPass.cpp`
- `tests/Rendering/unit/test_builtin_forward_pipeline.cpp`
- `tests/Rendering/unit/test_render_scene_extractor.cpp`
- 已确认问题:
- `RenderMaterialUtility.h` 当前已经公开 `BuiltinMaterialPass`、binding-plan struct、legacy fallback 绑定构造和 builtin pass 元数据匹配 helper但 canonical 文档树仍只覆盖旧的材质解析 / render-state 子集。
- `MaterialConstantPayloadView``ResolveSchemaMaterialConstantPayload()` 文档仍停留在“只有 `data + size`”的旧口径,没有同步当前 `layout` 视图和 `layout.size == size` 的有效性约束。
- `BuiltinForwardPipeline``BuiltinObjectIdPass` 文档虽然已经写到 explicit resource contract但还没有把 canonical 入口回链到 `RenderMaterialUtility` 的 binding-plan helper。
- 完成记录:
- 已新增 builtin pass 元数据 / 资源绑定契约页面,覆盖 `BuiltinMaterialPass``BuiltinPassResourceBindingPlan``TryBuildBuiltinPassResourceBindingPlan()`、legacy fallback 绑定构造与 shader-pass 元数据匹配 helper。
- 已新增 `MaterialConstantLayoutView.md``FindShaderPropertyBySemantic.md`,并同步 `MaterialConstantPayloadView.md``ResolveSchemaMaterialConstantPayload.md` 到当前 layout-aware 语义。
- 已重写 `RenderMaterialUtility.md` 的公开类型 / 函数索引,把 builtin pass 规范化与 binding-plan 契约纳入模块总览。
- 已同步 `BuiltinForwardPipeline.md``BuiltinObjectIdPass.md` 到当前 explicit binding-plan + legacy fallback 口径。
## T09 Rendering / `RenderMaterialUtility` 顶层 helper completeness 补页
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P1`
- 写入范围:
- `docs/api/XCEngine/Rendering/RenderMaterialUtility/**`
- 主要源码依据:
- `engine/include/XCEngine/Rendering/RenderMaterialUtility.h`
- `engine/src/Rendering/Pipelines/BuiltinForwardPipeline.cpp`
- `tests/Rendering/unit/test_builtin_forward_pipeline.cpp`
- `tests/Rendering/unit/test_render_scene_extractor.cpp`
- 已确认问题:
- `RenderMaterialUtility.h` 的顶层公开符号里,`IsForwardPassName()` 等 pass-name alias helper、`ToRHI*` 状态映射 helper以及 `MaterialRenderStateHash` 仍无对应 canonical 页面。
- `RenderMaterialUtility.md` 的索引也没有把这批顶层 helper 纳入公开函数 / 类型列表,导致文档目录和实际公开符号仍有一层颗粒度缺口。
- 完成记录:
- 已新增 `IsForwardPassName.md``IsUnlitPassName.md``IsDepthOnlyPassName.md``IsShadowCasterPassName.md``IsObjectIdPassName.md`
- 已新增 `ToRHICullMode.md``ToRHIComparisonFunc.md``ToRHIBlendFactor.md``ToRHIBlendOp.md``MaterialRenderStateHash.md`
- 已同步 `RenderMaterialUtility.md`,把这批 helper 和 hash functor 纳入模块索引。
- 已对照 `RenderMaterialUtility.h` 的顶层公开类型 / 函数名,确认当前 canonical 页已全覆盖。
## T10 Active API docs / 测试路径大小写按真实目录统一
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P1`
- 写入范围:
- `docs/api/_guides/**`
- `docs/api/XCEngine/**`
- 主要源码依据:
- `tests/`
- 已确认问题:
- 活跃文档里曾残留 `tests/core/...``tests/math/...``tests/scripting/...` 这类小写路径。
- 当前工作树真实目录名是 `tests/Core/``tests/Core/Math/``tests/Scripting/`;继续沿用小写写法会让文档和工程现实脱节。
- 这类问题与此前已收口的 `tests/Editor/` 一样,属于 Windows 工作树里最容易被忽略、但会持续制造噪音的路径口径漂移。
- 完成记录:
- 已把活跃 guide 与 canonical API 文档中的 `tests/Core/...``tests/Core/Math/...``tests/Scripting/...` 统一改成真实目录大小写。
- 本轮只收口活跃文档;`docs/plan/used/``docs/used/` 等归档材料继续保留历史写法。
## T11 Editor / Viewport 新增 header helper 补页
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P1`
- 写入范围:
- `docs/api/XCEngine/Editor/Viewport/Viewport.md`
- `docs/api/XCEngine/Editor/Viewport/SceneViewportEditorModes/**`
- `docs/api/XCEngine/Editor/Viewport/SceneViewportInteractionFrame/**`
- `docs/api/XCEngine/Editor/Viewport/SceneViewportNavigation/**`
- `docs/api/_meta/rebuild-status.md`
- 主要源码依据:
- `editor/src/Viewport/SceneViewportEditorModes.h`
- `editor/src/Viewport/SceneViewportInteractionFrame.h`
- `editor/src/Viewport/SceneViewportNavigation.h`
- `editor/src/Panels/SceneViewPanel.cpp`
- 已确认问题:
- 工作树里新增了 `SceneViewportEditorModes.h``SceneViewportInteractionFrame.h``SceneViewportNavigation.h` 三个 editor source header但 canonical 文档树还没有对应目录页。
- `Viewport.md` 也没有把这三块新 helper 纳入当前职责拆分,导致 Scene View 交互装配和导航状态管理的真实入口在模块总览里缺席。
- 完成记录:
- 已新增 `SceneViewportEditorModes/SceneViewportEditorModes.md`,收口 tool / pivot / transform-space 三类模式枚举。
- 已新增 `SceneViewportInteractionFrame/SceneViewportInteractionFrame.md`,补齐 tool state、frame geometry、interaction frame state 与 resolve request 装配语义。
- 已新增 `SceneViewportNavigation/SceneViewportNavigation.md`补齐快捷键、look/pan 导航、capture flags 与 `SceneViewportInput` 构建逻辑。
- 已补齐 `BuildSceneViewportTransformGizmoOverlayState.md`,并重写 `SceneViewPanel/**``SceneViewportOverlayHandleBuilder/**``SceneView-Interaction-And-Gizmo-Model.md` 的残留旧口径。
- 已顺手修复 `BuildSceneViewportGridPassData.md` 指向旧页名的坏链接。
- 已重新运行 `python -B docs/api/_tools/audit_api_docs.py`,确认 `Editor source headers: 133``Valid source refs (Editor canonical): 133``Invalid source refs: 0``Broken .md links: 0`
## T12 Editor / Viewport `SceneViewportInteractionFrame` Phase 5G focus 与 presentation helper 同步
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P1`
- 写入范围:
- `docs/api/XCEngine/Editor/Viewport/SceneViewportInteractionFrame/**`
- `docs/api/XCEngine/Editor/Viewport/SceneViewportNavigation/SceneViewportNavigationUpdate.md`
- `docs/api/XCEngine/Editor/Viewport/Viewport.md`
- `docs/api/XCEngine/Editor/panels/SceneViewPanel/**`
- `docs/api/_meta/rebuild-status.md`
- 主要源码依据:
- `editor/src/Viewport/SceneViewportInteractionFrame.h`
- `editor/src/panels/SceneViewPanel.cpp`
- `tests/Editor/test_scene_viewport_interaction_frame.cpp`
- 已确认问题:
- `SceneViewportInteractionFrame.h` 当前已经新增 `ShouldFocusSceneViewportAfterInteraction()``SceneViewportPresentationRequest``RefreshAndDrawSceneViewportPresentation()`,但 canonical 目录下还没有对应页面,模块总览也仍停在“只做交互前 frame-state 装配”的旧口径。
- `SceneViewportNavigationUpdate.md` 仍写成 `beginLookDrag` / `beginPanDrag` 直接决定 `ImGui::SetWindowFocus()`;当前真实逻辑已经改成由 `ShouldFocusSceneViewportAfterInteraction(...)` 统一折叠 tool command、interaction action 与 navigation begin 标志。
- `Viewport.md``SceneViewPanel/**``SceneViewportInteractionFrame` 的职责描述还没有完整纳入 focus / presentation helper 这一层尾段语义。
- 完成记录:
- 已新增 `ShouldFocusSceneViewportAfterInteraction.md``SceneViewportPresentationRequest.md``RefreshAndDrawSceneViewportPresentation.md`,补齐 `SceneViewportInteractionFrame.h` 的新增公开入口。
- 已重写 `SceneViewportInteractionFrame.md`,把模块职责从“交互前 frame-state 装配”扩展到当前真实的 focus 决策与 presentation 尾段收口语义。
- 已同步 `SceneViewportNavigationUpdate.md``Viewport.md``SceneViewPanel/Render.md``SceneViewPanel.md`,移除 `SetWindowFocus()` / presentation tail 的旧口径描述。
- 已重新运行 `python -B docs/api/_tools/audit_api_docs.py`,确认 `Editor source headers: 133``Valid source refs (Editor canonical): 133``Invalid source refs: 0``Broken .md links: 0``Stale editor canonical pages: 0`
## T13 Editor / Viewport `SceneViewportChrome` 与 `SceneViewPanel` 当前编排链补正
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P1`
- 写入范围:
- `docs/api/XCEngine/Editor/Viewport/SceneViewportChrome/**`
- `docs/api/XCEngine/Editor/panels/SceneViewPanel/**`
- `docs/api/_meta/rebuild-status.md`
- 主要源码依据:
- `editor/src/Viewport/SceneViewportChrome.h`
- `editor/src/Viewport/SceneViewportChrome.cpp`
- `editor/src/panels/SceneViewPanel.h`
- `editor/src/panels/SceneViewPanel.cpp`
- `tests/Editor/test_scene_viewport_chrome.cpp`
- 已确认问题:
- `SceneViewportChrome.md` 仍写成“没有独立单元测试”,但当前工作树已经存在 `tests/Editor/test_scene_viewport_chrome.cpp`,并覆盖工具命令折叠与执行规则。
- `SceneViewPanel.md``Render.md` 仍残留旧的 helper 列表和编排口径没有完整对齐当前真实调用顺序包括工具命令执行、focus 决策以及 `RefreshAndDrawSceneViewportPresentation(...)` 收口。
- 完成记录:
- 已修正 `SceneViewportChrome.md` 的测试锚点描述明确区分“命令折叠规则已有单测”和“UI 绘制细节仍由源码调用链锚定”。
- 已重写 `SceneViewPanel.md``Render.md`,按当前源码同步 `Chrome -> InteractionFrame -> Navigation -> InteractionActions -> Presentation` 的真实编排链。
- 已重新运行 `python -B docs/api/_tools/audit_api_docs.py`,确认 `Editor source headers: 133``Valid source refs (Editor canonical): 133``Invalid source refs: 0``Broken .md links: 0``Stale editor canonical pages: 0`
## T14 Core / Asset `ArtifactFormats` shader artifact 正文布局补页
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P1`
- 写入范围:
- `docs/api/XCEngine/Core/Asset/ArtifactFormats/ArtifactFormats.md`
- `docs/api/_meta/rebuild-status.md`
- 主要源码依据:
- `engine/include/XCEngine/Core/Asset/ArtifactFormats.h`
- `engine/src/Core/Asset/AssetDatabase.cpp`
- `engine/src/Resources/Shader/ShaderLoader.cpp`
- `tests/Resources/Shader/test_shader_loader.cpp`
- 已确认问题:
- `ArtifactFormats.md` 的 shader artifact 小节当前只列出了几种头结构名,没有像 material / mesh 一样写清真实正文布局,缺少 name/source-path 字符串、property 段、per-pass tag/resource/variant 段以及 `compiledBinary` payload 的写入顺序。
- 同页“读取侧”当前漏写了 `.xcshader` 的真实消费者 `ShaderLoader`
- 写入侧对 shader 只写了“产出 shader artifact”没有和当前实现保持同样的主 artifact 文件名口径 `main.xcshader`
- 完成记录:
- 已为 `ArtifactFormats.md` 的 shader artifact 小节补齐当前正文布局,明确名称/路径字符串、property 段、pass tag/resource/variant 段以及 `compiledBinary` payload 的写入顺序。
- 已补充 shader artifact 的 schema 值、`main.xcshader` 主 artifact 文件名,以及读取侧 `ShaderLoader` 的真实消费链。
- 已重新运行 `python -B docs/api/_tools/audit_api_docs.py`,确认 `Public headers: 244``Editor source headers: 133``Invalid header refs: 0``Invalid source refs: 0``Broken .md links: 0``Stale editor canonical pages: 0`
## T15 Resources / Material `Material.h` 公开符号 completeness 补页
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P1`
- 写入范围:
- `docs/api/XCEngine/Resources/Material/Material/**`
- `docs/api/_meta/rebuild-status.md`
- 主要源码依据:
- `engine/include/XCEngine/Resources/Material/Material.h`
- `engine/src/Resources/Material/Material.cpp`
- `tests/Resources/Material/test_material.cpp`
- `tests/Resources/Material/test_material_loader.cpp`
- `tests/Rendering/unit/test_render_scene_extractor.cpp`
- 已确认问题:
- `Material.h` 当前已经公开 `renderQueue / renderState / shaderPass / tags / constant layout / change version` 这一整组运行时接口,但 canonical 文档树仍主要停留在“数值属性 + 纹理绑定”子集,缺少大量类型页与方法页。
- 缺页不仅包括 `SetRenderQueue()``SetRenderState()``SetShaderPass()`、tag API、`GetConstantLayout()``FindConstantField()``GetChangeVersion()``RecalculateMemorySize()`,还包括 `MaterialRenderQueue``MaterialRenderState``MaterialConstantFieldDesc``MaterialTagEntry``PendingTextureLoadState` 等公开类型。
- `Material/Material.md` 的声明索引也没有把这批 render metadata / tag / constant-layout 相关公开符号纳入模块总览。
- 完成记录:
- 已补齐 `Material.h` 当前公开的 render metadata / tag / constant-layout 相关类型页与方法页,并重写 `Material.md` 的模块索引。
- 已把 `renderQueue / renderState / shaderPass / tags / texture bindings / properties / constant layout / change version` 这一整组运行时接口同步到 canonical 文档树。
- 已重新运行 `python -B docs/api/_tools/audit_api_docs.py`,确认 `Public headers: 247``Editor source headers: 136``Invalid header refs: 0``Invalid source refs: 0``Broken .md links: 0`
## T16 Editor / Viewport `SceneViewportOverlaySpriteResources` 新增头文件补页
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P1`
- 写入范围:
- `docs/api/XCEngine/Editor/Viewport/SceneViewportOverlaySpriteResources/**`
- `docs/api/XCEngine/Editor/Viewport/Viewport.md`
- `docs/api/XCEngine/Editor/Viewport/SceneViewportEditorOverlayData/SceneViewportEditorOverlayData.md`
- `docs/api/XCEngine/Editor/Viewport/Passes/SceneViewportEditorOverlayPass/**`
- `docs/api/_meta/rebuild-status.md`
- 主要源码依据:
- `editor/src/Viewport/SceneViewportOverlaySpriteResources.h`
- `editor/src/Viewport/SceneViewportOverlaySpriteResources.cpp`
- `editor/src/Viewport/Passes/SceneViewportEditorOverlayPass.h`
- `editor/src/Viewport/Passes/SceneViewportEditorOverlayPass.cpp`
- `tests/Editor/test_scene_viewport_overlay_sprite_resources.cpp`
- 已确认问题:
- 工作树当前新增了 `SceneViewportOverlaySpriteResources.h`,但 canonical 文档树还没有对应目录页,导致结构审计一度出现 `Editor source headers: 136` / `Valid source refs (Editor canonical): 135`
- `SceneViewportEditorOverlayPass` 文档仍把 camera / light icon 纹理描述成 pass 内部细节,没有同步当前已经拆出的“资源路径解析 + RGBA 解码 + descriptor set 缓存”辅助层。
- `SceneViewportOverlaySpriteTextureKind` 当前已经不再直接隐含具体文件路径;真实资源解析口径来自新头文件里的 helper 与 cache。
- 完成记录:
- 已新增 `SceneViewportOverlaySpriteResources` canonical 目录,补齐 texture-kind 映射、asset spec、pixel payload、像素加载与 GPU 资源缓存页面。
- 已同步 `Viewport.md``SceneViewportEditorOverlayData.md``SceneViewportEditorOverlayPass/**`,把 sprite overlay 资源准备链路改写为当前真实的 helper-header + cache 模型。
- 已重新运行 `python -B docs/api/_tools/audit_api_docs.py`,确认 `Public headers: 247``Editor source headers: 136``Valid source refs (Editor canonical): 136``Invalid source refs: 0``Broken .md links: 0`
## T17 Editor / Viewport `SceneViewportShaderPaths` 兼容层化与 pass-spec wrapper 类型口径收口
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P1`
- 写入范围:
- `docs/api/XCEngine/Editor/Viewport/SceneViewportShaderPaths/**`
- `docs/api/XCEngine/Editor/Viewport/ViewportHostRenderFlowUtils/**`
- `docs/api/XCEngine/Editor/Viewport/SceneViewportRenderPlan/**`
- `docs/api/XCEngine/Editor/Viewport/Passes/SceneViewportGridPass/**`
- `docs/api/XCEngine/Editor/Viewport/Passes/SceneViewportSelectionOutlinePass/**`
- `docs/api/XCEngine/Editor/Viewport/Passes/SceneViewportEditorOverlayPass/**`
- `docs/api/XCEngine/Resources/BuiltinResources/BuiltinResources.md`
- `docs/api/_meta/rebuild-status.md`
- 主要源码依据:
- `editor/src/Viewport/SceneViewportShaderPaths.h`
- `editor/src/Viewport/SceneViewportResourcePaths.h`
- `editor/src/Viewport/SceneViewportPassSpecs.h`
- `editor/src/Viewport/ViewportHostRenderFlowUtils.h`
- `editor/src/Viewport/SceneViewportRenderPlan.h`
- `editor/src/Viewport/Passes/SceneViewportGridPass.h`
- `editor/src/Viewport/Passes/SceneViewportGridPass.cpp`
- `editor/src/Viewport/Passes/SceneViewportSelectionOutlinePass.h`
- `editor/src/Viewport/Passes/SceneViewportSelectionOutlinePass.cpp`
- `editor/src/Viewport/Passes/SceneViewportEditorOverlayPass.h`
- `editor/src/Viewport/Passes/SceneViewportEditorOverlayPass.cpp`
- `engine/include/XCEngine/Resources/BuiltinResources.h`
- `tests/Editor/test_scene_viewport_shader_paths.cpp`
- `tests/Editor/test_viewport_render_flow_utils.cpp`
- 已确认问题:
- `SceneViewportShaderPaths.h` 当前已经退化为只包含 `SceneViewportResourcePaths.h` 的兼容头,但部分文档仍把它写成路径 helper 的真实 owner。
- `BuildSceneViewportGridPassData()``BuildSceneViewportSelectionOutlineStyle()`、两类 factory alias以及 grid / selection-outline pass 适配页仍沿用旧签名,把 editor wrapper 类型写成 runtime `InfiniteGridPassData` / `ObjectIdOutlineStyle`
- `SceneViewportEditorOverlayPass``BuiltinResources.md` 仍残留一部分旧口径,没有完全同步 sprite resource cache 和新的 builtin shader 集合。
- 完成记录:
- 已把 `SceneViewportShaderPaths/**` 收口为“兼容 include 层 + 迁移说明”口径,并统一回链当前真实 owner `SceneViewportResourcePaths`
- 已同步 `ViewportHostRenderFlowUtils/**``SceneViewportRenderPlan/**``SceneViewportGridPass/**``SceneViewportSelectionOutlinePass/**` 到当前 `SceneViewportGridPassData` / `SceneViewportSelectionOutlineStyle` wrapper 类型,以及 `ToBuiltin...` 转换链。
- 已补充 `SceneViewportEditorOverlayPass/**``SceneViewportOverlaySpriteResourceCache` 的引用,并把 `BuiltinResources.md` 改到当前 builtin shader 集合 `forward-lit / unlit / depth-only / shadow-caster / object-id`
- 已重新运行 `python -B docs/api/_tools/audit_api_docs.py`,确认 `Public headers: 247``Editor source headers: 136``Valid header refs (canonical): 247``Valid source refs (Editor canonical): 136``Broken .md links: 0`
## T18 Rendering / `CameraRenderer` depth-only 与 shadow-caster pass 注入链补页
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P1`
- 写入范围:
- `docs/api/XCEngine/Rendering/CameraRenderer/**`
- 主要源码依据:
- `engine/include/XCEngine/Rendering/CameraRenderer.h`
- `engine/src/Rendering/CameraRenderer.cpp`
- `tests/Rendering/unit/test_camera_scene_renderer.cpp`
- 已确认问题:
- `CameraRenderer.h` 当前已经公开 `SetDepthOnlyPass()``SetShadowCasterPass()``GetDepthOnlyPass()``GetShadowCasterPass()`,但 canonical 文档树还停留在只有主管线与 object-id pass 的旧索引。
- `Constructor.md` 仍把最高阶构造重载写成只有 `(pipeline, objectIdPass)`,没有同步当前 `depthOnlyPass / shadowCasterPass` 注入点。
- `Render.md` 仍把执行链写成 `pre -> pipeline -> object-id -> post -> overlay`,没有同步当前先跑 `shadowCaster``depthOnly` 请求的真实顺序。
- 完成记录:
- 已补齐 `SetDepthOnlyPass.md``SetShadowCasterPass.md``GetDepthOnlyPass.md``GetShadowCasterPass.md`
- 已重写 `CameraRenderer.md``Constructor.md``Render.md``Destructor.md`,同步当前 depth-only / shadow-caster pass 的持有、回退与执行链语义。
- 已重新运行 `python -B docs/api/_tools/audit_api_docs.py`,确认 `Public headers: 247``Broken .md links: 0``Stale canonical doc tokens: 0`
## T19 Editor / Viewport `SceneViewportOverlayFrameCache` 新增头文件补页
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P1`
- 写入范围:
- `docs/api/XCEngine/Editor/Viewport/SceneViewportOverlayFrameCache/**`
- `docs/api/XCEngine/Editor/Viewport/Viewport.md`
- `docs/api/XCEngine/Editor/Viewport/ViewportHostService/SceneView-Overlay-Frame-Data.md`
- `docs/api/_meta/rebuild-status.md`
- 主要源码依据:
- `editor/src/Viewport/SceneViewportOverlayFrameCache.h`
- `editor/src/Viewport/SceneViewportOverlayFrameCache.cpp`
- `editor/src/Viewport/ViewportHostService.h`
- `tests/Editor/test_scene_viewport_overlay_frame_cache.cpp`
- 已确认问题:
- 工作树新增了 `SceneViewportOverlayFrameCache.h`,但 canonical 文档树没有对应目录页,导致结构审计一度出现 `Editor source headers: 137` / `Valid source refs (Editor canonical): 136`
- `Viewport``ViewportHostService/SceneView-Overlay-Frame-Data.md` 仍在用“宿主类内部散落 cache key”的旧口径没有把 viewport 尺寸解析、内容签名与重建判定收口到新 helper header。
- 完成记录:
- 已新增 `SceneViewportOverlayFrameCache/**`,补齐 cache state、viewport 尺寸解析、内容签名、overlay 比较与重建判定页面。
- 已同步 `Viewport.md``ViewportHostService/SceneView-Overlay-Frame-Data.md`,把 Scene View editor overlay frame 的缓存链路改写到当前 helper-header 模型。
- 已重新运行 `python -B docs/api/_tools/audit_api_docs.py`,确认 `Public headers: 247``Editor source headers: 137``Valid source refs (Editor canonical): 137``Broken .md links: 0`
## T20 Editor / Viewport `SceneViewportRenderPassBundle` 上层总览与 guide 口径同步
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P1`
- 写入范围:
- `docs/api/XCEngine/Editor/Viewport/Viewport.md`
- `docs/api/XCEngine/Editor/Viewport/ViewportHostService/**`
- `docs/api/XCEngine/Editor/Viewport/SceneViewportRenderPlan/**`
- `docs/api/XCEngine/Editor/Viewport/Passes/SceneViewportGridPass/SceneViewportGridPass.md`
- `docs/api/XCEngine/Editor/Viewport/Passes/SceneViewportSelectionOutlinePass/SceneViewportSelectionOutlinePass.md`
- `docs/api/_guides/Editor/Scene-Viewport-Render-Plan-And-Failure-Flow.md`
- `docs/api/_meta/rebuild-status.md`
- 主要源码依据:
- `editor/src/Viewport/ViewportHostService.h`
- `editor/src/Viewport/SceneViewportRenderPassBundle.h`
- `editor/src/Viewport/SceneViewportRenderPassBundle.cpp`
- `editor/src/Viewport/SceneViewportRenderPlan.h`
- `editor/src/Viewport/Passes/SceneViewportGridPass.h`
- `editor/src/Viewport/Passes/SceneViewportSelectionOutlinePass.h`
- `tests/Editor/test_scene_viewport_render_pass_bundle.cpp`
- `tests/Editor/test_viewport_render_flow_utils.cpp`
- 已确认问题:
- `SceneViewportRenderPassBundle` 的 canonical 页面虽然已经存在,但 `Viewport.md``ViewportHostService.md``Initialize-And-Shutdown.md``RenderRequestedViewports.md``SceneViewportRenderPlan.md` 与 Scene View render-plan guide 仍在传播旧口径,把宿主服务写成“直接持有三个 pass renderer”或“直接调用 `BuildSceneViewportRenderPlan(...)`”。
- `SceneViewportGridPass.md``SceneViewportSelectionOutlinePass.md``SceneViewportGridPassFactory.md` 仍把 factory 绑定位置写成 `ViewportHostService` 上的旧 renderer 成员,而不是当前 bundle 内部成员。
- `Viewport.md` 还没有把 `SceneViewportResourcePaths``SceneViewportPassSpecs``SceneViewportRenderPlan``SceneViewportRenderPassBundle``ViewportHostRenderFlowUtils` 纳入当前模块总览。
- 完成记录:
- 已同步 `Viewport.md``ViewportHostService/**``SceneViewportRenderPlan/**` 与 Scene View render-plan guide 到当前真实链路:`ViewportHostService -> SceneViewportRenderPassBundle -> BuildSceneViewportRenderPlan / ApplySceneViewportRenderPlan`
- 已修正 grid / selection-outline 相关页面,把 factory 绑定和 renderer 生命周期表述改成 bundle 持有模型,并补上新的上层交叉链接。
- 已重新运行 `python -B docs/api/_tools/audit_api_docs.py`,确认 `Public headers: 247``Editor source headers: 138``Valid source refs (Editor canonical): 138``Broken .md links: 0``Stale editor canonical pages: 0`
## T21 XCUI / `Resources/UI` / `UI/Types` / `UI/DrawData` / Editor transition header 补页
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P0`
- 写入范围:
- `docs/api/XCEngine/Resources/UI/**`
- `docs/api/XCEngine/UI/UI.md`
- `docs/api/XCEngine/UI/Types/**`
- `docs/api/XCEngine/UI/DrawData/**`
- `docs/api/XCEngine/Editor/Editor.md`
- `docs/api/XCEngine/Editor/XCUIBackend/**`
- `docs/api/XCEngine/Editor/Platform/Platform.md`
- `docs/api/XCEngine/Editor/Platform/D3D12WindowRendererImGuiInterop/**`
- `docs/api/XCEngine/Editor/panels/panels.md`
- `docs/api/XCEngine/Editor/panels/XCUIDemoPanel/**`
- 主要源码依据:
- `engine/include/XCEngine/Resources/UI/UIDocumentTypes.h`
- `engine/include/XCEngine/Resources/UI/UIDocumentCompiler.h`
- `engine/include/XCEngine/Resources/UI/UIDocuments.h`
- `engine/include/XCEngine/Resources/UI/UIDocumentLoaders.h`
- `engine/src/Resources/UI/UIDocumentCompiler.cpp`
- `engine/src/Resources/UI/UIDocuments.cpp`
- `engine/src/Resources/UI/UIDocumentLoaders.cpp`
- `engine/include/XCEngine/UI/Types.h`
- `engine/include/XCEngine/UI/DrawData.h`
- `editor/src/XCUIBackend/ImGuiTransitionBackend.h`
- `editor/src/XCUIBackend/XCUIDemoRuntime.h`
- `editor/src/Platform/D3D12WindowRendererImGuiInterop.h`
- `editor/src/panels/XCUIDemoPanel.h`
- `editor/src/panels/XCUIDemoPanel.cpp`
- `editor/src/Application.cpp`
- `editor/src/Core/EditorWorkspace.h`
- `tests/Resources/UI/test_ui_document_loader.cpp`
- `tests/Resources/UI/test_ui_schema_document.cpp`
- `tests/UI/Core/unit/test_ui_core.cpp`
- `tests/Editor/test_xcui_imgui_transition_backend.cpp`
- `tests/Editor/test_window_renderer_api.cpp`
- 已确认问题:
- `Resources/UI` 模块总览已经存在,但四个 public header 仍缺少 canonical 页面。
- `UI/Types.h``UI/DrawData.h` 已被 runtime、Scene 和 editor transition backend 大量使用,但根模块入口页还没有把它们纳入顶层 API。
- `editor/src/XCUIBackend``editor/src/Platform/D3D12WindowRendererImGuiInterop.h``editor/src/panels/XCUIDemoPanel.h` 没有 source-backed API 页面,导致 Editor 侧 XCUI transition 链路存在结构缺口。
- 完成记录:
- 已新增 `UIDocumentTypes``UIDocumentCompiler``UIDocumentLoaders``UIDocuments``Types``DrawData``XCUIBackend``ImGuiTransitionBackend``XCUIDemoRuntime``D3D12WindowRendererImGuiInterop``XCUIDemoPanel` 页面。
- 已同步 `Resources/UI/UI.md``UI/UI.md``Editor.md``Platform.md``panels.md`,把 UI 资源层、XCUI transition backend 和 demo panel 纳入当前模块入口。
- 已重新运行 `python -B docs/api/_tools/audit_api_docs.py`,确认 `Editor source headers: 142``Valid source refs (Editor canonical): 142``Invalid source refs: 0``Broken .md links: 0`
## T22 RHI / Shader formalization 文档补页与 `MaterialRenderState` 归位
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P1`
- 写入范围:
- `docs/api/XCEngine/RHI/ShaderCompiler/**`
- `docs/api/XCEngine/Resources/Shader/**`
- `docs/api/XCEngine/Resources/Material/**`
- 主要源码依据:
- `engine/include/XCEngine/RHI/ShaderCompiler/SpirvShaderCompiler.h`
- `engine/src/RHI/ShaderCompiler/SpirvShaderCompiler.cpp`
- `engine/src/RHI/Vulkan/VulkanShaderCompiler.cpp`
- `engine/src/RHI/OpenGL/OpenGLDevice.cpp`
- `engine/include/XCEngine/Resources/Shader/ShaderKeywordTypes.h`
- `engine/src/Resources/Shader/ShaderLoader.cpp`
- `engine/src/Resources/Shader/Shader.cpp`
- `engine/include/XCEngine/Resources/Material/MaterialRenderState.h`
- `engine/src/Resources/Material/Material.cpp`
- `tests/Resources/Shader/test_shader_loader.cpp`
- `tests/Resources/Shader/test_shader.cpp`
- `tests/Resources/Material/test_material.cpp`
- `tests/Rendering/unit/test_render_scene_extractor.cpp`
- 已确认问题:
- `SpirvShaderCompiler.h``ShaderKeywordTypes.h` 已进入当前工作树,但 canonical API 树缺少对应入口页。
- `MaterialRenderState` 及其相关枚举页仍沿用旧归属,`头文件` 元信息还停在 `Material.h`
- 复核过程中发现 `ShaderRenderState.h` 并不在当前 public header 集合里,说明不能把计划中的 formalized pass-state 设想误写成现有 API 页面。
- 完成记录:
- 已新增 `SpirvShaderCompiler/SpirvShaderCompiler.md``ShaderKeywordTypes/ShaderKeywordTypes.md`,并同步 `ShaderCompiler.md``Resources/Shader/Shader.md`
- 已把 `MaterialRenderState``MaterialCullMode``MaterialComparisonFunc``MaterialBlendOp``MaterialBlendFactor``头文件` 归位到 `MaterialRenderState.h`,并更新 `Resources/Material/Material.md`
- 已删除误建的 `ShaderRenderState` canonical 页面,并重新运行审计,确认 `Public headers: 304``Invalid header refs: 0``Broken .md links: 0`
## T23 UI / Core + Input header coverage 补页
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P0`
- 写入范围:
- `docs/api/XCEngine/UI/Core/**`
- `docs/api/XCEngine/UI/Input/**`
- `docs/api/XCEngine/UI/UI.md`
- 主要源码依据:
- `engine/include/XCEngine/UI/Core/UIBuildContext.h`
- `engine/include/XCEngine/UI/Core/UIContext.h`
- `engine/include/XCEngine/UI/Core/UIElementTree.h`
- `engine/include/XCEngine/UI/Core/UIInvalidation.h`
- `engine/include/XCEngine/UI/Core/UIViewModel.h`
- `engine/include/XCEngine/UI/Input/UIFocusController.h`
- `engine/include/XCEngine/UI/Input/UIInputDispatcher.h`
- `engine/include/XCEngine/UI/Input/UIInputPath.h`
- `engine/include/XCEngine/UI/Input/UIInputRouter.h`
- `engine/include/XCEngine/UI/Input/UIShortcutRegistry.h`
- `engine/src/UI/Core/**`
- `engine/src/UI/Input/**`
- `tests/UI/Core/unit/**`
- `tests/UI/Runtime/unit/**`
- 已确认问题:
- 最新审计显示 `UI` 模块当前只覆盖 `2 / 37`,剩余缺口里最基础的一批就是 `Core``Input`
- 这些头文件已经有真实 `.cpp`、单测和 runtime 调用链,但 canonical API 树仍停留在目录总览页。
- 完成记录:
- 已新增 `UIBuildContext``UIContext``UIElementTree``UIInvalidation``UIViewModel``UIFocusController``UIInputDispatcher``UIInputPath``UIInputRouter``UIShortcutRegistry` 页面。
- 已同步 `Core.md``Input.md``UI.md`,把 retained-mode build / diff 主链和输入分发主链纳入当前模块入口。
- 已重新运行 `python -B docs/api/_tools/audit_api_docs.py`,确认 `Valid header refs (canonical): 279``Invalid header refs: 0``Invalid source refs: 0``Broken .md links: 0`
## T24 UI / Layout + Runtime + Style + Text + Widgets header coverage 补页
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P0`
- 写入范围:
- `docs/api/XCEngine/UI/Layout/**`
- `docs/api/XCEngine/UI/Runtime/**`
- `docs/api/XCEngine/UI/Style/**`
- `docs/api/XCEngine/UI/Text/**`
- `docs/api/XCEngine/UI/Widgets/**`
- `docs/api/XCEngine/UI/UI.md`
- 主要源码依据:
- `engine/include/XCEngine/UI/Layout/*.h`
- `engine/include/XCEngine/UI/Runtime/*.h`
- `engine/include/XCEngine/UI/Style/*.h`
- `engine/include/XCEngine/UI/Text/*.h`
- `engine/include/XCEngine/UI/Widgets/*.h`
- `engine/src/UI/Runtime/**`
- `engine/src/UI/Style/**`
- `engine/src/UI/Text/**`
- `engine/src/UI/Widgets/**`
- `tests/UI/Core/unit/**`
- `tests/UI/Runtime/unit/**`
- `tests/Scene/test_scene_runtime.cpp`
- 已确认问题:
- `Layout / Runtime / Style / Text / Widgets` 还剩 `25` 个未覆盖 public headers是当前 API 文档最大的连续缺口。
- 这些头文件里既有 header-only layout / interaction helper也有真实 source-backed runtime / style / widget 状态模型如果不拆开写overview 很容易继续混淆“声明契约”和“当前实现行为”。
- 当前进展:
- 已新增 `LayoutTypes``LayoutEngine``UISplitterLayout``UITabStripLayout``UIScreenTypes``UISceneRuntimeContext``UIScreenDocumentHost``UIScreenPlayer``UIScreenStackController``UISystem``StyleTypes``StyleSet``Theme``StyleResolver``DocumentStyleCompiler``UITextEditing``UITextInputController``UIExpansionModel``UIFlatHierarchyHelpers``UIKeyboardNavigationModel``UIPopupOverlayModel``UIPropertyEditModel``UISelectionModel``UISplitterInteraction``UITabStripModel` 页面。
- 已同步 `Layout.md``Runtime.md``Style.md``Text.md``Widgets.md``UI.md`,把 header-only helper 和 source-backed runtime/style/widget 状态模型拆开归位。
- 已重新运行 `python -B docs/api/_tools/audit_api_docs.py`,结果为:`Valid header refs (canonical): 304``UI: 37/37``Invalid source refs: 0``Broken .md links: 0`
## T25 Editor UI 壳层与 `RenderMaterialResolve` 增量漂移复核
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P1`
- 写入范围:
- `docs/api/XCEngine/Editor/UI/ImGuiSession/ImGuiSession.md`
- `docs/api/XCEngine/Editor/panels/ViewportPanelContent/ViewportPanelContent.md`
- `docs/api/XCEngine/Editor/Layout/DockLayoutController/DockLayoutController.md`
- `docs/api/XCEngine/Rendering/Materials/RenderMaterialResolve/RenderMaterialResolve.md`
- 主要源码依据:
- `editor/src/UI/ImGuiSession.h`
- `editor/src/panels/ViewportPanelContent.h`
- `editor/src/Layout/DockLayoutController.h`
- `engine/include/XCEngine/Rendering/Materials/RenderMaterialResolve.h`
- `engine/src/RHI/D3D12/D3D12ResourceView.cpp`
- `engine/include/XCEngine/Input/InputTypes.h`
- `engine/include/XCEngine/Threading/TaskSystem.h`
- 已确认问题:
- `ImGuiSession.md` 仍停留在旧的“单字体 + 简单初始化”口径,没有同步 `SetProjectPath()` / `GetIniPath()`、双字体回退链和 DPI 配置。
- `ViewportPanelContent.md` 没有写出当前 `AllowWhenOverlappedByItem` 的 hover/click 采样语义,容易误解 toolbar 覆盖视口时的交互行为。
- `DockLayoutController.md` 没有同步当前 main viewport work-area、dock tab bar chrome 配置和 reset 延迟到下一帧重建的真实路径。
- `RenderMaterialResolve.md` 漏掉了一批已经公开的 render-queue / legacy pass-fallback helper也没把常量 payload 有效性和 skybox 模式优先级写清。
- 完成记录:
- 已重写 `ImGuiSession.md`,补齐 `Initialize(projectPath, mainDpiScale)``GetIniPath()``SetProjectPath()`、Segoe UI + 微软雅黑 fallback 和 DPI 钳制逻辑。
- 已更新 `ViewportPanelContent.md`,补上 overlappable 交互表面、root-child focus 与状态文案依赖 item rect 的当前实现说明。
- 已更新 `DockLayoutController.md`,同步 dock host work-area、tab bar chrome 配置与 reset/rebuild 触发链。
- 已更新 `RenderMaterialResolve.md`,补齐 render queue tag 解析、legacy builtin pass fallback、skybox 纹理模式优先级和常量 payload 有效性边界。
- 抽查 `InputTypes``TaskSystem``D3D12ResourceView` 后,本轮未发现新的明确文档失配。
## 当前结论
- 第三轮复核当前已确认 `25` 组失配;`T01``T25` 已全部完成。
- 当前 `Public headers` 已达到 `304/304``Editor source headers` 已达到 `142/142`结构层、Resources、RHI、Rendering、UI 和全部 Editor source-backed API 均为全绿状态。
- 后续如果 `docs/plan/` 再出现新的 API 相关计划,或工作树新增/改动 public header、Editor source header应继续在此任务池追加新任务块并在收口前重新运行 `python -B docs/api/_tools/audit_api_docs.py`

View File

@@ -0,0 +1,376 @@
# API 文档实时同步任务池2026-04-03
## 文档定位
这份任务池接替已归档的:
- `docs/plan/used/API文档并行更新任务池_2026-04-02.md`
旧任务池解决的是:
- canonical 目录结构收口
- 历史缺页补齐
- 第一轮大规模内容重写
本轮不再以“补结构”为主,而是以“跟踪当前工作树真实实现变化,持续清理失准内容和过期 API 页面”为主。
## 本轮复核方法
本轮按下面三层做交叉复核:
1. 重新执行 `python docs/api/_tools/audit_api_docs.py`
2. 检查当前工作树里真实发生变化的源码与测试:
- `engine/src/Components/MeshFilterComponent.cpp`
- `engine/src/Components/MeshRendererComponent.cpp`
- `editor/src/Actions/EditorActions.h`
- `editor/src/Actions/MainMenuActionRouter.h`
- `editor/src/Commands/ProjectCommands.h`
- `editor/src/Core/IProjectManager.h`
- `editor/src/Managers/ProjectManager.h`
- `editor/src/Managers/ProjectManager.cpp`
- `tests/Components/test_mesh_render_components.cpp`
- `tests/Scene/test_scene.cpp`
- `tests/editor/test_action_routing.cpp`
3. 反向搜索 API 文档里对旧行为、旧菜单和旧序列化键的残留描述
## 当前总判断
- 旧的内容级失准问题已经全部关闭:
- `Editor`旧的项目迁移菜单、命令、接口、manager 和报告结构残留页已在 `2026-04-03 14:04:49` 收口完成
- `Components``MeshFilterComponent / MeshRendererComponent` 的旧键名、普通项目路径 fallback 和模块总览口径已在 `2026-04-03 14:09:47` 对齐到当前源码 / 测试
- 新暴露出的 `SceneViewportRenderPlan.h` 缺页问题已在 `2026-04-03 14:17:02` 收口完成
- 当前结构项重新回到全绿:
- public headers `246/246`
- Editor source headers `122/122`
- 失效 `.md` 链接 `0`
- 无效 header / source ref `0`
- Editor 显式过期符号残留 `0`
- Editor 残留 canonical 旧页面 `0`
这说明当前审计工具已经同时具备三种能力:兜住结构一致性、自动报出已删除 API 的旧符号残留、以及发现工作树中新冒出的未补页 header后续工作进入“继续跟踪新增 API 与计划文件新增任务块”的阶段。
## 认领规则
- 一次只认领 `1` 个任务块,先改 `状态``认领人`
- 只修改自己任务块的 `写入范围`,不要跨任务顺手扩写其它模块
- 每个任务都要以当前工作树源码、测试和真实调用点为依据,不允许只按旧文档重写旧文档
- 除最后的审计收口任务外,不要随意覆盖 `docs/api/_meta/rebuild-status.md`
- 如果任务涉及删除过期 API 页面,必须同步清理所有交叉链接
## 任务池
## T01 Components / Mesh 资产引用最终协议同步
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P0`
- 写入范围:
- `docs/api/XCEngine/Components/MeshFilterComponent/**`
- `docs/api/XCEngine/Components/MeshRendererComponent/**`
- 必要时 `docs/api/XCEngine/Components/Components.md`
- 必要时 `docs/api/_guides/Components/**`
- 主要源码依据:
- `engine/src/Components/MeshFilterComponent.cpp`
- `engine/src/Components/MeshRendererComponent.cpp`
- `tests/Components/test_mesh_render_components.cpp`
- `tests/Scene/test_scene.cpp`
- `engine/include/XCEngine/Components/MeshFilterComponent.h`
- `engine/include/XCEngine/Components/MeshRendererComponent.h`
- 当前确认缺口:
- `MeshFilterComponent.md` 仍写“反序列化会读取 `mesh=<path>`”,而当前实现只识别 `meshPath`
- `MeshFilterComponent.md` / `Serialize.md` 仍写“序列化输出 `mesh=<path>`”,而当前实现对项目资产已转向 `meshRef` 主路径,只在 virtual scheme 下保留 `meshPath`
- `MeshFilterComponent::Deserialize.md` 仍写“只有路径时会补算 `AssetRef` 并接受普通路径”,而当前实现已忽略没有 `AssetRef` 的普通项目路径,只保留 virtual scheme 路径
- `MeshRendererComponent.md` / `Serialize.md` / `Deserialize.md` 仍写“兼容 `materials=` 历史键”和“项目资产路径 fallback 仍是主恢复路径”,而当前实现已经不再读取 `materials=`,并且会清掉无 `AssetRef` 的普通 `materialPaths`
- 组件模块总览当前对“路径 + AssetRef + 运行时句柄双轨”的描述仍偏旧,没有强调“项目资产主协议已经收口为 `AssetRef`,路径主要保留给 `builtin://` / 其它 virtual scheme”
- 完成标准:
-`MeshFilterComponent` / `MeshRendererComponent` 类型页和序列化方法页全部改到当前实现
- 明确“项目资产只依赖 `AssetRef`,普通项目路径不再作为长期兼容协议”
- 明确“只有 virtual scheme 路径会稳定保留在 `meshPath` / `materialPaths` 里”
- 清掉所有关于 `mesh=``materials=` 仍被当前实现兼容的说法
- 完成记录:
- 已重新核对 `MeshFilterComponent.h/.cpp``MeshRendererComponent.h/.cpp``tests/Components/test_mesh_render_components.cpp``tests/Scene/test_scene.cpp`
- `MeshFilterComponent.md``Serialize.md``Deserialize.md``MeshRendererComponent.md``Serialize.md``Deserialize.md` 已确认按当前实现描述 `meshRef / materialRefs` 主协议
- 已继续修正 `SetMeshPath.md``SetMaterialPath.md``Components.md`,把“运行时路径缓存”和“正式序列化协议”明确拆开
- `2026-04-03 14:09:47` 审计后,当前仓库中这组页面不再把 `mesh=` / `materials=` 或普通项目路径 fallback 写成当前协议
## T02 Editor / 移除场景资产引用迁移链路文档与过期页
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P0`
- 写入范围:
- `docs/api/XCEngine/Editor/Actions/EditorActions/**`
- `docs/api/XCEngine/Editor/Actions/MainMenuActionRouter/**`
- `docs/api/XCEngine/Editor/Commands/ProjectCommands/**`
- `docs/api/XCEngine/Editor/Core/IProjectManager/**`
- `docs/api/XCEngine/Editor/Managers/ProjectManager/**`
- `docs/api/XCEngine/Editor/panels/ProjectPanel/**`
- 必要时 `docs/api/_guides/Editor/**`
- 主要源码依据:
- `editor/src/Actions/EditorActions.h`
- `editor/src/Actions/MainMenuActionRouter.h`
- `editor/src/Commands/ProjectCommands.h`
- `editor/src/Core/IProjectManager.h`
- `editor/src/Managers/ProjectManager.h`
- `editor/src/Managers/ProjectManager.cpp`
- `tests/editor/test_action_routing.cpp`
- 当前确认缺口:
- `EditorActions.md` 仍包含 `MakeMigrateSceneAssetReferencesAction`
- `MainMenuActionRouter.md` 仍把 `File -> Migrate Scene AssetRefs` 当成当前菜单项
- `ProjectCommands.md` 仍写 `CanMigrateSceneAssetReferences()` / `MigrateSceneAssetReferences()`
- `IProjectManager.md` 仍声明 `SceneAssetReferenceMigrationReport``MigrateSceneAssetReferences()`
- `ProjectManager.md` 仍把“场景资产引用迁移”写成当前公开职责
- `ProjectPanel.md` 仍把 `Migrate Scene AssetRefs` 记为项目级命令之一
- 过期 canonical 页面仍存在:
- `docs/api/XCEngine/Editor/Managers/ProjectManager/MigrateSceneAssetReferences.md`
- 完成标准:
- 把上述页面全部改成当前源码状态
- 删除已不存在的 API 页面,并清理所有交叉引用
- 把项目工作流文档收口到当前仍存在的入口:项目切换、保存、脚本重建、资源浏览与文件操作
- 完成记录:
- 已重写 `EditorActions.md``MainMenuActionRouter.md``ProjectCommands.md``IProjectManager.md``ProjectManager.md``ProjectPanel.md`
- 已把 `IProjectManager` 进一步拆成 `Current Items And Selection``Navigation And Path``Initialization And Refresh``File Operations` 四页,按当前头文件分组收口
- `docs/api/XCEngine/Editor/Managers/ProjectManager/MigrateSceneAssetReferences.md` 已删除;旧迁移 API 不再保留兼容入口页
- `2026-04-03 14:04:49` 已重新执行 `python docs/api/_tools/audit_api_docs.py`,结果为:
- `Stale editor doc tokens: 0`
- `Broken .md links: 0`
- `Valid source refs (Editor canonical): 121`
## T03 Cross-Module / 资产引用协议与编辑器工作流交叉说明收口
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P1`
- 写入范围:
- `docs/api/XCEngine/Components/Components.md`
- `docs/api/XCEngine/Scene/Scene.md`
- `docs/api/_guides/Editor/Editor-Architecture-And-Workflow.md`
- 必要时 `docs/api/main.md`
- 主要源码依据:
- `engine/src/Components/MeshFilterComponent.cpp`
- `engine/src/Components/MeshRendererComponent.cpp`
- `editor/src/Actions/MainMenuActionRouter.h`
- `editor/src/Commands/ProjectCommands.h`
- `editor/src/Managers/ProjectManager.cpp`
- `tests/Scene/test_scene.cpp`
- `tests/editor/test_action_routing.cpp`
- 当前确认缺口:
- 模块总览层还没有把“项目资产最终序列化协议已收口到 `AssetRef`virtual path 只保留给 builtin/虚拟资源”讲透
- Editor 架构层仍有旧项目维护入口的残留心智,需要删掉“场景迁移”这条已不存在的分支
- 目前用户如果只读模块总览,仍容易得出“普通项目路径仍是第一公民协议”“主菜单还带场景迁移入口”的错误结论
- 完成标准:
- 模块页和 guide 页不再沿用旧心智模型
- 用户只看总览页,也能得出当前正确结论:
- 项目资产靠 `AssetRef`
- `builtin://` / 其它 virtual scheme 才保留路径
- 主菜单已无 `Migrate Scene AssetRefs`
- 完成记录:
- 已修正 `docs/api/XCEngine/Components/Components.md`,明确项目资产正式协议优先 `AssetRef`
- 已复核 `docs/api/XCEngine/Scene/Scene.md``docs/api/_guides/Editor/Editor-Architecture-And-Workflow.md``docs/api/main.md`,确认不再传播旧菜单入口或“普通项目路径仍是第一公民协议”的说法
- 当前仅阅读模块总览 / guide也能得出“项目资产靠 `AssetRef`、virtual scheme 才稳定保留路径、主菜单没有旧迁移入口”的正确结论
## T04 API 审计工具补强 / 过期 API 页面检测
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P1`
- 写入范围:
- `docs/api/_tools/audit_api_docs.py`
- 必要时 `docs/api/_meta/rebuild-status.md`
- 必要时在 `docs/plan` 中补充审计口径说明
- 主要依据:
- 本轮复核结论
- 当前 audit 全绿但仍漏报 `MigrateSceneAssetReferences` 这类已删除 API 残留页
- 当前确认缺口:
- 现有审计能发现“缺页”和“断链”,但不能发现“源码已经删除,文档页仍然存在”
- 也不能发现模块页仍在描述已删除菜单项或已删除 helper
- 完成标准:
- 至少新增一种轻量检测,能把“已删除 API 的残留 canonical 页面”或“显式过期 helper 名称残留”暴露出来
- 让后续复核不再完全依赖人工 grep
- 完成记录:
- `docs/api/_tools/audit_api_docs.py` 已新增 Editor 显式过期符号残留检测
- `2026-04-03 13:53:21` 审计已能自动报出 `49``MigrateSceneAssetReferences` 相关残留
## T05 收口审计与进度回写
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P2`
- 写入范围:
- `docs/api/_meta/rebuild-status.md`
- `docs/plan/API文档实时同步任务池_2026-04-03.md`
- 主要依据:
- `T01-T04` 完成结果
- 完成标准:
- 重新执行 `python docs/api/_tools/audit_api_docs.py`
- 回写新的审计时间和结果
- 明确记录本轮哪些失准点已关闭、哪些仍待继续跟踪
- 完成记录:
- 已在 `2026-04-03 14:20:04` 重新执行 `python docs/api/_tools/audit_api_docs.py`
- 已回写 `docs/api/_meta/rebuild-status.md`
- 本轮已关闭:
- `T01` 对应的 Components / Mesh 资产引用协议失准
- `T02` 对应的 Editor 旧迁移链路文档残留
- `T03` 对应的跨模块总览与 guide 口径收口
- `T07` 对应的 `SceneViewportRenderPlan.h` 缺页
- 本轮剩余待继续跟踪:
- 当前任务池内无未完成块;后续按新增 API 或新增计划任务继续开块
## 最新收口结论2026-04-03 14:20:04
- 已重新执行 `python docs/api/_tools/audit_api_docs.py`
- 当前结构性问题重新回到 `0`
- public headers `246/246`
- Editor source headers `122/122`
- 失效 `.md` 链接 `0`
- 无效 header / source ref `0`
- 本轮新增收口结果:
- `T01 Components / Mesh 资产引用最终协议同步` 已完成
- `T02 Editor / 移除场景资产引用迁移链路文档与过期页` 已完成
- `T03 Cross-Module / 资产引用协议与编辑器工作流交叉说明收口` 已完成
- `T07 Editor / SceneViewportRenderPlan 新增头文件补页` 已完成
- `T09 Editor / EditorConsoleSink 生命周期与 Managers 总览口径复核` 已完成
- `IProjectManager` 已按当前头文件拆成 4 个职责页,`ProjectManager` / `ProjectCommands` / `MainMenuActionRouter` / `EditorActions` / `ProjectPanel` 已全部同步到当前源码
- Components 模块总览与 mesh/material 组件页已统一到“项目资产优先 `AssetRef`、virtual scheme 才稳定保留路径”的当前协议
- 对应的旧迁移 canonical 页已删除,已删除 API 名称也不再出现在正文里
- `EditorConsoleSink` 文档已改回当前真实生命周期:`GetInstance()` 没有 fallback 实例,未注册时会返回 `nullptr`
- `docs/api/_meta/rebuild-status.md` 当前显示:
- `Markdown pages (canonical): 3273`
- `Stale editor doc tokens: 0`
- `Stale editor canonical pages: 0`
- `Editor high-risk single-page dirs: 0`
- 当前仍待处理的内容级问题:
- 当前任务池内无未完成块
## T06 Rendering / CameraRenderer 与主管线职责边界收口
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P1`
- 写入范围:
- `docs/api/XCEngine/Rendering/CameraRenderer/**`
- `docs/api/XCEngine/Rendering/RenderPipeline/**`
- `docs/api/XCEngine/Rendering/RenderPipelineAsset/**`
- `docs/api/XCEngine/Rendering/Pipelines/BuiltinForwardPipelineAsset/**`
- 必要时 `docs/api/XCEngine/Rendering/Rendering.md`
- 主要源码依据:
- `engine/include/XCEngine/Rendering/CameraRenderer.h`
- `engine/src/Rendering/CameraRenderer.cpp`
- `engine/include/XCEngine/Rendering/RenderPipeline.h`
- `engine/include/XCEngine/Rendering/RenderPipelineAsset.h`
- `engine/include/XCEngine/Rendering/Pipelines/BuiltinForwardPipeline.h`
- `tests/Rendering/unit/test_camera_scene_renderer.cpp`
- 当前缺口:
- 已重写 `CameraRenderer.md``Constructor.md``Render.md``Rendering.md``RenderPipeline.md`,把“`SceneRenderer` 负责请求规划、`CameraRenderer` 负责执行单 request”的真实分层以及默认 `BuiltinForwardPipelineAsset -> BuiltinForwardPipeline` 链路同步到当前实现。
- 已继续重写 `RenderPipeline/Initialize.md``Render.md``Shutdown.md``Destructor.md`,明确 `RenderPipeline` 只覆盖主场景 runtime 绘制,不承担 object-id / builtin post-process / overlay 编排;同时写清 `Initialize()` 不是上层强制预热点,`Shutdown()` 调用路径由 `CameraRenderer` 托管。
- 已校正 `RenderPipelineAsset.md``CreatePipeline.md``BuiltinForwardPipelineAsset.md``CreatePipeline.md`把“asset 负责创建 runtime pipeline”与“空 asset / 空返回后的 fallback 由 `CameraRenderer` 处理”拆开说明,避免把调用方策略误记到 asset 接口本身。
- 完成标准:
- 用户只看 `CameraRenderer` / `RenderPipeline` / `RenderPipelineAsset` 这一组页面,也能得出当前正确结论:
- `SceneRenderer` 负责请求规划,`CameraRenderer` 负责执行单 request
- `RenderPipeline` 只负责主场景 runtime 绘制
- fallback 属于调用方装配逻辑,不属于 `RenderPipelineAsset` 接口本身
## T07 Editor / SceneViewportRenderPlan 新增头文件补页
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P1`
- 写入范围:
- `docs/api/XCEngine/Editor/Viewport/SceneViewportRenderPlan/**`
- 必要时 `docs/api/XCEngine/Editor/Viewport/Viewport.md`
- 必要时 `docs/api/_guides/Editor/**`
- 主要源码依据:
- `editor/src/Viewport/SceneViewportRenderPlan.h`
- `editor/src/Viewport/ViewportHostService.h`
- 当前缺口:
- `docs/api/_tools/audit_api_docs.py``2026-04-03 14:11:12` 报出新增未覆盖 header`editor/src/Viewport/SceneViewportRenderPlan.h`
- 当前缺的不只是类型页,还包括内联 helper
- `SceneViewportRenderPlan`
- `SceneViewportRenderPlanBuildResult`
- `BuildSceneViewportRenderPlan(...)`
- `ApplySceneViewportRenderPlan(...)`
-`ViewportHostService.h` 的调用关系看,这个头文件已经成为 Scene View request 装配链的一部分,不能继续留白
- 完成标准:
-`SceneViewportRenderPlan.h` 建立 canonical 目录与类型页
- 把 plan 结构、build result、build/apply 两个 helper 的职责边界写清楚
- 用户只看这组页面,也能得出当前正确结论:
- 它负责把 Scene View 的 builtin post-process、overlay passes 与 clear-color override 收口成一个 request plan
- `Build...` 负责从 overlay / targets 生成 plan
- `Apply...` 负责把 plan 回写到 `CameraRenderRequest`
- 完成记录:
- 已新增:
- `docs/api/XCEngine/Editor/Viewport/SceneViewportRenderPlan/SceneViewportRenderPlan.md`
- `docs/api/XCEngine/Editor/Viewport/SceneViewportRenderPlan/SceneViewportRenderPlanBuildResult.md`
- `docs/api/XCEngine/Editor/Viewport/SceneViewportRenderPlan/BuildSceneViewportRenderPlan.md`
- `docs/api/XCEngine/Editor/Viewport/SceneViewportRenderPlan/ApplySceneViewportRenderPlan.md`
- 已同步更新:
- `docs/api/XCEngine/Editor/Viewport/Viewport.md`
- `docs/api/XCEngine/Editor/Viewport/ViewportHostService/ViewportHostService.md`
- `2026-04-03 14:20:04` 审计结果已恢复为:
- `Editor source headers 122/122`
- `失效 .md 链接 0`
- `Stale editor doc tokens 0`
- `Stale editor canonical pages 0`
## T08 Rendering / RenderCameraData 与 builtin forward 材质契约补齐
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P2`
- 写入范围:
- `docs/api/XCEngine/Rendering/RenderCameraData/**`
- `docs/api/XCEngine/Rendering/RenderSceneUtility/**`
- `docs/api/XCEngine/Rendering/RenderMaterialUtility/**`
- 主要源码依据:
- `engine/include/XCEngine/Rendering/RenderCameraData.h`
- `engine/include/XCEngine/Rendering/RenderSceneUtility.h`
- `engine/src/Rendering/RenderSceneUtility.cpp`
- `engine/include/XCEngine/Rendering/RenderMaterialUtility.h`
- `tests/Rendering/unit/test_render_scene_extractor.cpp`
- `tests/Rendering/unit/test_render_scene_utility.cpp`
- 当前缺口:
- 已重写 `RenderCameraData.md`,补齐此前遗漏的 `clearFlags` 字段,以及 `RenderClearFlags` / `HasRenderClearFlag(...)` 的当前位标志语义;同时写清 `BuildRenderCameraData()` 不负责 clear mode 推导,真正的 per-request clear 规则由 `CameraRenderer` 回写。
- 已重写 `RenderSceneUtility.md``BuildRenderCameraData()` 的职责边界,明确它只构建矩阵、世界位置、默认清屏色和 viewport不直接决定相机 request 的 clear 规则。
- 已补齐 `ResolveBuiltinBaseColorFactor.md``ResolveBuiltinBaseColorTexture.md``BuildBuiltinForwardMaterialData.md`,并更新 `RenderMaterialUtility.md`,把 builtin forward 当前公开消费的 base-color 因子 / 贴图契约、semantic 优先级、别名回退与 alpha-only fallback 写到当前实现。
- 完成标准:
- 用户只看 `RenderCameraData` / `RenderSceneUtility` / `RenderMaterialUtility`,也能得出当前正确结论:
- clear flags 不是 extractor 里按相机直接定死的,而是 request 层再覆盖写回
- builtin forward 当前公开消费的材质契约至少包括 `baseColorFactor` 与 base-color 贴图解析规则
## T09 Editor / EditorConsoleSink 生命周期与 Managers 总览口径复核
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P2`
- 写入范围:
- `docs/api/XCEngine/Editor/Core/EditorConsoleSink/**`
- `docs/api/XCEngine/Editor/Managers/Managers.md`
- `docs/api/_tools/audit_api_docs.py`
- 必要时 `docs/api/_meta/rebuild-status.md`
- 必要时 `docs/plan/API文档实时同步任务池_2026-04-03.md`
- 主要源码依据:
- `editor/src/Core/EditorConsoleSink.h`
- `editor/src/Core/EditorConsoleSink.cpp`
- `tests/Editor/test_editor_console_sink.cpp`
- `editor/src/Managers/ProjectManager.h`
- `editor/src/Managers/ProjectManager.cpp`
- 当前缺口:
- `EditorConsoleSink.md``GetInstance.md``Destructor.md` 仍把 `GetInstance()` 写成“无活动实例时回退到 fallback sink”但当前实现只是直接返回 `s_instance`
- 新增测试 `GetInstanceTracksRegisteredSinkOnly` 已明确要求:活动实例析构后 `GetInstance()` 返回 `nullptr`
- `Managers.md` 仍把“场景资产引用迁移”写成 `ProjectManager` 的当前职责之一,与本轮已删除的旧迁移链路不一致
- 完成标准:
- `EditorConsoleSink` 生命周期相关页面全部对齐到当前实现:
- `GetInstance()` 可能返回 `nullptr`
- 没有静态 fallback sink
- `Managers.md` 不再残留旧迁移职责表述
- 审计工具新增轻量兜底,后续若 `EditorConsoleSink` 文档再次写回 fallback 语义,能够被自动报出
- 完成记录:
- 已修正 `EditorConsoleSink.md``GetInstance.md``Destructor.md`
- 已修正 `Managers.md``ProjectManager` 的职责概述
- `docs/api/_tools/audit_api_docs.py` 已新增针对 `EditorConsoleSink` 旧 fallback 生命周期表述的定向检测
## 现阶段优先级建议
- 当前这份实时任务池里的已知问题已全部收口
- `T01``T02``T03``T05``T06``T07``T09` 都已完成,不再作为并行入口重复认领
- 若工作树继续新增 API 或计划文件继续追加任务块,再按新增内容开新任务
## 一句话结论
旧任务池解决了“API 文档树有没有建起来”的问题;这份实时任务池目前已经把 Editor 旧迁移链路、Components 资产引用协议、跨模块总览口径、`SceneViewportRenderPlan.h` 的缺页,以及 `EditorConsoleSink` 生命周期文档失准全部收口,后续只需要继续跟踪新增 API 与新增计划任务。

View File

@@ -0,0 +1,600 @@
# API 文档实时同步任务池2026-04-03第二轮
## 文档定位
这份任务池接替已归档的第一轮计划:
- `docs/plan/used/API文档实时同步任务池_2026-04-03_第一轮归档.md`
第一轮已经解决的重点是:
- canonical 目录结构收口
- 历史缺页补齐
- 第一轮大规模内容重写
本轮重点不再是“补结构”,而是:
- 重新对照当前工作树源码与测试
- 清理最近重构后重新出现的内容级失配
- 继续维护一份适合多人并行认领的增量同步清单
## 当前复核快照
- 最近一次结构审计时间:`2026-04-03 16:21:55`
- 审计命令:`python -B docs/api/_tools/audit_api_docs.py`
- 当前结果:
- `Public headers: 244`
- `Editor source headers: 126`
- `Invalid header refs: 0`
- `Invalid source refs: 0`
- `Broken .md links: 0`
- `Stale canonical doc tokens: 0`
- `Stale editor doc tokens: 0`
- `Stale editor canonical pages: 0`
这说明当前结构层面已经恢复全绿;本轮已确认的内容级失配也已收口,后续以持续巡检为主。
## 认领规则
- 一次只认领 `1` 个任务块。
- 先把 `状态` 改成 `DOING`,再写 `认领人`
- 只能改自己任务块的 `写入范围`
- 所有改动都必须以“当前源码 + 当前测试 + 当前真实调用链”为依据,不允许按旧文档续写旧行为。
- 如果清理了过期 API 页面,必须同时清理交叉链接。
## 任务池
## T01 Editor / Viewport 渲染计划与宿主流程内容同步
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P0`
- 写入范围:
- `docs/api/XCEngine/Editor/Viewport/SceneViewportRenderPlan/**`
- `docs/api/XCEngine/Editor/Viewport/ViewportHostRenderFlowUtils/**`
- `docs/api/XCEngine/Editor/Viewport/ViewportHostService/**`
- 必要时 `docs/api/XCEngine/Editor/Viewport/IViewportHostService/**`
- 主要源码依据:
- `editor/src/Viewport/SceneViewportRenderPlan.h`
- `editor/src/Viewport/ViewportHostRenderFlowUtils.h`
- `editor/src/Viewport/ViewportHostService.h`
- `tests/editor/test_viewport_render_flow_utils.cpp`
- 已关闭问题:
- 旧文档仍把 Scene View 当前主路径写成 builtin post-process 主导
- 没写清 grid / selection outline 现在已转为显式 `postScenePasses`
- 没写清 overlay pass 是 `editorOverlayFrameData + transientOverlayFrameData` 合并后再创建
- 没写清 `Scene object id shader view is unavailable` 是局部降级警告,不是整帧失败
- 完成记录:
- 已重写 `SceneViewportRenderPlan.md``BuildSceneViewportRenderPlan.md``ApplySceneViewportRenderPlan.md`
- 已同步 `ViewportHostRenderFlowUtils.md``ViewportHostService.md``RenderRequestedViewports.md`
- 已清理 `IViewportHostService` 中残留的旧表述
## T02 Core / Asset 缓存接口改名与语义重构同步
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P0`
- 写入范围:
- `docs/api/XCEngine/Core/Asset/ResourceManager/**`
- `docs/api/XCEngine/Core/Asset/AssetImportService/**`
- `docs/api/XCEngine/Core/Asset/ProjectAssetIndex/**`
- 必要时 `docs/api/XCEngine/Core/Asset/Asset.md`
- 必要时 `docs/api/XCEngine/Core/Asset/ArtifactFormats/**`
- 主要源码依据:
- `engine/include/XCEngine/Core/Asset/ResourceManager.h`
- `engine/src/Core/Asset/ResourceManager.cpp`
- `engine/include/XCEngine/Core/Asset/AssetImportService.h`
- `engine/src/Core/Asset/AssetImportService.cpp`
- `engine/include/XCEngine/Core/Asset/ProjectAssetIndex.h`
- `engine/src/Core/Asset/ProjectAssetIndex.cpp`
- `tests/core/Asset/test_resource_manager.cpp`
- 已关闭问题:
- `RefreshAssetDatabase` 已经不存在,但旧文档仍在沿用
- `RefreshProjectAssets` / `RebuildProjectAssetCache` / `GetProjectLibraryRoot` 缺页或未写清
- `AssetImportService::EnsureArtifact()` 旧文档仍把输出写成 `ResolvedAsset`
- `BuildLookupSnapshot()` 旧文档仍按“双 map 出参”描述,而不是 `LookupSnapshot`
- `ImportedAsset::runtimeLoadPath` 语义未同步到上层文档
- 完成记录:
- 已删除过期页 `ResourceManager/RefreshAssetDatabase.md`
- 已补齐 `RefreshProjectAssets.md``RebuildProjectAssetCache.md``GetProjectLibraryRoot.md`
- 已补齐 `LookupSnapshot.md``ImportedAsset.md``GetLibraryRoot.md``RebuildLibraryCache.md`
- 已同步 `Asset.md``ArtifactFormats.md``ResourceManager/Load.md``runtimeLoadPath` 口径
## T03 Scripting / Mono 托管销毁入口同步
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P1`
- 写入范围:
- `docs/api/XCEngine/Scripting/Mono/MonoScriptRuntime/**`
- 主要源码依据:
- `engine/include/XCEngine/Scripting/Mono/MonoScriptRuntime.h`
- `engine/src/Scripting/Mono/MonoScriptRuntime.cpp`
- `tests/scripting/test_mono_script_runtime.cpp`
- 已关闭问题:
- `DestroyManagedObject(MonoObject*)` 已进入头文件与测试,但文档树没有对应页面
- `MonoScriptRuntime.md` 没写清 `Object.Destroy(...)` 会回落到原生对象 / 组件销毁
- 完成记录:
- 已新增 `DestroyManagedObject.md`
- 已更新 `MonoScriptRuntime.md` 的 internal call 说明与方法总表
## T04 Cross-Module / 教程层与模块总览口径持续复核
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P2`
- 写入范围:
- `docs/api/_guides/**`
- `docs/api/XCEngine/*/*.md`
- 仅限与本轮已确认 API 变更直接相关的总览页
- 任务目标:
- 继续检查教程页、模块总览页是否仍在传播旧心智模型
- 尤其关注:
- Scene View 仍被写成 builtin post-process 主导
- 资源导入链仍被写成 `artifactMainPath` / `RefreshAssetDatabase` 时代的口径
- 托管对象销毁路径未在教程层被解释
- 产出要求:
- 只修正已确认失配的 guide / overview 页面
- 不做与当前源码无关的泛化扩写
- 完成记录:
- 已完成一轮 guide / overview 复核
- 已确认 `GameObject / Scene` 教程层仍在传播“tag 只是 name 别名”的旧心智
- 已把后续需要实改的页面收口到 `T08`
## T05 增量变更监控 / 新一轮差异发现
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P2`
- 写入范围:
- 只读检查 `engine/include/**``engine/src/**``editor/src/**``tests/**`
- 必要时只向本任务池追加新任务块
- 任务目标:
- 继续结合工作树最新改动,找出新的“源码已变但文档还没跟上”的内容级失配
- 优先检查:
- 最近改动过的 public headers
- 最近改动过的 Editor source headers
- 最近新增或更新过的测试
- 产出要求:
- 只记录已确认的问题
- 每条新任务都要写明:
- 受影响文档
- 主要源码依据
- 真实失配点
- 建议写入范围
- 完成记录:
- 已重新扫描当前工作树改动过的 public header、Editor source header、实现文件和测试
- 已确认并追加 `T08``T09` 两组新的内容级失配
## T06 Rendering / Camera request、Passes 与执行链旧口径清理
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P1`
- 写入范围:
- `docs/api/XCEngine/Rendering/CameraRenderRequest/**`
- `docs/api/XCEngine/Rendering/CameraRenderer/**`
- `docs/api/XCEngine/Rendering/Passes/**`
- `docs/api/XCEngine/Rendering/ObjectIdPass/**`
- `docs/api/XCEngine/Rendering/RenderPipeline/**`
- `docs/api/XCEngine/Rendering/SceneRenderer/**`
- `docs/api/XCEngine/Editor/Viewport/SceneViewportRenderPlan/**`
- `docs/api/XCEngine/Editor/Viewport/Passes/**`
- 必要时 `docs/api/XCEngine/Editor/Viewport/Viewport.md`
- 必要时 `docs/api/XCEngine/XCEngine.md`
- 必要时 `docs/api/_tools/audit_api_docs.py`
- 主要源码依据:
- `engine/include/XCEngine/Rendering/CameraRenderRequest.h`
- `engine/include/XCEngine/Rendering/CameraRenderer.h`
- `engine/include/XCEngine/Rendering/Passes/BuiltinObjectIdPass.h`
- `engine/include/XCEngine/Rendering/Passes/BuiltinObjectIdOutlinePass.h`
- `engine/include/XCEngine/Rendering/Passes/BuiltinInfiniteGridPass.h`
- `engine/include/XCEngine/Rendering/ObjectIdPass.h`
- `engine/include/XCEngine/Rendering/RenderPipeline.h`
- `engine/include/XCEngine/Rendering/SceneRenderer.h`
- `engine/src/Rendering/CameraRenderer.cpp`
- `engine/src/Rendering/SceneRenderer.cpp`
- `tests/Rendering/unit/test_camera_scene_renderer.cpp`
- `editor/src/Viewport/SceneViewportRenderPlan.h`
- `editor/src/Viewport/Passes/SceneViewportGridPass.cpp`
- `editor/src/Viewport/Passes/SceneViewportSelectionOutlinePass.cpp`
- `editor/src/Viewport/ViewportHostRenderFlowUtils.h`
- `tests/Editor/test_viewport_render_flow_utils.cpp`
- `tests/Editor/test_scene_viewport_overlay_renderer.cpp`
- 已关闭问题:
- `CameraRenderRequest.md` 仍描述已删除的 `builtinPostProcess` 子请求
- 页面仍链接到不存在的 `BuiltinPostProcessRequest/BuiltinPostProcessRequest.md`
- Scene View 已改为通过 `postScenePasses` / `overlayPasses` 写回 request但该页口径未同步
- `CameraRenderer.md` 仍保留已删除的 `m_builtinPostProcessBuilder` 历史口径
- `Passes.md` 的典型链路只写了 `postScenePasses`,遗漏当前 `overlayPasses` 组装路径
- `Rendering/Passes` 下仍残留已删除的 `BuiltinPostProcessPassPlan` / `BuiltinPostProcessPassSequenceBuilder` 页面
- `BuiltinObjectIdPass``BuiltinInfiniteGridPass` 多个公开入口缺页
- `ObjectIdPass.md``RenderPipeline.md``SceneRenderer.md` 与顶层 `XCEngine.md` 仍在传播 builtin-post-process 心智模型
- 完成记录:
- 已重写 `CameraRenderRequest.md`
- 已清理 `2` 个失效 `.md` 链接
- 已同步 `CameraRenderer.md``Passes.md` 的当前执行链路表述
- 已删除 `BuiltinPostProcessPassPlan.md``BuiltinPostProcessPassSequenceBuilder.md`
- 已补齐 `BuiltinObjectIdPass` / `BuiltinInfiniteGridPass` 缺失页面,并补充 `SceneViewportRenderPlan` 下 grid / selection outline pass factory 页面
- 已新增 `SceneViewportGridPass` / `SceneViewportSelectionOutlinePass` 页面,并同步 `Editor/Viewport/Passes/Passes.md``Viewport.md` 的当前口径
- 已同步 `ObjectIdPass.md``RenderPipeline.md``SceneRenderer.md``XCEngine.md` 的当前口径
- 已补充 Rendering guide、`CameraRenderer::Render``ViewportHostService::RenderRequestedViewports` 的 request 级 pass 注入说明
- 已为 `builtinPostProcess` / `BuiltinPostProcessRequest` / `m_builtinPostProcessBuilder` 增加 canonical 过期符号审计
- 已复跑结构审计并确认 `Broken .md links: 0`
## T07 Editor / Core `EditorConsoleSink` 生命周期说明同步
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P1`
- 写入范围:
- `docs/api/XCEngine/Editor/Core/EditorConsoleSink/**`
- 必要时 `docs/api/XCEngine/Editor/Managers/Managers.md`
- 必要时 `docs/api/_tools/audit_api_docs.py`
- 主要源码依据:
- `editor/src/Core/EditorConsoleSink.h`
- `editor/src/Core/EditorConsoleSink.cpp`
- `editor/src/panels/ConsolePanel.cpp`
- `editor/src/Core/EditorLoggingSetup.h`
- `tests/Editor/test_editor_console_sink.cpp`
- 已关闭问题:
- `EditorConsoleSink::GetInstance()` 旧文档仍把它写成会返回 fallback 实例
- 相关 overview 页面没有写清活动 sink 销毁后会返回 `nullptr`
- 审计脚本此前无法自动拦截这类旧生命周期表述
- 完成记录:
- 已同步 `EditorConsoleSink.md``GetInstance.md``Destructor.md`
- 已同步 `Managers.md` 中对控制台 sink 生命周期的引用口径
- 已为 `fallback 实例` 与“不会返回空指针”旧表述增加定向审计
## T08 Components / Scene / Scripting `GameObject` tag-layer 语义同步
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P0`
- 写入范围:
- `docs/api/XCEngine/Components/GameObject/**`
- `docs/api/XCEngine/Scene/Scene/**`
- `docs/api/XCEngine/Scripting/Mono/MonoScriptRuntime/**`
- 必要时 `docs/api/_guides/Components/GameObject-Component-Lifecycle-And-Serialization.md`
- 必要时 `docs/api/_guides/Scene/Scene-Lifecycle-And-Serialization.md`
- 主要源码依据:
- `engine/include/XCEngine/Components/GameObject.h`
- `engine/src/Components/GameObject.cpp`
- `engine/src/Scene/Scene.cpp`
- `engine/src/Scripting/Mono/MonoScriptRuntime.cpp`
- `managed/XCEngine.ScriptCore/GameObject.cs`
- `managed/XCEngine.ScriptCore/Component.cs`
- `managed/XCEngine.ScriptCore/InternalCalls.cs`
- `tests/Components/test_game_object.cpp`
- `tests/Scene/test_scene.cpp`
- `tests/scripting/test_mono_script_runtime.cpp`
- 已确认问题:
- `GameObject.md` 仍写“没有真正的 tag 系统”,并把 `FindGameObjectsWithTag()` 描述成按名字匹配;这与当前 `m_tag` / `CompareTag()` / `SetTag()` 实现已不符
- `Scene.md``FindGameObjectWithTag.md` 仍在传播“按名字查 tag”的旧口径
- `GameObject` 目录缺少 `GetTag.md``SetTag.md``CompareTag.md``GetLayer.md``SetLayer.md`
- `Serialize.md` / `Deserialize.md` 尚未同步 `tag=` 字段、默认 `Untagged` 以及 layer clamp 语义
- `MonoScriptRuntime` 总览页尚未解释 Unity 风格 `GameObject.tag` / `layer` / `CompareTag()` 已通过 internal call 暴露到托管侧
- 产出要求:
- 类型页与方法页都要明确区分当前原生实现、场景查询语义和托管暴露语义
- 教程页要从“tag 只是名字别名”改成“当前已有独立 tag 字段,但仍是轻量 Unity 风格模型”
- 需要写清:空 tag 会回落到 `Untagged`layer 会 clamp 到 `[0, 31]`
- 完成记录:
- 已重写 `GameObject.md``Scene.md``FindGameObjectWithTag.md`
- 已补齐 `GetTag.md``SetTag.md``CompareTag.md``GetLayer.md``SetLayer.md`
- 已同步 `Serialize.md` / `Deserialize.md``tag=``layer=``Untagged` 与 clamp 语义
- 已同步 `MonoScriptRuntime.md` 对托管 `GameObject.tag` / `layer` / `CompareTag()` 的 internal call 桥接说明
- 已同步 `GameObject-Component-Lifecycle-And-Serialization.md``Scene-Lifecycle-And-Serialization.md` 的心智模型口径
- 已补充 `Constructor``AddComponent``SetActive``SetParent``IsActive``IsActiveInHierarchy``Find``FindObjectsOfType``Awake``Start``Update``FixedUpdate``LateUpdate``OnDestroy``Destroy` 的真实生命周期与查询语义
## T09 Resources / Material 与材质 Artifact v2 语义同步
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P0`
- 写入范围:
- `docs/api/XCEngine/Resources/Material/**`
- `docs/api/XCEngine/Core/Asset/ArtifactFormats/**`
- `docs/api/XCEngine/Core/Asset/AssetDatabase/**`
- 必要时 `docs/api/XCEngine/Core/Asset/Asset.md`
- 主要源码依据:
- `engine/include/XCEngine/Resources/Material/Material.h`
- `engine/src/Resources/Material/Material.cpp`
- `engine/src/Resources/Material/MaterialLoader.cpp`
- `engine/include/XCEngine/Core/Asset/ArtifactFormats.h`
- `engine/src/Core/Asset/AssetDatabase.cpp`
- `tests/Resources/Material/test_material.cpp`
- `tests/Resources/Material/test_material_loader.cpp`
- 已确认问题:
- `Resources/Material/Material.md` 仍是旧模板式总览,没有覆盖当前公开语义
- `Material` 目录缺少 `SetTextureAssetRef.md``GetTextureBindingAssetRef.md``GetTextureBindingLoadedTexture.md`
- `ArtifactFormats.md` 仍写 `kMaterialArtifactSchemaVersion = 1`、magic `XCMAT01`,与当前 schema v2 / `XCMAT02` 不符
- 材质 artifact 文档还没写清每个 texture binding 现在会序列化“编码后的 `AssetRef` + 可选 artifact/path 字符串”
- `Material` 文档尚未解释纹理绑定现在既有 loaded handle也有稳定 `AssetRef` 元数据,并且 `GetTexture()` 可在首次访问时通过 `TryResolveAssetPath()` 兑现延迟资源
- 产出要求:
- 重写 `Material.md`,把 shader 属性、texture binding 元数据、lazy resolve、路径与 `AssetRef` 的边界写清
- 为新增公开方法补页,并把现有 `SetTexture` / `GetTexture` / `GetTextureBindingCount` 等页面更新到当前实现
- 更新 `ArtifactFormats.md``AssetDatabase` 相关页面,写清材质 artifact v2 的字段顺序、兼容边界和设计动机
- 完成记录:
- 已重写 `docs/api/XCEngine/Resources/Material/Material.md``docs/api/XCEngine/Resources/Material/Material/Material.md`
- 已新增 `SetTextureAssetRef.md``SetTexturePath.md``GetTextureBindingName.md``GetTextureBindingAssetRef.md``GetTextureBindingPath.md``GetTextureBindingLoadedTexture.md``GetTextureBindingTexture.md`
- 已同步 `SetTexture.md``GetTexture.md``GetTextureBindingCount.md` 的当前 lazy-load 与 binding metadata 语义
- 已更新 `ArtifactFormats.md`,把材质 artifact 修正到 schema v2 / `XCMAT02`,并写清 texture binding 三元组布局
- 已更新 `AssetDatabase.md` 的当前 importerVersion 常量,并在 `Asset.md` 补充 `.xcmat` v2 的跨模块说明
- 已为旧 `kMaterialArtifactSchemaVersion = 1` / `XCMAT01` 文案增加审计回归保护
- 已复跑结构审计并确认 `Broken .md links: 0`
## T10 Editor / Viewport `SceneViewportShaderPaths` canonical 补页
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P1`
- 写入范围:
- `docs/api/XCEngine/Editor/Viewport/SceneViewportShaderPaths/**`
- 必要时 `docs/api/XCEngine/Editor/Viewport/Viewport.md`
- 主要源码依据:
- `editor/src/Viewport/SceneViewportShaderPaths.h`
- `editor/src/Viewport/Passes/SceneViewportGridPass.cpp`
- `editor/src/Viewport/Passes/SceneViewportSelectionOutlinePass.cpp`
- 已关闭问题:
- `editor/src/Viewport/SceneViewportShaderPaths.h` 新进入工作树后还没有 canonical 页面
- 结构审计一度出现 `Editor source headers: 125``Valid source refs (Editor canonical): 124`
- 完成记录:
- 已新增 `SceneViewportShaderPaths.md` 与 5 个 helper/function 页面
- 已同步 `Viewport.md` 的目录结构总览
- 已复跑结构审计并确认 `Valid source refs (Editor canonical): 125`
## T11 Platform / 概述页与方法页模板化表述清理
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P1`
- 写入范围:
- `docs/api/XCEngine/Platform/**`
- 主要源码依据:
- `engine/include/XCEngine/Platform/GameTime.h`
- `engine/include/XCEngine/Platform/PlatformTypes.h`
- `engine/include/XCEngine/Platform/IClock.h`
- `engine/include/XCEngine/Platform/IWindow.h`
- `engine/include/XCEngine/Platform/IFileSystem.h`
- `engine/include/XCEngine/Platform/IPlatform.h`
- `engine/include/XCEngine/Platform/IDynamicLibrary.h`
- `engine/include/XCEngine/Platform/IDisplayEnumerator.h`
- `engine/include/XCEngine/Platform/Window.h`
- `engine/include/XCEngine/Platform/Windows/WindowsWindow.h`
- `engine/include/XCEngine/Platform/Windows/WindowsInputModule.h`
- `engine/src/Platform/Window.cpp`
- `engine/src/Platform/Windows/WindowsWindow.cpp`
- `engine/src/Platform/Windows/WindowsInputModule.cpp`
- 已关闭问题:
- `Platform` 下多组概述页仍把自己写成“canonical 总览”,没有说明符号本身的职责和边界
- 大量方法页仍残留“获取相关状态或对象”“公开方法,详见头文件声明”“参数语义详见头文件声明”等模板废话
- `WindowsInputModule::PumpEvents()` 当前是空实现,但旧页没有说明,容易误导成真实消息泵入口
- `WindowsWindow` 的 Win32 当前实现路径没有写清,例如 `Create()``Destroy()``PumpEvents()``SetFullscreen()``ShouldClose()`
- 完成记录:
- 已重写 `GameTime``PlatformTypes``IClock``IWindow``IFileSystem``IPlatform``IDynamicLibrary``IDisplayEnumerator``Window``WindowsWindow``WindowsInputModule` 相关 overview 与方法页
- 已把 `Platform` 下残留模板短语、参数占位语和 canonical 占位说明清理到 `0`
- 已写清 `Window` / `WindowsWindow` / `WindowsInputModule` 的当前实现语义与输入桥接关系
- 已复跑结构审计并确认 `Old template pages: 0``Broken .md links: 0`
## T12 Cross-Module / canonical 式概述废话清理
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P1`
- 写入范围:
- `docs/api/XCEngine/RHI/D3D12/**`
- `docs/api/XCEngine/Resources/**`
- 主要源码依据:
- `engine/include/XCEngine/RHI/D3D12/D3D12Types.h`
- `engine/include/XCEngine/RHI/D3D12/D3D12Common.h`
- `engine/include/XCEngine/RHI/D3D12/D3D12Enums.h`
- `engine/include/XCEngine/RHI/D3D12/D3D12RootSignature.h`
- `engine/include/XCEngine/RHI/D3D12/D3D12PipelineState.h`
- `engine/include/XCEngine/Resources/Resources.h`
- `engine/include/XCEngine/Resources/Texture/Texture.h`
- `engine/include/XCEngine/Resources/Texture/TextureLoader.h`
- `engine/include/XCEngine/Resources/Texture/TextureImportSettings.h`
- `engine/include/XCEngine/Resources/Mesh/Mesh.h`
- `engine/include/XCEngine/Resources/Mesh/MeshLoader.h`
- `engine/include/XCEngine/Resources/Mesh/MeshImportSettings.h`
- `engine/include/XCEngine/Resources/Shader/Shader.h`
- `engine/include/XCEngine/Resources/Shader/ShaderLoader.h`
- `engine/include/XCEngine/Resources/AudioClip/AudioClip.h`
- `engine/include/XCEngine/Resources/AudioClip/AudioLoader.h`
- 已关闭问题:
- `RHI/D3D12``Resources` 下仍有一批 overview 页把“概述”写成“当前页面作为平行目录中的 canonical 总览”,没有解释符号本身做什么
- `Texture``Mesh``Shader``AudioClip` 等资源类型页没有把类型边界、持有的数据和辅助声明写清
- `D3D12Types``D3D12Common``D3D12Enums` 这类 helper header 页没有说明它们是转换 / 构造 / 检查函数集合
- 完成记录:
- 已重写 `RHI/D3D12``Resources` 下全部 `16` 个 canonical 式 overview 页
- 已把全仓库 `docs/api/XCEngine/**` 中“当前页面作为平行目录中的 canonical 总览”这类概述废话清理到 `0`
- 已复跑结构审计并确认 `Broken .md links: 0``Old template pages: 0`
## T13 Components / `GameObject` 剩余辅助页内容化补齐
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P2`
- 写入范围:
- `docs/api/XCEngine/Components/GameObject/DetachChildren.md`
- `docs/api/XCEngine/Components/GameObject/DetachFromParent.md`
- `docs/api/XCEngine/Components/GameObject/Destructor.md`
- `docs/api/XCEngine/Components/GameObject/GetChild.md`
- `docs/api/XCEngine/Components/GameObject/GetChildCount.md`
- `docs/api/XCEngine/Components/GameObject/GetChildren.md`
- `docs/api/XCEngine/Components/GameObject/GetComponent.md`
- `docs/api/XCEngine/Components/GameObject/GetComponentInChildren.md`
- `docs/api/XCEngine/Components/GameObject/GetComponentInParent.md`
- `docs/api/XCEngine/Components/GameObject/GetComponents.md`
- `docs/api/XCEngine/Components/GameObject/GetComponentsInChildren.md`
- `docs/api/XCEngine/Components/GameObject/GetID.md`
- `docs/api/XCEngine/Components/GameObject/GetName.md`
- `docs/api/XCEngine/Components/GameObject/GetParent.md`
- `docs/api/XCEngine/Components/GameObject/GetScene.md`
- `docs/api/XCEngine/Components/GameObject/GetTransform.md`
- `docs/api/XCEngine/Components/GameObject/GetUUID.md`
- `docs/api/XCEngine/Components/GameObject/RemoveComponent.md`
- `docs/api/XCEngine/Components/GameObject/SetName.md`
- 主要源码依据:
- `engine/include/XCEngine/Components/GameObject.h`
- `engine/src/Components/GameObject.cpp`
- `tests/Components/test_game_object.cpp`
- `tests/Scene/test_scene.cpp`
- `tests/scripting/test_mono_script_runtime.cpp`
- 已关闭问题:
- `GameObject` 模块的核心生命周期、tag/layer 与场景边界已经完成,但上述辅助页仍残留模板式表述
- 这些页面尚未写清模板接口的真实语义,例如 `Transform` 特例、层级递归查询、观察指针返回与移除边界
- 产出要求:
- 把这些方法页全部改成基于当前源码的行为说明
- 优先写清组件查询模板、层级辅助接口和对象身份访问器的真实边界
- 不重复改动本轮已经完成内容化的生命周期和 tag/layer 页面
- 完成记录:
- 已重写 `DetachChildren.md``DetachFromParent.md``Destructor.md``GetChild.md``GetChildCount.md``GetChildren.md`
- 已重写 `GetComponent.md``GetComponentInChildren.md``GetComponentInParent.md``GetComponents.md``GetComponentsInChildren.md``RemoveComponent.md`
- 已重写 `GetID.md``GetName.md``GetParent.md``GetScene.md``GetTransform.md``GetUUID.md``SetName.md`
- 已写清 `Transform` 特例、层级查询顺序、`Scene` / registry 观察指针语义,以及 `RemoveComponent` 当前不会补发 `OnDestroy()`
## T14 Rendering / `RenderMaterialUtility` schema-driven 材质常量 payload 语义同步
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P1`
- 写入范围:
- `docs/api/XCEngine/Rendering/RenderMaterialUtility/**`
- `docs/api/XCEngine/Rendering/Pipelines/BuiltinForwardPipeline/**`
- 必要时 `docs/api/_tools/audit_api_docs.py`
- 主要源码依据:
- `engine/include/XCEngine/Rendering/RenderMaterialUtility.h`
- `engine/include/XCEngine/Rendering/Pipelines/BuiltinForwardPipeline.h`
- `engine/src/Rendering/Pipelines/BuiltinForwardPipeline.cpp`
- `engine/include/XCEngine/Resources/Material/Material.h`
- `tests/Rendering/unit/test_render_scene_extractor.cpp`
- 已关闭问题:
- `RenderMaterialUtility` 总览页尚未覆盖新进入 public header 的 `MaterialConstantPayloadView``ResolveSchemaMaterialConstantPayload(...)`
- `BuiltinForwardPipeline.md` 仍把逐材质常量写成“目前只写入 `baseColorFactor`”,没有同步当前优先消费 schema-driven payload、仅在缺失时回退 fallback 的实现
- `BuildBuiltinForwardMaterialData.md` 还没把自己定位成兼容 fallback helper容易与当前主路径混淆
- 完成记录:
- 已新增 `BuiltinForwardMaterialData.md``MaterialConstantPayloadView.md``ResolveSchemaMaterialConstantPayload.md`
- 已重写 `RenderMaterialUtility.md``BuildBuiltinForwardMaterialData.md`,写清 schema payload 与 builtin forward fallback 的边界
- 已同步 `BuiltinForwardPipeline.md``Render.md`,补入 `Material::GetConstantBufferData()` 主路径和 `FallbackPerMaterialConstants` 回退逻辑
- 已为“逐材质常量目前只写入 `baseColorFactor`”等旧口径增加 canonical 审计回归保护
- 已复跑结构审计并确认 `Stale canonical doc tokens: 0`
## T15 Editor / Scripting 脚本程序集重建与运行时锁语义同步
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P1`
- 写入范围:
- `docs/api/XCEngine/Editor/Scripting/EditorScriptAssemblyBuilder/**`
- `docs/api/XCEngine/Editor/Application/RebuildScriptingAssemblies.md`
- 必要时 `docs/api/XCEngine/Editor/Application/Application.md`
- 主要源码依据:
- `editor/src/Scripting/EditorScriptAssemblyBuilder.cpp`
- `editor/src/Application.cpp`
- `tests/Editor/test_editor_script_assembly_builder.cpp`
- 已关闭问题:
- `EditorScriptAssemblyBuilder` 文档仍把 `mscorlib.dll` 写成“每次重建都复制”,没有同步当前“首次复制、后续复用项目本地 corlib”的实现
- `RebuildProjectAssemblies.md` 没写清活动 Mono runtime 仍持有 `GameScripts.dll` 时可能出现文件锁失败
- `Application::RebuildScriptingAssemblies` 文档仍写“构建失败会保留旧 runtime”与当前先 `ShutdownScriptingRuntime()` 再构建的实现不符
- 完成记录:
- 已同步 `EditorScriptAssemblyBuilder.md``RebuildProjectAssemblies.md`,补入项目本地 `mscorlib.dll` 复用策略、Mono 文件锁失败路径与测试锚点
- 已同步 `Application::RebuildScriptingAssemblies``Application.md`,写清“先卸载当前 runtime 释放程序集锁,再重建并在成功后重载”的真实顺序
- 已复跑结构审计并确认 `Broken .md links: 0``Stale canonical doc tokens: 0`
## T16 Resources / Rendering Passes SceneView shader ownership 口径同步
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P1`
- 写入范围:
- `docs/api/XCEngine/Resources/BuiltinResources/**`
- `docs/api/XCEngine/Rendering/Passes/BuiltinInfiniteGridPass/**`
- `docs/api/XCEngine/Rendering/Passes/BuiltinObjectIdOutlinePass/**`
- 主要源码依据:
- `engine/include/XCEngine/Resources/BuiltinResources.h`
- `engine/src/Resources/BuiltinResources.cpp`
- `engine/include/XCEngine/Rendering/Passes/BuiltinInfiniteGridPass.h`
- `engine/src/Rendering/Passes/BuiltinInfiniteGridPass.cpp`
- `engine/include/XCEngine/Rendering/Passes/BuiltinObjectIdOutlinePass.h`
- `engine/src/Rendering/Passes/BuiltinObjectIdOutlinePass.cpp`
- `editor/src/Viewport/SceneViewportShaderPaths.h`
- 已关闭问题:
- `BuiltinResources.md` 仍把 `object-id-outline` / `infinite-grid` 写成 engine `builtin://shaders/*` helper 与 builtin shader 工厂的一部分,但当前头文件与实现已只保留 `forward-lit``object-id`
- `BuiltinInfiniteGridPass``BuiltinObjectIdOutlinePass` 已改为由调用方注入 `shaderPath`,文档却仍在传播“固定 builtin shader”口径
- 两个 pass 的文档树缺少 `SetShaderPath.md``GetShaderPath.md``BuiltinInfiniteGridPass` 还缺少 `Constructor.md``Destructor.md`
- 完成记录:
- 已更新 `BuiltinResources.md`,把 builtin shader 集合收口到 `forward-lit` / `object-id`,并写清 Scene View grid / outline shader 现在由 editor 侧 `SceneViewportShaderPaths` 提供
- 已重写 `BuiltinInfiniteGridPass.md``Render.md``Shutdown.md`,补上 `Constructor.md``Destructor.md``SetShaderPath.md``GetShaderPath.md`
- 已重写 `BuiltinObjectIdOutlinePass.md``Constructor.md``Render.md``Shutdown.md`,补上 `SetShaderPath.md``GetShaderPath.md`
## T17 Editor / Viewport `SceneViewportOverlayProviders` canonical 补页
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P1`
- 写入范围:
- `docs/api/XCEngine/Editor/Viewport/SceneViewportOverlayProviders/**`
- 主要源码依据:
- `editor/src/Viewport/SceneViewportOverlayProviders.h`
- `editor/src/Viewport/SceneViewportOverlayProviders.cpp`
- `editor/src/Viewport/SceneViewportOverlayBuilder.h`
- `tests/editor/test_scene_viewport_overlay_providers.cpp`
- 已关闭问题:
- `editor/src/Viewport/SceneViewportOverlayProviders.h` 新进入工作树后还没有 canonical 页面
- 结构审计出现 `Editor source headers: 126``Valid source refs (Editor canonical): 125`
- 缺少对 overlay build context、provider registry 和默认相机 / 灯光 provider 工厂的当前语义说明
- 完成记录:
- 已新增 `SceneViewportOverlayProviders.md``SceneViewportOverlayBuildContext.md``ISceneViewportOverlayProvider.md``SceneViewportOverlayProviderRegistry.md`
- 已新增 `CreateSceneViewportCameraOverlayProvider.md``CreateSceneViewportLightOverlayProvider.md``BuildDefaultSceneViewportOverlayProviderRegistry.md`
- 已复跑结构审计并确认 `Valid source refs (Editor canonical): 126``Broken .md links: 0`
## T18 Editor / Viewport overlay builder provider 化口径同步
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P1`
- 写入范围:
- `docs/api/XCEngine/Editor/Viewport/SceneViewportOverlayBuilder/**`
- `docs/api/XCEngine/Editor/Viewport/ViewportHostService/**`
- `docs/api/XCEngine/Editor/Viewport/Viewport.md`
- 必要时 `docs/api/_guides/Editor/**`
- 主要源码依据:
- `editor/src/Viewport/SceneViewportOverlayBuilder.h`
- `editor/src/Viewport/SceneViewportOverlayBuilder.cpp`
- `editor/src/Viewport/SceneViewportOverlayProviders.h`
- `editor/src/Viewport/ViewportHostService.h`
- `tests/editor/test_scene_viewport_overlay_providers.cpp`
- 已关闭问题:
- `SceneViewportOverlayBuilder` 文档仍把类型写成“无状态构建器 + static Build(...)”,没有同步当前实例化 builder + provider registry 的实现
- `SceneViewportOverlayBuilder` 目录缺少 `Constructor.md``GetProviderRegistry.md`
- `ViewportHostService.md` 仍把基础 overlay 来源写成 `SceneViewportOverlayBuilder::Build(...)`,没有同步当前成员 `m_sceneViewportOverlayBuilder`
- guide 层仍在传播 `overlay builder -> overlay pass` 与“先把 scene icon 塞进 builder”的旧扩展口径
- 完成记录:
- 已重写 `SceneViewportOverlayBuilder.md``Build.md`,把默认 registry、build context 和 provider 聚合链路写清
- 已新增 `Constructor.md``GetProviderRegistry.md`
- 已同步 `ViewportHostService.md``Viewport.md` 以及两篇 Editor guide 的当前 provider 化心智模型
- 已把新扩展建议改成 `overlay provider -> overlay builder -> overlay pass`
## 当前结论
- 本轮已经关掉十七组明确的内容级失配:
- `Viewport` 渲染计划与宿主流程
- `Core/Asset` 缓存接口与导入服务语义
- `MonoScriptRuntime` 托管销毁入口
- `Rendering` 相机请求、Passes 与单相机执行链旧口径
- `EditorConsoleSink` 生命周期与空指针返回语义
- 跨模块 guide / overview 漂移的本轮复核与拆分
- `Material` / `ArtifactFormats` / `AssetDatabase` 的材质 artifact v2 与 texture `AssetRef` 语义
- `GameObject` / `Scene` / `Mono` 的 tag-layer 与托管暴露语义
- `GameObject` 剩余辅助访问器 / 层级辅助页的内容化补齐
- `SceneViewportShaderPaths` canonical 缺页
- `Platform` 模块概述页与方法页的模板化废话清理
- `RHI/D3D12``Resources` 的 canonical 式概述废话清理
- `RenderMaterialUtility` / `BuiltinForwardPipeline` 的 schema-driven 材质常量 payload 语义
- `Editor` 脚本程序集重建流程中的 corlib 复用与 runtime 文件锁语义
- `BuiltinResources` 与 Scene View grid / outline shader ownership、`shaderPath` 注入口径
- `SceneViewportOverlayProviders` canonical 缺页
- `SceneViewportOverlayBuilder` / `ViewportHostService` / guide 层的 provider 化心智模型同步
- 当前结构审计为全绿。
- 当前仍建议保留 `T04``T05` 作为持续性复核入口,用来承接后续源码变更带来的新文档漂移。

View File

@@ -0,0 +1,590 @@
# API 文档并行更新任务池2026-04-02
## 目的
基于 `2026-04-02` 当前工作树,这份清单用于把 API 文档更新任务拆成可并行认领的独立块,供多个会话同时推进。
## 认领规则
- 一次只认领 `1` 个任务块,先改 `状态``认领人`
- 只修改自己任务块的 `写入范围`,不要跨任务顺手改别的模块页。
-`T09` 之外,其他任务不要更新 `docs/api/_meta/rebuild-status.md`,避免多人冲突。
- 每个任务都要以源码、实现、测试、真实调用点为依据,不允许只按命名猜测行为。
- 如果任务执行中发现需要新增 guide统一放到 `docs/api/_guides/<Module>/` 下。
## 当前并行推荐
- 历史任务 `T01-T20` 已完成,本轮文档内容同步与收口已落地。
- 如果继续并行推进,重点不再是补历史缺页,而是:
- 跟踪新增源码 API
- 继续人工抽样审阅审计中提示的高风险单页目录
- `2026-04-03 00:24:08` 这轮复核后,已新增 `T21-T27`;优先从 `Input``Editor` 项目工作流、`Game View -> Runtime Input` 三块并行切入。
## 任务池
## T01 Editor / Viewport 子模块补齐与重写
- 状态: `DONE`
- 认领人: `Codex-Viewport`
- 优先级: `P0`
- 写入范围: `docs/api/XCEngine/Editor/Viewport/**``docs/api/XCEngine/Editor/panels/SceneViewPanel/**``docs/api/XCEngine/Editor/panels/ViewportPanelContent/**`
- 主要源码依据: `editor/src/Viewport/**``editor/src/panels/SceneViewPanel.*``editor/src/panels/ViewportPanelContent.h``tests/editor/test_scene_viewport_camera_controller.cpp`
- 当前缺口: `Viewport` 整个 canonical 树尚未建立;以下页面当前缺失: `SceneViewportCameraController``SceneViewportMoveGizmo``SceneViewportRotateGizmo``SceneViewportScaleGizmo``SceneViewportOverlayRenderer``ViewportHostService``ViewportHostRenderFlowUtils``SceneViewportEditorOverlayData``SceneViewportOverlayBuilder``ViewportPanelContent`
- 完成标准: 补齐 `Viewport/Viewport.md` 与所有类型页;`SceneViewPanel` 文档重写到当前 gizmo / overlay / host flow 实现;写清楚生命周期、交互链路、渲染路径和测试覆盖
## T02 Editor / ScriptComponentEditor 补齐
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P0`
- 写入范围: `docs/api/XCEngine/Editor/ComponentEditors/ScriptComponentEditor/**``docs/api/XCEngine/Editor/ComponentEditors/ScriptComponentEditorUtils/**``docs/api/XCEngine/Editor/ComponentEditors/ComponentEditors.md``docs/api/XCEngine/Editor/ComponentEditors/ComponentEditorRegistry/**`
- 主要源码依据: `editor/src/ComponentEditors/ScriptComponentEditor.h``editor/src/ComponentEditors/ScriptComponentEditorUtils.h``editor/src/ComponentEditors/ComponentEditorRegistry.cpp`
- 当前缺口: `ScriptComponentEditor``ScriptComponentEditorUtils` 还没有 canonical 页面;组件编辑器总览也需要纳入脚本组件编辑器
- 完成标准: 补齐缺页;说明 Inspector 侧脚本字段绘制、字段元数据来源、与 `ScriptEngine` / `ScriptComponent` 的关系
## T03 Core / AssetDatabase 新建与资产数据库链路说明
- 状态: `DONE`
- 认领人: `Codex-Asset`
- 优先级: `P0`
- 写入范围: `docs/api/XCEngine/Core/Asset/AssetDatabase/**``docs/api/XCEngine/Core/Asset/Asset.md`
- 主要源码依据: `engine/include/XCEngine/Core/Asset/AssetDatabase.h`、相关 `.cpp` 实现、项目目录下新增的 `.meta``Library` 资产缓存变化
- 当前缺口: `AssetDatabase` 对应的 canonical 类型页完全缺失;`Core/Asset` 模块总览需要反映新的数据库/导入缓存方向
- 完成标准: 建立 `AssetDatabase` 页面,明确 GUID、path、meta、导入缓存、查询职责以及它和 `ProjectPanel` / `ResourceManager` / 资源导入流程的关系
## T04 Rendering / Passes 子模块与 BuiltinObjectIdOutlinePass 补齐
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P0`
- 写入范围: `docs/api/XCEngine/Rendering/Passes/**`
- 主要源码依据: `engine/include/XCEngine/Rendering/Passes/BuiltinObjectIdOutlinePass.h``engine/src/Rendering/Passes/BuiltinObjectIdOutlinePass.cpp`
- 当前缺口: `Rendering/Passes` 目录当前没有 canonical 文档树;`BuiltinObjectIdOutlinePass` 页面缺失
- 完成标准: 新建 `Passes/Passes.md``BuiltinObjectIdOutlinePass` 类型页;写清楚对象 ID / 轮廓高亮的输入输出、依赖资源、典型使用位置和当前限制
## T05 Scripting 模块内容重构
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P1`
- 写入范围: `docs/api/XCEngine/Scripting/**``docs/api/_guides/Scripting/**`
- 主要源码依据: `engine/include/XCEngine/Scripting/IScriptRuntime.h``Mono/MonoScriptRuntime.h``NullScriptRuntime.h``ScriptComponent.h``ScriptEngine.h` 及对应 `.cpp``tests/scripting/**`
- 当前缺口: 结构存在,但脚本运行时、字段同步、项目脚本程序集、空运行时回退等内容需要按当前实现重写
- 完成标准: 明确运行时抽象、Mono 后端、Null 后端、字段存储与组件生命周期;必要时补一篇项目脚本程序集 / 字段同步 guide
## T06 Editor 运行时胶水层与面板内容更新
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P1`
- 写入范围: `docs/api/XCEngine/Editor/Application/**``docs/api/XCEngine/Editor/Core/EventBus/**``docs/api/XCEngine/Editor/panels/InspectorPanel/**``docs/api/XCEngine/Editor/panels/ProjectPanel/**``docs/api/XCEngine/Editor/UI/Widgets/**``docs/api/XCEngine/Editor/Actions/HierarchyActionRouter/**``docs/api/XCEngine/Editor/Commands/EntityCommands/**`
- 主要源码依据: `editor/src/Application.*``editor/src/Core/EventBus.h``editor/src/panels/InspectorPanel.*``editor/src/panels/ProjectPanel.*``editor/src/UI/Widgets.h``editor/src/Actions/HierarchyActionRouter.h``editor/src/Commands/EntityCommands.h`
- 当前缺口: 这些页面虽然大多存在,但内容容易落后于当前交互链路;`ProjectPanel` 虽已较新,仍要根据这轮源码变化做二次核对
- 完成标准: 把“Editor 主循环 -> EventBus -> 面板 -> Action/Command”这条链路写清楚Inspector/Project/Hierarchy 相关页内容与当前实现严格对齐
## T07 Rendering 相机请求与对象 ID 渲染链路更新
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P1`
- 写入范围: `docs/api/XCEngine/Rendering/CameraRenderRequest/**``docs/api/XCEngine/Rendering/CameraRenderer/**``docs/api/XCEngine/Rendering/RenderMaterialUtility/**``docs/api/XCEngine/Rendering/Rendering.md`
- 主要源码依据: `engine/include/XCEngine/Rendering/CameraRenderRequest.h``engine/src/Rendering/CameraRenderer.cpp``engine/src/Resources/Material/MaterialLoader.cpp``engine/src/Rendering/Passes/BuiltinObjectIdOutlinePass.cpp`
- 当前缺口: 文档需要反映这轮 renderer 里对象 ID、outline、camera request、材质 render state 的新关系
- 完成标准: 写清楚 camera request 的职责边界、camera renderer 的主流程、object-id/outline 的接入点,以及材质 render state 对渲染路径的影响
## T08 Components / MeshFilterComponent 与资源绑定链路更新
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P1`
- 写入范围: `docs/api/XCEngine/Components/MeshFilterComponent/**``docs/api/XCEngine/Components/Components.md`
- 主要源码依据: `engine/include/XCEngine/Components/MeshFilterComponent.h`、相关 `.cpp``tests/Resources/Mesh/test_mesh_loader.cpp``tests/Resources/Material/test_material_loader.cpp`
- 当前缺口: `MeshFilterComponent` 页面存在,但需要重新核对 mesh handle / path / 资源解析链路;模块总览也应补充 MeshFilter 在渲染和资产导入链路中的定位
- 完成标准: 说明 `MeshFilterComponent` 如何保存 mesh 引用、如何与资源系统和渲染提取流程衔接,以及当前限制
## T09 根总览与最终审计
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P2`
- 写入范围: `docs/api/XCEngine/XCEngine.md`、受影响的模块总览页、`docs/api/_meta/rebuild-status.md`
- 主要源码依据: 前面所有任务的完成结果
- 当前缺口: 已完成根总览与模块总览收口;`2026-04-02 23:22:27` 的最终审计结果显示 `246/246` 个 public headers 全量覆盖,结构性问题保持 `0`
- 完成标准: 在 `T10-T13` 完成后统一调整总览页导航;重新执行 `audit_api_docs.py`、覆盖校验与链接校验;确认未覆盖 public headers 归零后写回最终 `rebuild-status.md`
## 审计结论2026-04-02 23:22:27
- 本轮全量审计已执行: `python docs/api/_tools/audit_api_docs.py`
- 当前结构性问题为 `0`: 无失效 `.md` 链接、无非 `.md` 相对链接、无旧模板页面、无扁平 header 页面、无缺失目录总览页
- 当前剩余覆盖缺口: `0` 个 public headers 未覆盖
- 受影响模块:
- `Core`: `0`
- `Rendering`: `0`
- `Resources`: `0`
- `Scene`: `0`
- 说明:
- `T01-T13` 对应的结构重构、基础层补页与总览收口已全部落地
- `AssetImportService``ProjectAssetIndex` 两个 `Core/Asset` 尾项已补齐
- canonical API 文档树当前与 `engine/include/XCEngine` 的 public header 集合保持全量对齐
## T10 Core / Asset 标识与产物格式补齐
- 状态: `DONE`
- 认领人: `Codex-Asset2`
- 优先级: `P1`
- 写入范围: `docs/api/XCEngine/Core/Asset/ArtifactFormats/**``docs/api/XCEngine/Core/Asset/AssetGUID/**``docs/api/XCEngine/Core/Asset/AssetRef/**`
- 主要源码依据: `engine/include/XCEngine/Core/Asset/ArtifactFormats.h``engine/include/XCEngine/Core/Asset/AssetGUID.h``engine/include/XCEngine/Core/Asset/AssetRef.h`、相关使用点 `engine/src/Components/MeshFilterComponent.cpp``engine/src/Resources/*/*Loader.cpp``tests/core/Asset/test_resource_manager.cpp``tests/Resources/Texture/test_texture_loader.cpp`
- 当前缺口: 已补齐 `ArtifactFormats``AssetGUID``AssetRef` 三个 canonical 页面,并将资产身份 / 引用 / artifact 格式链路并入 `Core/Asset` 模块叙述
- 完成标准: 建立三个 canonical 类型页,写清楚 GUID 格式、AssetRef 结构语义、artifact 产物文件格式在资源导入与反序列化链路中的作用
## T11 Rendering / RenderPass 与 SceneRenderRequest 基础层补齐
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P1`
- 写入范围: `docs/api/XCEngine/Rendering/ObjectIdEncoding/**``docs/api/XCEngine/Rendering/ObjectIdPass/**``docs/api/XCEngine/Rendering/RenderPass/**``docs/api/XCEngine/Rendering/RenderSceneUtility/**``docs/api/XCEngine/Rendering/SceneRenderRequestPlanner/**``docs/api/XCEngine/Rendering/SceneRenderRequestUtils/**`
- 主要源码依据: `engine/include/XCEngine/Rendering/ObjectIdEncoding.h``ObjectIdPass.h``RenderPass.h``RenderSceneUtility.h``SceneRenderRequestPlanner.h``SceneRenderRequestUtils.h`,对应 `.cpp`,以及 `tests/Rendering/unit/test_render_pass.cpp``test_render_scene_utility.cpp``test_scene_render_request_planner.cpp``test_scene_render_request_utils.cpp``test_camera_scene_renderer.cpp``tests/Editor/test_viewport_render_flow_utils.cpp`
- 当前缺口: 已补齐 `ObjectIdEncoding``ObjectIdPass``RenderPass``RenderSceneUtility``SceneRenderRequestPlanner``SceneRenderRequestUtils` 六个基础层页面,并回写 Rendering 总览导航
- 完成标准: 补齐六个类型页,明确 render pass 生命周期、object-id 编解码语义、scene request 规划规则,以及这些基础设施与 `CameraRenderer` / editor viewport 的衔接
## T12 Resources / BuiltinResources 补齐
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P1`
- 写入范围: `docs/api/XCEngine/Resources/BuiltinResources/**`
- 主要源码依据: `engine/include/XCEngine/Resources/BuiltinResources.h``engine/src/Resources/BuiltinResources.cpp`、相关调用点 `editor/src/Commands/EntityCommands.h``engine/src/Rendering/Passes/BuiltinObjectIdPass.cpp``engine/src/Rendering/Passes/BuiltinObjectIdOutlinePass.cpp``engine/src/Rendering/Pipelines/BuiltinForwardPipeline.cpp``tests/Resources/Shader/test_shader_loader.cpp`
- 当前缺口: 已建立 `BuiltinResources` canonical 页面,并纳入 `Resources` 模块总览
- 完成标准: 建立 `BuiltinResources` 类型页,写清楚内置 mesh / material / shader / primitive display name 的职责边界、典型调用点与当前限制
## T13 Scene / RuntimeLoop 补齐
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P1`
- 写入范围: `docs/api/XCEngine/Scene/RuntimeLoop/**`
- 主要源码依据: `engine/include/XCEngine/Scene/RuntimeLoop.h``engine/src/Scene/RuntimeLoop.cpp``editor/src/Core/PlaySessionController.h``tests/Scene/test_runtime_loop.cpp`
- 当前缺口: 已建立 `RuntimeLoop` canonical 页面,并把 fixed step / pause / step-frame 语义并入 `Scene` 模块导航
- 完成标准: 建立 `RuntimeLoop` 类型页,说明 fixed step / max delta / max fixed steps 这些设置的语义,以及它与 play mode、scene tick 生命周期的关系
## T14 Core / Asset 服务与索引尾项补齐
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P1`
- 写入范围: `docs/api/XCEngine/Core/Asset/AssetImportService/**``docs/api/XCEngine/Core/Asset/ProjectAssetIndex/**`、必要时补充 `docs/api/XCEngine/Core/Asset/Asset.md`
- 主要源码依据: `engine/include/XCEngine/Core/Asset/AssetImportService.h``engine/src/Core/Asset/AssetImportService.cpp``engine/include/XCEngine/Core/Asset/ProjectAssetIndex.h``engine/src/Core/Asset/ProjectAssetIndex.cpp``tests/core/Asset/test_resource_manager.cpp`
- 当前缺口: 已补齐 `AssetImportService``ProjectAssetIndex` 两个 canonical 页面,并把它们补入 `Core/Asset` 模块总览
- 完成标准: 建立两个类型页,写清楚 `AssetDatabase -> AssetImportService -> ProjectAssetIndex -> ResourceManager` 这条项目资产查询链路
## 二次审核结论2026-04-02 23:31:03
- 本轮全量结构审计已执行: `python docs/api/_tools/audit_api_docs.py`
- 当前结构性问题为 `0`: 无失效 `.md` 链接、无非 `.md` 相对链接、无旧模板页面、无扁平 header 页面、无缺失目录总览页
- 当前剩余覆盖缺口: `0` 个 public headers 未覆盖
- 审计口径说明:
- 当前 `docs/api/_meta/rebuild-status.md` 的覆盖口径仍是 `engine/include/XCEngine` 的 public headers。
- `Editor` 下基于 `editor/src/**` 的源文件页、方法页颗粒度,以及说明性内容是否跟随源码重构同步,仍需要人工复核。
- 抽样确认出的实际遗留问题:
- `Editor/Application` 目录当前只有 `Application.md``ReloadScriptingRuntime()``RebuildScriptingAssemblies()``GetScriptRuntimeStatus()` 只在总览页有概述,缺少按商业级 API 文档颗粒度拆出的独立方法页。
- `Editor/panels/SceneViewPanel` 目录当前只有 `SceneViewPanel.md`,尚未把 pivot / center、global / local、scene icon 命中优先级、transient overlay 注入链路拆开讲透。
## T15 Components / MeshRendererComponent 内容同步
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P0`
- 写入范围: `docs/api/XCEngine/Components/MeshRendererComponent/**`、必要时 `docs/api/XCEngine/Components/Components.md`
- 主要源码依据: `engine/include/XCEngine/Components/MeshRendererComponent.h``engine/src/Components/MeshRendererComponent.cpp``tests/Components/test_mesh_render_components.cpp`
- 当前缺口: 已核对 `MeshRendererComponent.md``Serialize.md``Deserialize.md``GetMaterial.md``GetMaterialHandle.md``SetMaterialPath.md``Components.md`;文档已覆盖 `materialPaths + materialRefs` 双轨序列化、deferred async material load 与首次访问触发加载的当前行为
- 完成标准: 重写 `MeshRendererComponent.md``Serialize.md``Deserialize.md``GetMaterial.md``GetMaterialHandle.md``SetMaterialPath.md` 等核心页面,写清楚 deferred load、asset ref 回填与测试覆盖
## T16 Scripting / ScriptEngine 固定步长配置补齐
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P0`
- 写入范围: `docs/api/XCEngine/Scripting/ScriptEngine/**`、必要时 `docs/api/XCEngine/Scripting/Scripting.md``docs/api/_guides/Scripting/**`
- 主要源码依据: `engine/include/XCEngine/Scripting/ScriptEngine.h``engine/src/Scripting/ScriptEngine.cpp``tests/scripting/test_script_engine.cpp`
- 当前缺口: 已补齐 `SetRuntimeFixedDeltaTime()``GetRuntimeFixedDeltaTime()``DefaultFixedDeltaTime` 页面,并把 fixed delta 配置、运行时启停复位语义与 `OnFixedUpdate()` 的关系补入 `ScriptEngine``Scripting` 总览
- 完成标准: 补齐固定步长相关页面,并写清楚它与 `OnFixedUpdate()`、运行时启动/停止、脚本类重绑定之间的关系
## T17 Editor / Application 脚本运行时方法页补齐
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P1`
- 写入范围: `docs/api/XCEngine/Editor/Application/**`、必要时 `docs/api/XCEngine/Editor/Scripting/**`
- 主要源码依据: `editor/src/Application.h``editor/src/Application.cpp``editor/src/Scripting/EditorScriptAssemblyBuilder.h``editor/src/Scripting/EditorScriptRuntimeStatus.h``tests/Editor/test_editor_script_assembly_builder.cpp`
- 当前缺口: 已补齐 `ReloadScriptingRuntime()``RebuildScriptingAssemblies()``GetScriptRuntimeStatus()` 独立页面,并补入“程序集缺失时如何降级到不可用状态”的明确说明
- 完成标准: 为上述方法补齐独立页面,写清楚构建成功/失败路径、Mono 后端缺失时的回退、状态快照如何供 Inspector/脚本 UI 消费
## T18 Editor / SceneViewPanel 交互语义深化
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P1`
- 写入范围: `docs/api/XCEngine/Editor/panels/SceneViewPanel/**`、必要时 `docs/api/XCEngine/Editor/Viewport/**``docs/api/_guides/Editor/**`
- 主要源码依据: `editor/src/panels/SceneViewPanel.h``editor/src/panels/SceneViewPanel.cpp``editor/src/Viewport/SceneViewportOverlayHandleBuilder.h``editor/src/Viewport/SceneViewportOverlayHitTester.h``editor/src/Viewport/IViewportHostService.h`
- 当前缺口: 已重写 `SceneViewPanel.md`,并新增 `SceneView Interaction And Gizmo Model` guide文档已明确 pivot / center 的计算依据、global / local 轴向语义、scene icon 与 gizmo 的命中优先级,以及 cached / interaction / transient 三层 overlay 数据流
- 完成标准: 把 Scene View 交互模型补成商业级说明,尤其是 selection pivot、transform space、overlay hit-test 与 scene icon 选择这几条链路
## T19 审计工具口径扩展
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P2`
- 写入范围: `docs/api/_tools/audit_api_docs.py`、必要时 `docs/api/_meta/rebuild-status.md`
- 主要源码依据: 当前审计脚本口径与 `docs/api/XCEngine/Editor/**` 的实际页面分布
- 当前缺口: 自动审计目前能确认 public headers 与链接结构,但无法自动暴露 `Editor` 源文件页是否缺少方法页,也无法报告像 `Application``SceneViewPanel` 这种“只有总览页”的高风险目录
- 完成标准: 让审计结果至少能额外报告 source-file 页覆盖概况或方法页缺口统计,降低后续人工抽样成本
## T20 二次内容收口与最终复核
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P2`
- 写入范围: `docs/api/_meta/rebuild-status.md``docs/plan/API文档并行更新任务池_2026-04-02.md`、必要时受影响的模块总览页
- 主要源码依据: `T15-T19` 的完成结果
- 当前缺口: 已在 `2026-04-03 00:16:11` 重新执行 `python docs/api/_tools/audit_api_docs.py` 并回写 `rebuild-status.md`;结构性问题继续保持 `0``246/246` public headers 与 `120/120` Editor source headers 继续全量覆盖;审计中的 `Editor 高风险单页目录数: 19` 属于启发式抽样信号,不等同于仍有 19 处缺页
- 完成标准: 在 `T15-T19` 完成后重新执行结构审计与人工抽样复核,把新的结论写回进度表
## 收口结论2026-04-03 00:16:11
- 本轮收口审计已执行: `python docs/api/_tools/audit_api_docs.py`
- 当前结构性问题继续为 `0`:
- 无失效 `.md` 链接
- 无非 `.md` 相对链接
- 无旧模板页面
- 无扁平 header 页面
- 无失效 header / source ref
- 当前覆盖状态:
- public headers `246/246`
- Editor source headers `120/120`
- 本轮内容级收口结果:
- `MeshRendererComponent` 内容同步已完成
- `ScriptEngine` 固定步长配置页已补齐
- `Application` 脚本运行时方法页已补齐
- `SceneViewPanel` 交互语义与 guide 已补齐
- 审计提示解释:
- `Editor 高风险单页目录数: 19` 是新增启发式报告,用于提示“目录只有单页但实现较大,建议继续人工抽样”
- 它不是“当前仍缺 19 个 canonical 页面”的等价表达
## 三次审核结论2026-04-03 00:24:08
- 已重新执行 `python docs/api/_tools/audit_api_docs.py`
- 当前结构性问题仍为 `0`
- public headers `246/246`
- Editor source headers `120/120`
- 失效 `.md` 链接 `0`
- 无效 header / source ref `0`
- 本轮新增问题不在“结构覆盖”,而在“内容与源码同步”
- 经过 `git diff`、源码抽样与文档抽样,当前确认的内容级缺口有:
- `Input/InputManager` 文档已失准
- `Input.md` / `InputManager.md` 仍把 `GetAxisRaw()` 解释成“按下边沿”语义
- `GetButtonUp()` 的未注册按钮返回值说明仍是旧行为
- 缺少 `IsKeyReleased.md``IsMouseButtonReleased.md``IsAnyKeyDown.md``IsAnyKeyPressed.md`
- `Editor` 的 Game View 输入桥接链路没有写完整
- [GameViewPanel](../api/XCEngine/Editor/panels/GameViewPanel/GameViewPanel.md) 还在按“薄视口壳层”描述
- [EditorEvents](../api/XCEngine/Editor/Core/EditorEvents/EditorEvents.md) 还没纳入 `GameViewInputFrameEvent`
- `GameViewPanel -> EventBus -> PlaySessionController -> InputManager` 这条运行时输入链路没有统一说明
- `Editor` 项目工作流文档落后于当前功能
- [MainMenuActionRouter](../api/XCEngine/Editor/Actions/MainMenuActionRouter/MainMenuActionRouter.md) 未写 `Scripts` 菜单与“迁移场景资产引用”
- [ProjectCommands](../api/XCEngine/Editor/Commands/ProjectCommands/ProjectCommands.md) 未写 `MigrateSceneAssetReferences`
- [IProjectManager](../api/XCEngine/Editor/Core/IProjectManager/IProjectManager.md) / [ProjectManager](../api/XCEngine/Editor/Managers/ProjectManager/ProjectManager.md) 未写迁移报告结构与批量重写场景流程
- `Core/Asset` 局部页存在陈旧说明
- [AssetDatabase](../api/XCEngine/Core/Asset/AssetDatabase/AssetDatabase.md) 仍提到已不存在的 `ResourceManager::m_ioMutex`
- 新增的 artifact 依赖快照、`BuildLookupSnapshot()` 热路径、`AssetImportService + ProjectAssetIndex` 分层关系需要再校对一次叙述是否完全一致
- `Scripting` 虽已补齐 fixed delta 页面,但托管输入桥接与类发现/类切换行为还没有在模块页和 guide 层讲透
- 另外有一个文档组织问题需要收口:
- `docs/api/_guides/Editor/Scene-View-Interaction-Model.md`
- `docs/api/_guides/Editor/SceneView-Interaction-And-Gizmo-Model.md`
- 这两篇主题重叠,当前链接入口分叉,需统一 canonical guide
- `Editor 高风险单页目录数: 19` 仍保留为抽样队列,不等同于这 19 处都已确认失准
## T21 Input / InputManager 内容校准与方法补页
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P0`
- 写入范围: `docs/api/XCEngine/Input/**`、必要时 `docs/api/_guides/Input/**`
- 主要源码依据: `engine/include/XCEngine/Input/InputManager.h``engine/src/Input/InputManager.cpp``tests/Input/test_input_manager.cpp`
- 当前缺口:
- 已重写 `Input.md``InputManager.md``Input-Flow-and-Frame-Semantics.md`
- 已补齐 `IsKeyReleased.md``IsMouseButtonReleased.md``IsAnyKeyDown.md``IsAnyKeyPressed.md`
- 文档已按当前源码校正 `GetAxisRaw()``GetButtonUp()``ProcessKeyUp()``ProcessMouseButton()``Update()` 的帧语义
- 已进一步补充 `IsKeyPressed()` / `GetButtonDown()` / `IsAnyKeyPressed()``repeat` 语义,以及 `IsKeyUp()` / `IsMouseButtonUp()` 和释放边沿接口的区别
- 完成标准: 重写模块页与类型页,补齐 4 个方法页并把键鼠释放态、any-key 语义、默认映射和测试覆盖按当前源码写清楚
## T22 Editor / Game View 输入桥接链路补写
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P0`
- 写入范围: `docs/api/XCEngine/Editor/panels/GameViewPanel/**``docs/api/XCEngine/Editor/Core/EditorEvents/**``docs/api/XCEngine/Editor/Core/PlaySessionController/**`、必要时 `docs/api/_guides/Editor/**`
- 主要源码依据: `editor/src/panels/GameViewPanel.cpp``editor/src/Core/EditorEvents.h``editor/src/Core/PlaySessionController.h``editor/src/Core/PlaySessionController.cpp``tests/editor/test_play_session_controller.cpp`
- 当前缺口:
- 已重写 `GameViewPanel.md`,补入 ImGui 键鼠采集、逐帧发布 `GameViewInputFrameEvent` 与空事件释放语义
- `EditorEvents.md` 已纳入 `GameViewInputFrameEvent`
- `PlaySessionController.md` 已明确“只有运行态 `Update()` 才会把 Game View 输入桥接到 `InputManager`”及 `hovered/focused` 门控规则
- 已补齐 `GameViewPanel/Constructor.md``GameViewPanel/Render.md`
- 已新增 `docs/api/_guides/Editor/Game-View-Runtime-Input-Bridge.md`,把 `GameViewPanel -> EventBus -> PlaySessionController -> InputManager` 收口成单条连续说明
- 完成标准: 把 `GameViewPanel -> EventBus -> PlaySessionController -> InputManager` 这条桥接链路写成一组可追踪的 API 文档,明确 `hovered/focused`、键鼠状态快照与帧边界
## T23 Editor / 项目工作流与脚本菜单同步
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P0`
- 写入范围: `docs/api/XCEngine/Editor/Actions/MainMenuActionRouter/**``docs/api/XCEngine/Editor/Actions/EditorActions/**``docs/api/XCEngine/Editor/Actions/ProjectActionRouter/**``docs/api/XCEngine/Editor/Commands/ProjectCommands/**``docs/api/XCEngine/Editor/Core/IProjectManager/**``docs/api/XCEngine/Editor/Managers/ProjectManager/**`、必要时 `docs/api/XCEngine/Editor/panels/ProjectPanel/**`
- 主要源码依据: `editor/src/Actions/MainMenuActionRouter.h``editor/src/Commands/ProjectCommands.h``editor/src/Core/IProjectManager.h``editor/src/Managers/ProjectManager.h``editor/src/Managers/ProjectManager.cpp``tests/editor/test_action_routing.cpp`
- 当前缺口:
- 已重写 `MainMenuActionRouter.md`,补入 `Scripts` 菜单、`Migrate Scene AssetRefs` 文件菜单入口,以及菜单到 `ProjectCommands` / `EventBus` 的下游链路
- 已重写 `ProjectCommands.md`,补入 `RebuildScriptAssemblies``MigrateSceneAssetReferences``SwitchProject``SaveProject` 的真实 guard 和执行流程
- 已重写 `IProjectManager.md` / `ProjectManager.md`,补入 `SceneAssetReferenceMigrationReport` 结构、`Assets/**/*.xc` 批量迁移流程、`ResourceManager::ScopedDeferredSceneLoad` 与日志/刷新语义
- 已进一步补充“菜单层不消费返回值”“脚本重建产物不在 `ProjectPanel` 视图内”“`.meta` sidecar 跟随规则”“迁移报告只给汇总计数”的边界说明
- 已校对 `ProjectPanel.md``EditorActions.md`,明确面板只消费资源级命令,而项目保存 / 脚本重建 / 场景迁移入口位于主菜单
- 完成标准: 把项目工作流文档升级到“菜单入口 -> command -> manager -> 场景重写报告”的完整链路,并校对 `ProjectPanel` 对这些命令的消费关系
## T24 Core / AssetDatabase 与项目资产快照链路复核
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P1`
- 写入范围: `docs/api/XCEngine/Core/Asset/AssetDatabase/**``docs/api/XCEngine/Core/Asset/ResourceManager/**`、必要时 `docs/api/XCEngine/Core/Asset/Asset.md`
- 主要源码依据: `engine/include/XCEngine/Core/Asset/AssetDatabase.h``engine/src/Core/Asset/AssetDatabase.cpp``engine/include/XCEngine/Core/Asset/ResourceManager.h``engine/src/Core/Asset/ResourceManager.cpp``engine/src/Resources/Material/MaterialLoader.cpp``tests/core/Asset/test_resource_manager.cpp`
- 当前缺口:
- 已移除 `AssetDatabase.md` 中陈旧的 `m_ioMutex` 叙述,并改成当前 `AssetImportService::recursive_mutex` 的真实封装关系
- 已重写 `BuildLookupSnapshot()``TryGetAssetRef()``EnsureArtifact()``Asset.md` 中关于 snapshot 消费链路、cache miss 自刷新和 artifact 导入边界的说明
- 已补入材质纹理绑定依赖、`.obj -> .mtl -> texture` 依赖快照,以及 `BuildLookupSnapshot()` 只导出主资产 path/GUID 表而不导出 artifact 路径的语义
- 已继续重写 `ResourceManager` 下残留的通用占位方法页,补齐 `Get()``AddRef()/Release()``Find()/Exists()``Unload*()``ResolvePath()``LoadGroup()` 等真实行为与当前限制
- 完成标准: 把 `AssetDatabase -> ResourceManager` 的当前链路与依赖快照行为写实,并消除与 `AssetImportService` / `ProjectAssetIndex` 相关的陈旧描述
## T25 Scripting / 托管输入桥接与类发现链路补强
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P1`
- 写入范围: `docs/api/XCEngine/Scripting/**`、必要时 `docs/api/_guides/Scripting/**`
- 主要源码依据: `engine/include/XCEngine/Scripting/IScriptRuntime.h``engine/include/XCEngine/Scripting/Mono/MonoScriptRuntime.h``engine/include/XCEngine/Scripting/NullScriptRuntime.h``engine/include/XCEngine/Scripting/ScriptComponent.h``engine/include/XCEngine/Scripting/ScriptEngine.h`、对应 `.cpp``managed/XCEngine.ScriptCore/Input.cs``managed/XCEngine.ScriptCore/Time.cs``managed/XCEngine.ScriptCore/KeyCode.cs``tests/scripting/test_mono_script_runtime.cpp``tests/scripting/test_script_engine.cpp`
- 当前缺口:
- 已重写 `Scripting.md``ScriptEngine.md``MonoScriptRuntime.md`,把托管 `Input` / `Time` internal call、`Time.fixedDeltaTime` 配置来源,以及 `InputManager` 消费边界收口到同一条说明链。
- 已补强 `TryGetAvailableScriptClasses()``SetScriptClass()``ClearScriptClass()``IScriptRuntime` 契约页,明确排序、按程序集过滤、项目程序集发现和类切换重建语义。
- 已重写两篇 `Scripting` guide`project/Assets/**/*.cs -> GameScripts.dll -> ScriptClassDescriptor -> ScriptComponent::SetScriptClass()` 以及运行时切类后的实例销毁/重建流程串成连续入口。
- 完成标准: 在不扩散成两套文档体系的前提下,把原生 `ScriptEngine`、Mono internal call、项目脚本类发现与类切换重建写成一组连续说明
## 四次审核结论2026-04-03 11:39:21
- 已重新执行 `python docs/api/_tools/audit_api_docs.py`
- 当前结构性问题继续为 `0`
- public headers `246/246`
- Editor source headers `121/121`
- 失效 `.md` 链接 `0`
- 无效 header / source ref `0`
- 本轮新增与收口结果:
- `EditorConsoleSink` 已从单页目录重构为“类型页 + record 页 + 方法页”
- `ConsoleFilterState` 已按真实字段与别名关系重写
- 工作树新增的 `editor/src/Viewport/SceneViewportTransformGizmoFrameBuilder.h` 已补入 canonical 文档树
- 审计抽样结果:
- `Editor 高风险单页目录数` 已从 `14` 下降到 `10`
- `ConsolePanel``EditorConsoleSink` 已移出高风险单页目录清单
- 当前剩余抽样池见 `T26`
## 五次审核结论2026-04-03 11:56:30
- 已重新执行 `python docs/api/_tools/audit_api_docs.py`
- 当前结构性问题继续为 `0`
- public headers `246/246`
- Editor source headers `121/121`
- 失效 `.md` 链接 `0`
- 无效 header / source ref `0`
- 本轮新增与收口结果:
- 已补齐 `GameViewPanel/Constructor.md``GameViewPanel/Render.md`
- 已新增 `Game View Runtime Input Bridge` guide并把 `GameViewPanel``EditorEvents``PlaySessionController``Editor-Architecture-And-Workflow` 串成统一入口
- 审计抽样结果:
- `Editor 高风险单页目录数` 已从 `10` 下降到 `5`
- 当前剩余抽样池已进一步收缩到 `Viewport gizmo + SceneManager`
## 六次审核结论2026-04-03 12:00:34
- 已重新执行 `python docs/api/_tools/audit_api_docs.py`
- 当前结构性问题继续为 `0`
- public headers `246/246`
- Editor source headers `121/121`
- 失效 `.md` 链接 `0`
- 无效 header / source ref `0`
- 本轮新增与收口结果:
- 已重写 `SceneManager.md`,并补齐实体编辑、场景文件生命周期、快照恢复相关方法页
- `ISceneManager.md` 已按当前实现职责更新接口说明
- 审计抽样结果:
- `Editor 高风险单页目录数` 已从 `5` 下降到 `0`
- `T26` 对应的启发式抽样队列已全部清空
## T26 Editor / 高风险单页目录抽样复核队列
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P2`
- 写入范围: `docs/api/XCEngine/Editor/Managers/SceneManager/**``docs/api/XCEngine/Editor/Viewport/SceneViewportMoveGizmo/**``docs/api/XCEngine/Editor/Viewport/SceneViewportRotateGizmo/**``docs/api/XCEngine/Editor/Viewport/SceneViewportScaleGizmo/**``docs/api/XCEngine/Editor/Viewport/SceneViewportOrientationGizmo/**`
- 主要源码依据: `docs/api/_meta/rebuild-status.md` 中的高风险单页目录清单及对应 `editor/src/**`
- 当前缺口:
- `2026-04-03 12:00:34` 这轮复核后,审计中的 `Editor 高风险单页目录数` 已下降到 `0`
- 启发式抽样队列已收口完成,当前不再保留剩余目录。
- 完成标准: 至少抽样复核一遍源码与现有页面;若发现失准则直接重写,若确认足够则在任务认领记录里注明“已复核”
## T27 Editor / Scene View 交互 guide 去重与入口收口
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P2`
- 写入范围: `docs/api/_guides/Editor/Scene-View-Interaction-Model.md``docs/api/_guides/Editor/SceneView-Interaction-And-Gizmo-Model.md`、以及所有引用这两篇 guide 的 API 页面
- 主要依据: 当前 guide 内容本身与 `SceneViewPanel` / `IViewportHostService` / `ViewportHostService` / `Viewport.md` 的交叉链接分布
- 当前缺口:
- 已确认 `SceneView-Interaction-And-Gizmo-Model.md` 作为唯一 canonical guide`Scene-View-Interaction-Model.md` 保留为兼容入口页,只负责跳转说明。
- 已把残留的业务页引用统一切到 canonical guide当前仓库里已无 API 页面继续把旧 guide 当主入口。
- 完成标准: 统一保留一个 canonical guide 或明确拆分两篇职责,并把全部入口链接收口到一致命名
## 四次审核结论2026-04-03 11:44:52
- 已重新执行 `python docs/api/_tools/audit_api_docs.py`
- 当前结构性问题仍为 `0`
- public headers `246/246`
- Editor source headers `121/121`
- 失效 `.md` 链接 `0`
- 无效 header / source ref `0`
- 本轮新增收口结果:
- `T21 Input / InputManager` 已补充 `Pressed` / `Up` / `Released` / `repeat` 的内容级语义说明
- `Input-Flow-and-Frame-Semantics.md` 已提升为面向接入与设计理解的 canonical guide
- 当前自动审计提示:
- `Editor high-risk single-page dirs: 10`
- 这仍是人工抽样优先队列,不等同于已经确认存在 10 处失准
- 后续并行优先级建议保持为:
- `T23`
- `T24` / `T25`
- `T26` / `T27`
## 五次审核结论2026-04-03 11:53:48
- 已重新执行 `python docs/api/_tools/audit_api_docs.py`
- 当前结构性问题仍为 `0`
- public headers `246/246`
- Editor source headers `121/121`
- 失效 `.md` 链接 `0`
- 无效 header / source ref `0`
- 本轮新增收口结果:
- `T23 Editor / 项目工作流与脚本菜单同步` 已继续补强内容级说明
- 已明确主菜单层只负责触发项目维护动作,不消费 `RebuildScriptAssemblies` / `MigrateSceneAssetReferences` 的返回结果
- 已明确 `ProjectPanel` 只投影 `<Project>/Assets`,因此脚本重建成功后不保证出现可见树变化
- 已明确 `ProjectManager``.meta` sidecar 跟随语义、resource root 临时切换 / 恢复,以及迁移报告只提供汇总计数
- 当前自动审计提示:
- `Editor high-risk single-page dirs: 6`
- 仍属于人工抽样队列,不等同于已经确认失准
- 后续并行优先级建议调整为:
- `T24` / `T25`
- `T26`
- `T27`
## 六次审核结论2026-04-03 11:57:51
- 已重新执行 `python docs/api/_tools/audit_api_docs.py`
- 当前结构性问题仍为 `0`
- public headers `246/246`
- Editor source headers `121/121`
- 失效 `.md` 链接 `0`
- 无效 header / source ref `0`
- 本轮新增收口结果:
- `T24 Core / AssetDatabase 与项目资产快照链路复核` 已完成
- 已修正 `AssetDatabase` 的锁模型、`BuildLookupSnapshot()` 的真实消费链路、`TryGetAssetRef()``EnsureArtifact()` 的职责边界
- 已把材质贴图依赖与模型依赖快照的真实采集方式补入文档
- 当前自动审计提示:
- `Editor high-risk single-page dirs: 4`
- 仍属于人工抽样队列,不等同于已经确认失准
## 七次审核结论2026-04-03 12:16:18
- 已重新执行 `python docs/api/_tools/audit_api_docs.py`
- 当前结构性问题仍为 `0`
- public headers `246/246`
- Editor source headers `121/121`
- 失效 `.md` 链接 `0`
- 无效 header / source ref `0`
- 本轮新增收口结果:
- `T24` 已继续补齐 `ResourceManager` 目录下残留的占位方法页
- `ResolvePath()``Exists()/Find()``Unload*()``LoadGroup()` 等方法页已改成按源码解释当前行为与限制
- 当前自动审计提示:
- `Editor high-risk single-page dirs: 0`
- 当前追踪表中的内容级收口任务已全部落地
- 后续并行优先级建议调整为:
- `T25`
- `T26`
- `T27`
## 八次审核结论2026-04-03 12:21:03
- 已重新执行 `python docs/api/_tools/audit_api_docs.py`
- 当前结构性问题仍为 `0`
- public headers `246/246`
- Editor source headers `121/121`
- 失效 `.md` 链接 `0`
- 无效 header / source ref `0`
- 本轮新增收口结果:
- `T25 Scripting / 托管输入桥接与类发现链路补强` 已完成最后一轮内容级重写
- 已把托管 `Input` / `Time` internal call、`Time.fixedDeltaTime` 配置来源、`TryGetAvailableScriptClasses()` 的排序与按程序集过滤语义、`SetScriptClass()` / `ClearScriptClass()` 的运行时重建链路补入模块页、类型页与 guide
- `MonoScriptRuntime` 与两篇 `Scripting` guide 已明确项目脚本程序集入口、类发现约束、字段默认值与本地覆盖同步的设计边界
- 当前自动审计提示:
- `Editor high-risk single-page dirs: 0`
- 当前任务池中的内容级收口任务已全部完成
- 后续并行优先级建议调整为:
- 跟踪后续源码新增 API
- 发现新的内容失准后再按模块开新任务
- 保持 `docs/api/_meta/rebuild-status.md` 的周期性审计回写
## T28 Rendering / BuiltinForwardPipeline 资源契约与描述符布局同步
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P1`
- 写入范围: `docs/api/XCEngine/Rendering/Pipelines/BuiltinForwardPipeline/**`、必要时 `docs/api/XCEngine/Rendering/Pipelines/Pipelines.md``docs/api/XCEngine/Rendering/Rendering.md`
- 主要源码依据: `engine/include/XCEngine/Rendering/Pipelines/BuiltinForwardPipeline.h``engine/src/Rendering/Pipelines/BuiltinForwardPipeline.cpp``tests/Rendering/unit/test_builtin_forward_pipeline.cpp`
- 当前缺口:
- 已重写 `BuiltinForwardPipeline.md``Initialize.md``Render.md``Shutdown.md`,把 `RenderPassSequence``PassResourceLayout`、动态/静态 descriptor set 分流与 legacy binding 回退补齐到当前实现。
- 已新增 `Constructor.md``BuildInputLayout.md`,补齐公开构造入口和 `StaticMeshVertex` 输入布局契约。
- 已新增 `BuiltinForwardPipelineAsset/BuiltinForwardPipelineAsset.md``BuiltinForwardPipelineAsset/CreatePipeline.md`,补清默认 pipeline asset 工厂与 runtime pipeline 的衔接关系。
- 已更新 `Pipelines.md``RenderPipeline.md``RenderPipelineAsset.md``RenderPipelineAsset/CreatePipeline.md``Rendering.md` 与渲染 guide使 `ForwardLit` 资源契约、`visibleItems` 和默认 pipeline asset 链路保持一致。
- 完成标准: 把 `BuiltinForwardPipeline` 类型页与核心方法页重写到当前实现,明确 shader pass 资源契约、descriptor set 生命周期、legacy 回退语义和当前限制
## T29 Rendering / SceneRenderer 与 RenderSceneExtractor 口径复核
- 状态: `DONE`
- 认领人: `Codex`
- 优先级: `P1`
- 写入范围: `docs/api/XCEngine/Rendering/SceneRenderer/**``docs/api/XCEngine/Rendering/RenderSceneExtractor/**``docs/api/XCEngine/Rendering/VisibleRenderObject/**`
- 主要源码依据: `engine/include/XCEngine/Rendering/SceneRenderer.h``engine/src/Rendering/SceneRenderer.cpp``engine/include/XCEngine/Rendering/RenderSceneExtractor.h``engine/src/Rendering/RenderSceneExtractor.cpp``tests/Rendering/unit/test_camera_scene_renderer.cpp``tests/Rendering/unit/test_scene_render_request_planner.cpp`
- 当前缺口:
- 已重写 `SceneRenderer.md``Constructor.md``Destructor.md``SetPipeline.md``GetPipeline.md``Render.md`,纠正“`SceneRenderer` 直接做 scene extraction / 直接创建 `BuiltinForwardPipeline`”的旧口径。
- 已新增 `BuildRenderRequests.md``SetPipelineAsset.md``GetPipelineAsset.md`,补齐 `SceneRenderer` 当前公开方法页。
- 已重写 `RenderSceneExtractor.md``Extract.md`,并新增 `ExtractForCamera.md``SelectCamera.md`,把 `visibleItems`、相机选择、光照提取与排序规则同步到当前实现。
- 已重写 `VisibleRenderObject.md`,把它明确为 `VisibleRenderItem` 的兼容别名入口,并补齐 `material / section / renderQueue / cameraDistanceSq` 等当前字段。
- 完成标准: 把 `SceneRenderer` 更新为“请求规划 + 转发到 `CameraRenderer`”的真实职责模型;把 `RenderSceneExtractor` 更新为 `visibleItems` 与当前排序 / 相机选择语义
## 九次审核结论2026-04-03 13:30:05
- 已重新执行 `python docs/api/_tools/audit_api_docs.py`
- 当前结构性问题仍为 `0`
- public headers `246/246`
- Editor source headers `121/121`
- 失效 `.md` 链接 `0`
- 无效 header / source ref `0`
- 本轮新增收口结果:
- `T28 Rendering / BuiltinForwardPipeline 资源契约与描述符布局同步` 已完成
- 已补齐 `BuiltinForwardPipeline/Constructor.md``BuiltinForwardPipeline/BuildInputLayout.md``BuiltinForwardPipelineAsset` 类目录
- 已把默认 `BuiltinForwardPipelineAsset -> BuiltinForwardPipeline -> CameraRenderer` 链路补入 `Pipelines``RenderPipelineAsset``RenderPipeline``Rendering` 与 rendering guide
- 当前自动审计提示:
- `Editor high-risk single-page dirs: 0`
- 当前 canonical API 树与 public headers / Editor source headers 仍保持全量覆盖
## 备注
- `T01-T20` 当前已全部完成
- `T21-T27` 当前也已全部完成
- 下一阶段重点已经从“补历史缺页”切换为“跟踪源码新增行为并持续校正文档内容”

View File

@@ -0,0 +1,758 @@
# C#脚本模块的设计与实现
日期3.27
## 1. 背景
XCEngine 的整体方向是模仿传统 Unity 引擎架构,而不是 DOTS/ECS-first 路线。
在这一目标下,脚本系统应当满足以下基本预期:
- 脚本语言使用 `C#`
- 脚本以“挂载到 `GameObject` 上的组件”形式工作
- 脚本与引擎核心解耦,支持独立编译和运行时加载
- 脚本可以逐步扩展到 Inspector、场景序列化、Play/Simulate 工作流
当前 `editor` 仍处于基础阶段,因此脚本系统第一阶段不应依赖 editor 完整落地。
第一阶段的目标应当收敛为:
- 先完成原生运行时与托管运行时之间的桥接
- 先完成 `ScriptComponent + C# MonoBehaviour` 的基本执行链路
- 先完成单元测试和最小场景级验证
- 将 editor 集成需求单独列为 issue后续补齐
---
## 2. 设计目标
### 2.1 总体目标
脚本系统应当提供一条接近 Unity 的开发路径:
1. 用户在独立的 C# 项目中编写脚本
2. C# 脚本编译为程序集
3. Engine Core 在运行时加载程序集
4. `GameObject` 上挂载 `ScriptComponent`
5. `ScriptComponent` 驱动一个对应的 C# `MonoBehaviour` 实例
6. 脚本通过引擎暴露的 API 调用原生功能
### 2.2 第一阶段目标
第一阶段只覆盖以下内容:
- `engine` 内部的脚本运行时抽象
- 第一套 C# 运行时实现
- `ScriptComponent` 原生组件
- `ScriptCore` 托管基础库
- 最小可用的 `InternalCall` 绑定
- 单元测试与最小运行时测试
### 2.3 第一阶段非目标
第一阶段明确不做以下内容:
- editor Inspector 脚本字段编辑
- editor 中的脚本类选择器
- editor 的 Play/Simulate 集成
- 自动编译、文件监听、热重载
- 调试器接入
- 发布态 AOT / IL2CPP
- 大而全的引擎 API 暴露
---
## 3. 三方对比结论
### 3.1 Unity
Unity 的典型脚本模型有几个关键特征:
- 用户脚本通常继承 `MonoBehaviour`
- 一段脚本本质上就是一个组件实例
- 脚本字段可序列化、可在 Inspector 中编辑
- 生命周期完整,且与 `GameObject active` / `Component enabled` 语义一致
- Play 模式运行的是运行时场景副本,而不是直接修改编辑场景
### 3.2 参考项目 Fermion
参考项目已经实现了一套 C# 脚本模块,优点主要在于:
- 已经证明了 `Mono embedding + InternalCall + C# 程序集加载` 这条路线可行
- 已经具备脚本类发现、脚本实例创建、字段反射、运行时调用
- 已经有托管侧 API 包装层和原生侧 `ScriptGlue`
但它的对象模型并不是 Unity 风格:
- 托管脚本类继承的是 `Entity`
- 原生挂载结构是 `ScriptContainerComponent`
- 更像“一个实体挂多个脚本类名”,而不是“每个脚本本身就是一个组件”
- 生命周期目前主要聚焦 `OnCreate/OnUpdate`
结论:
- Fermion 适合借鉴运行时技术路线
- Fermion 不适合作为最终 API 形态的直接模板
### 3.3 XCEngine 当前情况
XCEngine 当前已经具备以下基础:
- 已有 `GameObject + Component + Scene` 模型
- `Component` 已定义 Unity 风格生命周期接口
- `Scene``GameObject` 已有序列化入口
- `ComponentFactoryRegistry` 已支持按类型名恢复组件
但当前也存在会直接影响脚本系统设计的现实约束:
- `Scene::Update/FixedUpdate/LateUpdate` 目前只遍历根对象
- `GameObject::Update/FixedUpdate/LateUpdate` 目前不递归子对象
- `Start` 的场景级一次性调度路径还未完整建立
- `SetActive` 尚未真正驱动 `OnEnable/OnDisable`
- editor 的 Play/Simulate 工作流仍未落地
- `GameObject UUID` 当前未进入场景序列化主路径
结论:
- XCEngine 适合走 Unity 风格脚本模型
- 但脚本系统第一阶段必须连同一部分运行时地基一起建设
---
## 4. 总体设计结论
XCEngine 的 C# 脚本模块采用以下路线:
- **脚本语言**C#
- **脚本挂载模型**:原生 `ScriptComponent` 对应托管 `MonoBehaviour`
- **程序集模型**`ScriptCore``GameScripts` 分离
- **运行时加载模式**:独立编译,运行时加载
- **桥接方式**`InternalCall`
- **运行时抽象策略**:先抽象接口,再优先落 Mono 实现
- **第一阶段验证方式**:单元测试优先,不依赖 editor
这条路线有两个核心原则:
1. API 形态尽量接近 Unity
2. 第一阶段严格控制范围,只做运行时闭环和测试闭环
---
## 5. 运行时选型
### 5.1 第一阶段选型Mono
第一阶段建议使用 `Mono` 作为第一套 C# 运行时实现,原因如下:
- 与现有规划文档保持一致
- 参考项目已经证明这条技术路线可落地
- `InternalCall` 路线成熟,适合快速建立最小可用系统
- 便于在 Windows 环境中先做出可运行结果
### 5.2 选型边界
本设计不把 `Mono` 写死为脚本系统唯一实现,而是将其作为第一实现:
- 对外暴露 `IScriptRuntime` / `ScriptEngine` 抽象
- `MonoScriptRuntime` 作为第一套后端
- 后续如有需要,可以演进到 `CoreCLR` 或其他运行时
### 5.3 第一阶段不做的运行时能力
Mono 相关的以下复杂能力不进入第一阶段:
- 域热重载
- 编辑器内自动重编译后重载
- 托管调试器接入
- 发布态 AOT
第一阶段仅要求:
- 初始化运行时
- 加载核心程序集
- 加载用户程序集
- 发现脚本类
- 实例化对象
- 调用生命周期
- 读写托管字段
---
## 6. 模块划分
### 6.1 原生侧模块
建议在 `engine` 内新增 `Scripting` 模块:
```text
engine/
├── include/XCEngine/Scripting/
│ ├── ScriptEngine.h
│ ├── IScriptRuntime.h
│ ├── ScriptAssembly.h
│ ├── ScriptClass.h
│ ├── ScriptInstance.h
│ ├── ScriptField.h
│ ├── ScriptFieldStorage.h
│ ├── ScriptGlue.h
│ └── ScriptComponent.h
└── src/Scripting/
├── ScriptEngine.cpp
├── ScriptGlue.cpp
├── ScriptComponent.cpp
└── Mono/
├── MonoScriptRuntime.cpp
├── MonoScriptClass.cpp
└── MonoScriptAssembly.cpp
```
### 6.2 托管侧模块
建议新增托管核心库 `ScriptCore`
```text
managed/
├── XCEngine.ScriptCore/
│ ├── XCEngine.ScriptCore.csproj
│ ├── Object.cs
│ ├── Component.cs
│ ├── Behaviour.cs
│ ├── MonoBehaviour.cs
│ ├── GameObject.cs
│ ├── Transform.cs
│ ├── Debug.cs
│ ├── Time.cs
│ └── InternalCalls.cs
└── GameScripts/
├── GameScripts.csproj
└── Scripts/*.cs
```
### 6.3 程序集分层
程序集分为两层:
- `XCEngine.ScriptCore.dll`
- 由引擎维护
- 提供托管基类和引擎 API 包装
- `GameScripts.dll`
- 由项目侧维护
- 编写具体游戏脚本
关系如下:
```text
GameScripts.dll
└── 引用 XCEngine.ScriptCore.dll
Engine Core
├── 先加载 XCEngine.ScriptCore.dll
└── 再加载 GameScripts.dll
```
---
## 7. 对象模型
### 7.1 托管侧模型
托管侧应当采用接近 Unity 的对象层次:
```text
Object
└── Component
└── Behaviour
└── MonoBehaviour
```
其中:
- `Object`:基础托管对象
- `Component`:挂载到 `GameObject` 上的托管组件基类
- `Behaviour`:带 `enabled` 语义的组件
- `MonoBehaviour`:用户脚本直接继承的基类
### 7.2 原生挂载模型
原生侧脚本挂载使用 `ScriptComponent`,而不是 `ScriptContainerComponent`
原因如下:
- 更符合 Unity 认知模型
- 更容易与现有 `GameObject::AddComponent<T>` 思路对齐
- 更容易在未来做 Inspector 级脚本组件显示
- 更容易把字段序列化与组件实例对应起来
建议 `ScriptComponent` 至少包含:
- `scriptComponentUUID`
- `assemblyName`
- `namespaceName`
- `className`
- `enabled`
- `fieldStorage`
推荐接口示意:
```cpp
class ScriptComponent : public Component {
public:
std::string GetName() const override { return "Script"; }
const std::string& GetAssemblyName() const;
const std::string& GetNamespaceName() const;
const std::string& GetClassName() const;
std::string GetFullClassName() const;
uint64_t GetScriptComponentUUID() const;
bool IsRuntimeValid() const;
void Serialize(std::ostream& os) const override;
void Deserialize(std::istream& is) override;
private:
uint64_t m_scriptComponentUUID = 0;
std::string m_assemblyName = "GameScripts";
std::string m_namespaceName;
std::string m_className;
ScriptFieldStorage m_fieldStorage;
};
```
### 7.3 多脚本挂载
一个 `GameObject` 应允许挂载多个 `ScriptComponent`
这与 Unity 保持一致:
- 同一个对象可以挂多个不同脚本
- 同一个脚本是否允许重复挂载,由后续属性或规则控制
- 第一阶段不做“禁止重复挂载”的复杂策略
---
## 8. 身份模型与序列化要求
### 8.1 必须使用 UUID而不是运行时 ID
脚本系统中,托管实例与原生对象的稳定绑定必须建立在 `UUID` 之上,而不是当前的自增 `ID`
原因如下:
- 运行时场景复制不能依赖自增 ID 稳定
- 脚本字段里的对象引用必须有稳定键
- editor 与 runtime 之间的对象映射必须有稳定键
- 单元测试和场景恢复也需要稳定身份
因此需要补齐以下要求:
- `GameObject UUID` 进入场景序列化
- 场景反序列化时恢复 `UUID`
- `ScriptComponent` 自身也应有持久化 UUID
### 8.2 第一阶段字段序列化策略
第一阶段的脚本字段序列化原则如下:
- 只序列化 `ScriptComponent` 的字段缓存
- 只序列化脚本作者显式设置的字段值
- 运行时脚本执行过程中修改的值,不自动回写场景
这与 Unity 的 Play 模式行为一致:
- Play 中的运行时改动不应直接污染编辑数据
### 8.3 第一阶段字段支持范围
建议第一阶段先支持:
- `float`
- `double`
- `bool`
- `int32`
- `uint64`
- `string`
- `Vector2`
- `Vector3`
- `Vector4`
- `GameObject` 引用
第一阶段不要求支持:
- `List<T>`
- 自定义托管结构体
- 嵌套对象图
- 泛型容器
- 资源引用对象选择器
---
## 9. 生命周期设计
### 9.1 目标生命周期
脚本系统最终应支持以下 Unity 风格生命周期:
- `Awake`
- `OnEnable`
- `Start`
- `FixedUpdate`
- `Update`
- `LateUpdate`
- `OnDisable`
- `OnDestroy`
### 9.2 第一阶段生命周期闭环
第一阶段就应当把上述生命周期的原生调度链路设计好,哪怕 editor 尚未接入。
建议运行时流程如下:
#### `Scene` 运行时启动
1. `ScriptEngine::OnRuntimeStart(scene)`
2. 遍历场景中全部激活对象
3. 找到所有 `ScriptComponent`
4. 为每个组件创建托管 `MonoBehaviour` 实例
5. 写入原生对象 UUID / 组件 UUID / 基础上下文
6. 应用序列化字段缓存
7. 调用 `Awake`
8. 若对象激活且组件启用,调用 `OnEnable`
9. 标记“等待 Start”
#### 每帧执行
- 物理阶段:`FixedUpdate`
- 普通阶段:`Update`
- 后处理阶段:`LateUpdate`
- 对于尚未执行 `Start` 的脚本,在第一次普通帧前先调用 `Start`
#### 运行时停止
1. 对仍处于启用状态的脚本调用 `OnDisable`
2. 对所有脚本调用 `OnDestroy`
3. 清理托管实例表
4. 清理运行时场景上下文
### 9.3 对现有引擎的前置要求
为了让脚本生命周期符合预期,现有引擎需要补齐以下地基:
- `Scene` 更新必须递归整个层级,而不是只更新根对象
- `Start` 必须具备“一次且仅一次”语义
- `SetActive` 必须驱动 `OnEnable/OnDisable`
- 运行时场景启动与停止必须显式化
- 创建对象时不应直接把“编辑态创建”与“运行态 Awake”混为一谈
这些工作虽然不都属于脚本模块,但它们是脚本模块的直接运行前提。
---
## 10. 原生与托管之间的桥接
### 10.1 桥接方式
第一阶段使用 `InternalCall`
- 托管侧通过 `MethodImplOptions.InternalCall` 声明方法
- 原生侧通过 `mono_add_internal_call` 注册
### 10.2 第一阶段最小 API 集
第一阶段建议只暴露最小必需 API
- `Debug.Log / LogWarning / LogError`
- `Time.deltaTime`
- `GameObject.GetName / SetName`
- `GameObject.GetTransform`
- `Component.GetGameObject`
- `GameObject.HasComponent<T>`
- `GameObject.GetComponent<T>`
- `Transform` 的本地位置 / 旋转 / 缩放
这套 API 足够覆盖以下测试与最小演示:
- 变换脚本
- 旋转/移动脚本
- 生命周期日志验证
- 组件访问验证
第一阶段不建议优先暴露:
- 物理 API
- 渲染 API
- 音频 API
- 输入系统
- 资源系统
原因很简单:
- 第一阶段以单元测试闭环为主
- 暴露面越大,绑定维护成本越高
- 当前这些系统本身仍在演进
---
## 11. 类发现与实例管理
### 11.1 脚本类发现规则
用户脚本类应满足以下条件才被视为可挂载脚本:
- 定义在 `GameScripts.dll`
- 非抽象类
- 继承 `XCEngine.MonoBehaviour`
### 11.2 缓存结构
原生运行时需要缓存以下信息:
- 程序集表
- 脚本类表
- 方法句柄表
- 字段元数据表
- 运行时实例表
建议实例表键使用:
- `GameObjectUUID + ScriptComponentUUID`
而不是:
- 内存地址
- 组件在容器中的索引
- 自增 ID
### 11.3 方法缓存
每个脚本类应缓存常用生命周期方法句柄:
- `Awake`
- `OnEnable`
- `Start`
- `FixedUpdate`
- `Update`
- `LateUpdate`
- `OnDisable`
- `OnDestroy`
这样可以避免每帧按字符串查找方法。
---
## 12. 单元测试优先策略
### 12.1 原则
第一阶段脚本模块不依赖 editor因此验证策略以单元测试和最小运行时测试为主。
### 12.2 测试目录建议
```text
tests/
└── Scripting/
├── unit/
│ ├── test_script_runtime.cpp
│ ├── test_script_metadata.cpp
│ ├── test_script_component.cpp
│ ├── test_script_fields.cpp
│ └── CMakeLists.txt
└── managed/
├── XCEngine.ScriptCore/
└── TestScripts/
```
### 12.3 第一阶段必须覆盖的测试
#### 运行时初始化
- 能初始化脚本运行时
- 能加载 `ScriptCore`
- 能加载测试脚本程序集
#### 类发现
- 只发现继承 `MonoBehaviour` 的类
- 忽略抽象类
- 忽略普通工具类
#### 生命周期
- 能创建托管实例
- 能按顺序触发 `Awake -> OnEnable -> Start -> Update`
- 能在停止时触发 `OnDisable -> OnDestroy`
#### 组件桥接
- 脚本能访问 `GameObject`
- 脚本能访问 `Transform`
- 脚本能访问最小组件 API
#### 字段系统
- 能发现公共字段
- 能读写字段
- 字段缓存可回填到托管实例
- 场景序列化后字段值不丢失
#### 多脚本对象
- 同一 `GameObject` 上多个 `ScriptComponent` 都可实例化
- 不同脚本实例之间不会串字段
#### UUID 绑定
- 运行时复制或反序列化后仍可稳定恢复脚本绑定键
### 12.4 第一阶段不要求的测试
- editor Inspector UI
- 热重载
- 编译器输出面板
- 文件监听
- 资源拖拽
---
## 13. 建议的实现顺序
### 阶段 A补运行时地基
先补以下基础能力:
- `GameObject UUID` 序列化
- 层级递归更新
- `Start` 一次性语义
- `SetActive` 对生命周期的影响
- `Scene` 运行时启动/停止接口
### 阶段 B脚本最小闭环
完成:
- `Scripting` 模块骨架
- `ScriptComponent`
- `MonoScriptRuntime`
- `XCEngine.ScriptCore.dll`
- `GameScripts.dll`
- 最小 `InternalCall`
### 阶段 C字段与序列化
完成:
- 脚本字段元数据
- 字段缓存
- `ScriptComponent` 序列化/反序列化
- 字段相关单元测试
### 阶段 D最小运行时演示
在不依赖 editor 的前提下完成:
- 纯运行时测试场景
- 一个或两个最小脚本示例
- Play 级别运行验证
### 阶段 Eeditor 集成
后续再做:
- 脚本组件 Inspector
- 类选择器
- 编译按钮
- 错误输出
- 重载流程
---
## 14. 与 editor 的关系
第一阶段文档明确规定:
- C# 脚本模块**不依赖 editor 完整落地**
- editor 相关工作全部后置
- editor 相关缺口统一记录在 `docs/issues`
第一阶段唯一允许与 editor 共用的内容是:
- 场景序列化格式
- `GameObject UUID` 语义
- 运行时场景副本的总体设计方向
除此之外,不应把脚本模块第一阶段实现建立在 editor 已具备以下能力的假设上:
- Play/Simulate 控制条
- Inspector 自定义字段绘制
- 项目内脚本自动编译
- 脚本异常面板
---
## 15. 风险与权衡
### 15.1 Mono 依赖
风险:
- Windows 环境需要显式安装或打包 Mono
- CMake 配置与发布路径管理会变复杂
权衡:
- 第一阶段优先解决“能跑起来”的问题
- 运行时抽象保留未来替换空间
### 15.2 生命周期与现有引擎实现的偏差
风险:
- 如果继续保留当前“创建对象就立即 `Awake`”的行为,脚本生命周期会混乱
权衡:
- 脚本系统建设必须带动运行时生命周期整理
### 15.3 字段系统范围
风险:
- 一开始就追求完整序列化会让范围失控
权衡:
- 第一阶段只做基础类型与少量引用类型
- 复杂容器和高级序列化后置
### 15.4 editor 后置
风险:
- 第一阶段用户体验不完整
权衡:
- 可以显著降低实现风险
- 可以先通过单测和运行时样例把底层做稳
---
## 16. 最终结论
XCEngine 的 C# 脚本系统应当采用:
- `ScriptComponent + MonoBehaviour`
- `ScriptCore + GameScripts` 双程序集结构
- `InternalCall` 桥接
- `Mono` 作为第一套运行时实现
- `UUID` 作为绑定与序列化的稳定身份
- 第一阶段只做运行时与单元测试,不依赖 editor
这条路线既保留了 Unity 风格的一致性,也能适配当前工程实际进度。
第一阶段的成功标准不是“Inspector 能编辑脚本字段”,而是:
- 能加载脚本程序集
- 能发现脚本类
- 能在场景运行时驱动 `MonoBehaviour`
- 能通过单元测试验证生命周期、字段和绑定语义
达到这一点后,再进入 editor 集成阶段,工程风险会显著更低。

View File

@@ -0,0 +1,128 @@
# Editor Viewport 宿主渲染收口总结 4.1
## 当前判断
截至 2026-04-01这一阶段的主线应视为
-`Editor -> ViewportHost -> Renderer -> RHI` 这条链路接通
- 把 editor viewport 的宿主层从 panel 内部逻辑中收出来
- 把这层宿主代码压到“可继续演进,但先停止扩张”的状态
这一阶段的目标不是继续往 editor viewport 里塞更多功能,也不是提前做完未来 renderer 的全部能力。
如果继续在本阶段里混入 gizmo 完整体系、GPU picking 正式方案、多 pass 大改、后处理、光照系统等内容,只会让阶段边界再次失控。
## 已完成的收口结果
### 1. editor viewport 已经不再是空壳
当前 `SceneView``GameView` 已经能通过统一的 viewport host 路径请求离屏 render target并把 renderer 输出展示到 editor 面板中。
当前已实际接通:
- Scene viewport 渲染
- Game viewport 渲染
- viewport resize 资源重建
- backpack 等真实模型内容在 editor 中显示
- grid / 选中 / 描边 / object id 读取链路
### 2. viewport host 的职责边界已经成型
当前 viewport 宿主层已经被拆成几块相对明确的职责:
- [editor/src/Viewport/ViewportHostSurfaceUtils.h](D:/Xuanchi/Main/XCEngine/editor/src/Viewport/ViewportHostSurfaceUtils.h)
- viewport surface / texture / reuse 相关纯工具
- [editor/src/Viewport/ViewportHostRenderTargets.h](D:/Xuanchi/Main/XCEngine/editor/src/Viewport/ViewportHostRenderTargets.h)
- viewport render target 生命周期与创建销毁
- [editor/src/Viewport/ViewportObjectIdPicker.h](D:/Xuanchi/Main/XCEngine/editor/src/Viewport/ViewportObjectIdPicker.h)
- viewport object id 读取与像素映射
- [editor/src/Viewport/ViewportHostRenderFlowUtils.h](D:/Xuanchi/Main/XCEngine/editor/src/Viewport/ViewportHostRenderFlowUtils.h)
- scene/game viewport 的失败回退策略、request 组装、成功态迁移
- [editor/src/Viewport/ViewportHostService.h](D:/Xuanchi/Main/XCEngine/editor/src/Viewport/ViewportHostService.h)
- 保留真正的 orchestration、scene view camera、post pass 组装与 clear 执行
这意味着 viewport host 已经不再是“一个面板私有的大杂烩类”,而是一个有明确宿主边界的 editor 侧接入层。
### 3. 现阶段测试闭环已经补上
当前 editor 侧已经有明确的宿主层单测覆盖:
- [tests/editor/test_viewport_host_surface_utils.cpp](D:/Xuanchi/Main/XCEngine/tests/editor/test_viewport_host_surface_utils.cpp)
- [tests/editor/test_viewport_render_targets.cpp](D:/Xuanchi/Main/XCEngine/tests/editor/test_viewport_render_targets.cpp)
- [tests/editor/test_viewport_object_id_picker.cpp](D:/Xuanchi/Main/XCEngine/tests/editor/test_viewport_object_id_picker.cpp)
- [tests/editor/test_viewport_render_flow_utils.cpp](D:/Xuanchi/Main/XCEngine/tests/editor/test_viewport_render_flow_utils.cpp)
本轮收口完成后,`editor_tests` 已覆盖 viewport host 中最容易回归的纯策略与资源管理逻辑。
## 为什么到这里应当停止继续拆
当前 [editor/src/Viewport/ViewportHostService.h](D:/Xuanchi/Main/XCEngine/editor/src/Viewport/ViewportHostService.h) 剩下的主要内容,是以下几类“真正属于宿主编排”的职责:
- scene view camera 的创建与驱动
- focus / orientation axis 等 editor 专属视图控制
- scene view post pass 的装配
- scene/game viewport 的 render dispatch
- clear 执行
这些逻辑如果继续硬拆,很容易为了“文件更小”而把真正依赖 editor 运行时状态的 orchestration 人为打散,收益已经明显下降。
所以这一阶段的明确结论是:
- `ViewportHostService` 继续保持为宿主编排入口是合理的
- 不再以“继续拆文件”为本阶段目标
- 下一阶段应把重点转移到 renderer 本身的演进,而不是继续挤压 editor host
## 本阶段的结束标准
这一阶段以以下标准视为完成:
1. `editor_tests` 全部通过
2. `XCEditor` 能正常编译
3. viewport host 的主要纯逻辑都有独立单测
4. `ViewportHostService` 不再继续承载资源创建、object id 读取、失败策略等细碎职责
5. 明确哪些问题属于后续 renderer 阶段,而不是继续留在当前阶段消耗
## 明确不属于本阶段的内容
以下内容不再计入“editor viewport 宿主渲染收口”阶段:
- GPU object id 正式拾取方案
- renderer 内部通用多 pass / render graph 体系
- 更正式的 editor outline 方案升级
- gizmo 全量产品化
- 光照、阴影、后处理
- runtime 渲染管线的完整 SRP 式抽象
这些内容应进入 renderer 后续阶段,而不是继续塞回当前 viewport host 收口任务。
## 下一阶段建议
下一阶段主线应转为:
### 1. renderer 能力继续上移
把目前 editor 层为了接通 viewport 而保留的一些临时职责,逐步让 renderer 吸收为正式能力,例如:
- 多 pass 组织能力
- 正式的 object id / editor helper pass 接口
- editor 与 runtime 共享的 camera render path
### 2. editor 只消费 renderer 提供的正式输出
editor viewport 后续应更多扮演:
- render target 宿主
- 输入转发
- overlay / gizmo 宿主
- editor 专属交互入口
而不是继续承载 renderer 内部演进本体。
## 阶段性结论
这一阶段现在可以正式收口:
- editor viewport 已经从“空面板”进入“真实宿主层”
- renderer 与 RHI 已经能稳定把离屏结果送进 editor
- viewport host 的边界已经明确
- 后续不应继续在本阶段内部无限拆分,而应切换到 renderer 下一阶段

View File

@@ -0,0 +1,78 @@
# Editor模块 CMake直链Release版XCEngine库破坏配置一致性
## 1. 问题定义
当前 editor 可执行目标的链接方式仍然是硬编码文件路径:
- [`editor/CMakeLists.txt`](D:\Xuanchi\Main\XCEngine\editor\CMakeLists.txt)
当前写法:
- `target_link_libraries(... ${CMAKE_CURRENT_SOURCE_DIR}/../build/engine/Release/XCEngine.lib)`
这不是正常的 CMake target 依赖,而是直接绑死到一个磁盘上的 `Release` 静态库文件。
---
## 2. 当前影响
这会导致几个非常实际的问题:
1. Debug editor 也可能链接到旧的 Release 版引擎库
2. editor 对 `XCEngine` 目标没有真实依赖关系
3. 引擎库变更后editor 可能不会按正确配置自动重建
4. Debug / Release 混链风险被隐藏
当前本地状态就能看到:
- `build/engine/Debug/XCEngine.lib`
- `build/engine/Release/XCEngine.lib`
两者时间戳和体积明显不同,但 editor 目标仍然硬连 Release 文件。
---
## 3. 为什么这是重大缺陷
这条会直接污染后续 Viewport 对接的开发过程:
- 你以为 editor 正在吃最新的 Renderer / RHI 改动
- 实际上它可能仍在链接旧的 Release 库
这样一来:
- viewport 接入问题很难调
- Debug 行为和 Release 行为可能不一致
- CI / 新机器 / 干净构建环境也更容易炸
它不是“代码风格问题”,而是构建依赖关系本身不正确。
---
## 4. 建议方案
应改成标准 CMake target 依赖:
1. editor 直接链接 `XCEngine`
2. 不再手写 `../build/engine/Release/XCEngine.lib`
3. 由 CMake 自己处理 Debug / Release / RelWithDebInfo 的库选择
4. editor/include 路径和 link 关系都从 target 传播,而不是继续手写 build 输出路径
---
## 5. 验收标准
完成后至少应满足:
1. `editor` 目标通过 `target_link_libraries(... XCEngine)` 链接引擎
2. Debug editor 自动吃 Debug `XCEngine`
3. Release editor 自动吃 Release `XCEngine`
4. 修改 engine 后重新构建 editor 时,依赖关系正确生效
5. 干净构建环境不依赖预先存在的某个磁盘库文件
---
## 6. 优先级
中高。
它未必第一时间阻塞面板 UI 开发,但会显著污染后续所有 viewport / renderer 联调结果,建议尽快修。

View File

@@ -0,0 +1,94 @@
# Editor模块 宿主渲染与EngineRHI未统一导致Viewport纹理无法接入
## 1. 问题定义
当前 editor 的窗口宿主渲染仍然是一套独立的原生 D3D12 路径:
- [`editor/src/Application.h`](D:\Xuanchi\Main\XCEngine\editor\src\Application.h)
- [`editor/src/Application.cpp`](D:\Xuanchi\Main\XCEngine\editor\src\Application.cpp)
- [`editor/src/Platform/D3D12WindowRenderer.h`](D:\Xuanchi\Main\XCEngine\editor\src\Platform\D3D12WindowRenderer.h)
这套路径只负责:
- 创建 Win32 窗口交换链
- 创建独立的 `ID3D12Device / ID3D12CommandQueue`
- 渲染 ImGui 主界面
而当前引擎的 RHI / Renderer 则是另一套独立设备与上下文体系。
这意味着后续即使 Renderer 能把 `SceneView/GameView` 渲染到离屏目标editor 侧也没有稳定的统一设备桥接层把那张纹理安全地贴到 ImGui。
---
## 2. 当前现状
当前 `Application::InitializeWindowRenderer()` 直接创建原生 D3D12 宿主:
- editor 只知道 `Platform::D3D12WindowRenderer`
- editor 并不持有 `RHIDevice / RenderContext / RenderSurface`
- `SceneViewPanel / GameViewPanel` 也没有可复用的 viewport host 对象
结果是:
- editor 主界面渲染和引擎 Renderer 渲染仍然分裂
- 未来 viewport 要么走不通
- 要么被迫写一层高风险的 D3D12 私有纹理互拷/句柄桥接
- 要么反向污染 Renderer使其去适配 editor 私有宿主
---
## 3. 为什么这是重大缺陷
这不是“面板里还没把图显示出来”的小缺口,而是 viewport 接入的根部边界问题。
如果不先统一宿主层,后面很容易走成错误路线:
- Editor 继续维护一套私有 D3D12 设备
- Renderer 再维护一套引擎 RHI 设备
- `SceneView``GameView` 为了显示纹理被迫做后端专用互操作
- Vulkan / OpenGL 路径在 editor 中天然失去接入可能
这会直接破坏:
- RHI 抽象边界
- Renderer 的后端无关性
- 后续 editor viewport 与 runtime 共用同一渲染链路的目标
---
## 4. 建议方案
正确方向应该是:
1. editor 宿主层只保留“窗口 + ImGui 宿主”职责
2. viewport 输出统一来自引擎 Renderer 的 `RenderSurface`
3. editor 增加专门的 viewport bridge / host 层,而不是把渲染实现塞进 panel
4. 该 bridge 层需要明确处理:
- 使用哪个 RHI backend
- 如何创建离屏 color/depth 目标
- 如何把离屏结果暴露为 ImGui 可显示纹理
- resize 生命周期
- device/context 所有权
建议不要继续扩张 `D3D12WindowRenderer` 的职责。
它可以继续作为 editor 主窗口 UI 宿主,但不应成为 viewport 真实渲染实现本体。
---
## 5. 验收标准
完成后至少应满足:
1. editor 可以不依赖私有 D3D12 纹理路径来显示 viewport
2. `SceneView``GameView` 都走统一的 viewport host 接口
3. viewport 输出来自引擎 `RenderSurface`
4. editor 不需要因为切换 OpenGL / D3D12 / Vulkan 而重写面板逻辑
5. Renderer 不需要反向依赖 editor 平台实现
---
## 6. 优先级
高。
在开始正式做 Scene/Game Viewport 之前必须先收敛这个边界,否则后面的接入实现会天然带着架构债。

View File

@@ -0,0 +1,87 @@
# Editor模块 项目根路径仍绑定可执行目录阻塞真实场景与资源加载
## 1. 问题定义
当前 editor 初始化 `EditorContext` 时,把 project path 直接设成了可执行文件目录:
- [`editor/src/Application.cpp`](D:\Xuanchi\Main\XCEngine\editor\src\Application.cpp)
具体行为是:
- 通过 `GetExecutableDirectoryUtf8()` 拿 exe 目录
- 用这个目录初始化 `EditorContext`
- `ProjectPanel``SceneManager::LoadStartupScene()` 都基于这个路径工作
这意味着 editor 当前没有“真实工程根目录”的概念。
---
## 2. 当前影响
基于当前实现:
- `ProjectManager::Initialize()` 会把 `<projectPath>/Assets` 当作项目资源根
- [`editor/src/Managers/ProjectManager.cpp`](D:\Xuanchi\Main\XCEngine\editor\src\Managers\ProjectManager.cpp)
- [`editor/src/Core/EditorWorkspace.h`](D:\Xuanchi\Main\XCEngine\editor\src\Core\EditorWorkspace.h)
`projectPath` 现在是 `editor/bin/...`
结果就是:
- Project 面板看到的是 exe 目录下的 `Assets`
- Startup Scene 也是从 exe 目录下找 `Assets/Scenes/Main.xc`
- viewport 后面如果要加载真实 scene / material / texture / mesh也会默认走错根目录
对“真正接引擎工程内容”来说,这是实打实的阻塞项。
---
## 3. 为什么这是重大缺陷
Scene/Game Viewport 一旦接 Renderer就不再只是“显示一个空测试图”。
它需要基于当前工程:
- 加载场景
- 找到 mesh / material / texture / shader 资产
- 正确解析 `Assets/...` 相对路径
如果 editor 的项目根仍然绑定在 exe 目录:
- 资源加载结果会和实际工程目录脱钩
- Editor 和运行时看到的资产树不是同一棵
- 后续 Project 面板、Scene 保存、Viewport 渲染都会形成伪项目环境
---
## 4. 建议方案
建议尽快引入明确的工程根路径入口,而不是继续默认 exe 目录:
1. `Application` 启动时明确解析 editor project root
2. 最少先支持:
- 命令行传入工程根
- 或固定读取 workspace/project 配置
3. `EditorContext / ProjectManager / SceneManager` 统一只认这一份 project root
4. `ProjectPanel`、startup scene、future viewport asset loading 全部复用同一来源
在没有真实 project root 之前,不建议开始做 viewport 里的正式资源接入。
---
## 5. 验收标准
完成后至少应满足:
1. editor 能明确知道当前工程根目录,而不是推断 exe 目录
2. Project 面板显示的是工程真实 `Assets`
3. Startup Scene 从真实工程根加载
4. Scene/Game Viewport 后续使用的资源路径与 Project 面板一致
5. Debug / Release / editor/bin 变化不会改变 editor 看到的项目内容
---
## 6. 优先级
高。
这条不解决Viewport 接入后只会跑在一个“伪项目目录”里,后面越做越难回收。

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -0,0 +1,165 @@
# Editor 重构 3.26
## 当前判断
截至 2026-03-27如果只看 editor 的 UI 架构与编辑器壳层整理,不把 `Viewport / RHI``Scene / Game` 的真实内容算进去,这一轮重构大约已经完成 **96%**
如果把“编辑器整体可用度”一起算进去,则仍然没有结束,因为:
- `Scene` panel 仍然是空壳。
- `Game` panel 仍然是空壳。
- `Viewport` 尚未跟随 RHI 重构完成回归。
所以现在的真实状态是:
- **UI 架构已经基本收稳**
- **编辑器产品功能还没有做完**
## 已经完成的核心重构
### 1. 分层已经基本建立
当前 editor 已经形成比较稳定的职责划分:
- `UI` 负责主题、token、共享控件、popup、property-grid。
- `Actions` 负责菜单、快捷键、右键菜单、按钮动作的共享路由。
- `Commands` 负责 scene/project/entity/component 的编辑行为。
- `Layout` 负责 dock host、默认布局、布局重置与持久化。
- `Panels` 逐步退化为窗口壳层。
- `Core / Managers` 负责 editor context、selection、undo、scene、project 等共享状态。
- `ComponentEditors` 负责 inspector 中各组件的编辑器与注册体系。
这说明 editor 已经从“每个 panel 自己堆逻辑”的结构,切换到“共享层驱动”的结构。
### 2. 共享 UI 基础层已经落稳
已经把大量原先散落在 panel 内部的视觉和控件逻辑收口到 shared UI 层,包括:
- 主题和样式 token
- panel chrome
- toolbar/search/button
- popup / modal state
- empty state
- asset tile
- hierarchy tree node
- component section
- property grid / scalar / vector 编辑控件
这部分的意义是:后面再调 editor 外观,不应该回到 panel 内部逐个修补。
### 3. Action 路由已经成型
当前已形成两条主路由:
- `MainMenuActionRouter`
- `EditActionRouter`
并且 `Hierarchy / Project / Inspector / Console / MenuBar` 的主要菜单和快捷键语义已经接入共享 action/router。
当前已经做到:
- `Edit` 菜单不再只是一套写死逻辑,而是跟随 active action route 切换。
- menu / shortcut / context menu / toolbar 的动作开始共用同一套 action 定义。
- rename、popup、about、exit、reset layout 等交互已不再零散写在 panel 内部。
### 4. Commands 层已经承担主要编辑语义
当前主要编辑行为已进入 command 层:
- 新建 / 打开 / 保存场景
- 脏场景 fallback 保存
- 创建 / 删除 / 复制 / 粘贴 / duplicate / rename / reparent entity
- 创建文件夹 / 删除资源 / 打开资源 / 移动资源
- 添加 / 删除组件
同时undo / dirty / selection reset 等关键边界,已经尽量不再散落在 panel。
### 5. Dock / Workspace / Application 壳层已收口
当前已经完成:
- `EditorWorkspace` 统一 panel 装配与生命周期调度
- `DockLayoutController` 统一 dockspace 和 layout reset
- ImGui layout 持久化到项目 `.xceditor/imgui_layout.ini`
- `Application.cpp` 中的窗口、renderer、ImGui session、layer attach/detach 已完成明显拆分
这说明 editor 顶层壳层已经不再像之前那样把 UI、layout、backend、panel 生命周期混在一起。
### 6. Inspector 的 ComponentEditor 注册体系已稳定
当前 inspector 不再直接硬编码全部组件逻辑,而是通过:
- `IComponentEditor`
- `ComponentEditorRegistry`
- 各具体 `Transform / Camera / Light` component editor
来统一:
- 组件显示
- Add Component 菜单构建
- 组件可添加性 / 可删除性判断
这部分已经是后续扩展自定义组件 inspector 的正确落点。
### 7. 回归测试基础已补齐
当前已新增 `editor_tests`,并已覆盖关键 editor 行为,包括:
- hierarchy edit route 的 copy / paste / duplicate / delete / rename request
- project edit route 的 open / back / delete
- scene dirty save + load 后的 selection / undo reset
- reparent 时的 parent 切换、cycle 拦截与 world transform 保持
- main menu 的 exit / reset layout / about popup request
- hierarchy rename helper
- project create-folder / move-asset / open-folder helper
本轮收尾继续补充后,测试会进一步覆盖:
- clean scene 下的新建场景重置行为
- clean scene 下 fallback save 的 no-op 路径
- project move-asset 的非法输入保护
## 当前仍然剩下什么
### 架构收尾项
1. 继续压缩少量 panel 本地瞬时状态
目标是把还能共享的 popup / router / state 再往 shared 层收一点。
2. 继续补 editor 回归测试
重点补 command/router 边界,而不是 UI 像素测试。
3. 为 viewport 回归保留 editor shell 接口
但暂时不把 RHI/renderer 接进来。
### 暂缓项
以下内容不计入当前这一轮 UI 架构收尾:
- `Scene` panel 真正内容
- `Game` panel 真正内容
- `Viewport` 渲染接入
原因不是不做,而是这些工作和 renderer / RHI 重构直接绑定,应该放到后续阶段。
## 本轮新增文档
本次已补正式架构说明:
- `docs/plan/Editor架构说明.md`
这个文档用于明确:
- 各层职责边界
- 允许依赖方向
- panel / action / command / manager / component editor 的落点规则
- event bus、undo、dirty、selection 的统一约定
## 阶段性结论
当前 editor 可以明确地说:
- **UI 架构层面已经基本重构完成**
- **剩余主要是封口、验证和后续 viewport 接入准备**
也就是说,后面不应该再回到“看到一个 panel 问题就地补一段特殊逻辑”的方式,而应该继续沿着现有分层做增量完善。

View File

@@ -0,0 +1,536 @@
# Library资产导入与缓存系统收口计划
归档状态2026-04-03当前 `project` 范围内的 Library 导入与缓存系统收口已完成,本文档转为归档记录。
## 0. 文档定位
这份文档不是上一轮“从零搭一套 Unity 式 Library 体系”的继续描述,而是当前阶段的正式收口文档。
### 0.1 当前执行进度2026-04-03
| 阶段 | 状态 | 当前结果 |
| --- | --- | --- |
| 阶段 A协议定稿与旧兼容删除 | 已完成 | 已删除 `mesh=` / `materials=` 旧兼容读取,项目资产序列化正式收敛到 `AssetRef`路径字段仅保留给虚拟资源scene 迁移工具链已移除。 |
| 阶段 B导入与缓存边界收口 | 已完成 | `AssetImportService` 已接管 Library 根目录、快照构建、缓存重建与 artifact 保证入口;`ProjectAssetIndex` 已只消费服务快照;`ResourceManager` 已收口为运行时缓存/异步调度入口,并提供 `RefreshProjectAssets` / `RebuildProjectAssetCache`。 |
| 阶段 C进行中 | 已完成 `xcmat` 纹理绑定的 `AssetRef + lazy resolve` 首轮收口;下一步继续压缩缓存命中后的恢复成本,并检查是否还存在主线程等待点。 |
| 阶段 D最小工具闭环 | 已完成 | 已完成 `Reimport Selected Asset / Reimport All Assets / Clear Library` 正式入口;已补 `Project` 面板最小导入状态输出;已接入 orphan artifact 清理。 |
### 0.2 当前已完成的收口结果2026-04-03
- 阶段 A 已完成并验证通过:
- `MeshFilterComponent` 对项目 mesh 只序列化 `meshRef``meshPath` 只保留给 `builtin://...`
- `MeshRendererComponent` 对项目 material 只序列化 `materialRefs``materialPaths` 只保留给 `builtin://...`
- 旧的 `mesh=` / `materials=` 兼容读取已移除
- scene 迁移命令、菜单、report 链路已删除
- 阶段 B 已完成并验证通过:
- `AssetImportService` 对外新增 `LookupSnapshot``ImportedAsset``GetLibraryRoot()``RebuildLibraryCache()`
- `ProjectAssetIndex` 不再直接拼装 `AssetDatabase` 细节,而是只刷新服务快照
- `ResourceManager` 不再暴露旧式导入数据库心智,新增 `RefreshProjectAssets()``RebuildProjectAssetCache()``GetProjectLibraryRoot()`
- `AssetDatabase` 初始化后会落盘 `ArtifactDB/artifacts.db`,使空 Library 结构稳定成型
- 阶段 C 已开始并完成首个子项:
- `Material` 纹理绑定新增稳定 `AssetRef` 元数据,运行时按需把 `AssetRef` 解析为加载路径
- `xcmat` 协议已升级为纹理绑定写入 `AssetRef + load path hint`
- `AssetDatabase` importer version 已提升,旧 material artifact 将自动失效并重建
- 阶段 D 已开始并完成首轮工具口:
- `AssetDatabase` 已新增 `TryGetImportableResourceType()``ReimportAsset()``ReimportAllAssets()`
- `AssetImportService` 已新增 `ClearLibraryCache()``ReimportAllAssets()``ReimportAsset()`
- `ResourceManager` 已新增 `CanReimportProjectAsset()``ReimportProjectAsset()``ClearProjectLibraryCache()`
- editor `Assets` 菜单已新增 `Reimport Selected Asset``Reimport All Assets``Clear Library`
- `AssetImportService` 已新增导入状态快照,`Project` 面板工具栏会显示最近一次导入/清库/清理状态
- `AssetDatabase` 已新增 orphan artifact 清理,`Refresh / Reimport / 自动重导入` 后都会回收未被 `ArtifactDB` 引用的 `Library/Artifacts/*` 目录
- 已完成 focused 验证:
- `asset_tests`
- `ResourceManager_Test.ConcurrentAsyncLoadsCoalesceSameMeshPath`
- `ResourceManager_Test.AssetLookupFallbackRefreshesSnapshotForNewProjectAsset`
- `ProjectAssetIndex_Test.RefreshesSnapshotThroughImportServiceOnCacheMiss`
- `AssetImportService_Test.RebuildLibraryCacheKeepsStableAssetRefs`
- `ResourceManager_Test.RebuildProjectAssetCacheRefreshesLookupState`
- `AssetImportService_Test.ClearLibraryAndReimportAllAssetsManageArtifactsExplicitly`
- `AssetImportService_Test.ImportStatusTracksExplicitOperationsAndRefreshCleanup`
- `ResourceManager_Test.ReimportProjectAssetBuildsArtifactForSelectedPath`
- `editor_tests`
- `EditorActionRoutingTest.ProjectCommandsExposeAssetCacheMaintenanceActions`
- `EditorActionRoutingTest.ProjectCommandsReimportSelectedAssetAndClearLibraryDriveAssetCache`
- `EditorActionRoutingTest.ProjectCommandsReportWhenScriptAssembliesCanBeRebuilt`
- `components_tests`
- `MeshRendererComponent_Test.SerializeAndDeserializeLoadsProjectMaterialByAssetRef`
- `MeshRendererComponent_Test.DeferredSceneDeserializeLoadsProjectMaterialAsync`
- `material_tests`46/46 通过
- `mesh_tests`33/33 通过
- `scene_tests`
- `Scene_ProjectSample.DeferredLoadBackpackSceneEventuallyRestoresBackpackMesh`
- `Scene_ProjectSample.DeferredLoadBackpackSceneEventuallyProducesVisibleRenderItems`
- `XCEditor` Release 已成功编译
旧方案文档已经归档到:
- `docs/plan/used/Unity式Library资产导入与缓存系统重构方案.md`
归档原因很简单:
- 旧文档解决的是“从没有 Library到建立 Library 基础设施”的问题。
- 现在的问题已经不是“要不要做 Library”而是“怎么把当前这套半过渡、半正式的实现收成一套干净的正式系统”。
本轮收口以以下前提为准:
- 只服务当前 `project` 这一个项目。
- 不兼容旧版本 scene / component 资产引用格式。
- 不再提供旧格式迁移工具。
- 可以直接改写 `project` 下现有场景和资源源文件。
- 目标不是继续堆补丁,而是形成一套边界清晰、行为稳定、可长期维护的正式实现。
---
## 1. 当前收口基线
当前系统已经具备以下基础,这些不是本轮要推倒重来,而是本轮收口的起点:
- 已有 Unity 风格的 `Library` 目录结构:
- `Library/SourceAssetDB`
- `Library/ArtifactDB`
- `Library/Artifacts`
- 已有 `.meta + AssetGUID` 机制,项目资产已经具备稳定身份。
- 已有 `AssetRef` 结构,运行时已经可以通过 `AssetRef` 回查项目资产。
- 已有纹理、材质、模型 artifact
- `xctex`
- `xcmat`
- `xcmesh`
- 已有 `AssetImportService`,用于承接导入与 artifact 保证逻辑。
- 已有 `ProjectAssetIndex`,用于承接项目资产路径与 `AssetRef` 快照索引。
- `ResourceManager` 已不再直接承担全部导入数据库职责,而是开始回到运行时调度器角色。
- scene 打开链路已经接入 deferred restore`MeshFilterComponent` / `MeshRendererComponent` 能在反序列化后异步恢复项目资源。
- 当前 `project/Assets/Scenes/Main.xc``project/Assets/Scenes/Backpack.xc` 已经具备 `AssetRef` 版本数据,可作为最终格式收口的直接修改对象。
当前真正没有收口的,不是“功能不存在”,而是下面这三类问题还在:
- 还保留着旧格式兼容和双写逻辑。
- 组件 / scene / editor 工具链里还残留过渡期代码。
- 材质与贴图恢复仍不够轻,缓存命中后仍有额外同步成本。
---
## 2. 本轮收口的核心原则
### 2.1 不保留旧版本兼容
这是本轮与上一轮最大的区别。
本轮明确不做以下事情:
- 不兼容历史 `mesh=` / `materials=` 场景字段。
- 不兼容“项目资产仍按普通文件路径序列化”的旧格式。
- 不保留 `path + AssetRef` 双写作为长期状态。
- 不保留 `Migrate Scene AssetRefs` 之类的迁移工具与菜单。
允许保留的只有两类稳定引用:
- `AssetRef`
- 用于 `project/Assets` 下的正式项目资产。
- `builtin://...`
- 用于内置几何体、内置默认材质等虚拟内置资源。
这里的 `builtin://` 不是旧版本兼容,而是引擎内部稳定资源协议,可以继续保留。
### 2.2 只对当前项目做干净落地
因为当前只服务一个项目,所以这轮不需要为了“以后可能导入旧项目”保留复杂迁移链路。
本轮允许直接做以下事情:
- 直接改写 `project/Assets/Scenes/*.xc`
- 直接删除旧序列化字段的读写逻辑
- 直接删除旧迁移命令、菜单、报告结构
- 直接调整测试数据到最终格式
### 2.3 运行时只负责“用缓存”,不负责“解释历史”
收口完成后,运行时层要满足:
- scene 反序列化只恢复最终格式数据
- `ResourceManager` 只做运行时缓存、异步调度、artifact 读取入口
- 导入与索引职责留在 `AssetImportService` / `ProjectAssetIndex`
- 不再在运行时主链路里背负旧协议兼容判断
### 2.4 收口优先级高于“继续设计更大系统”
本轮目标是把现有系统收干净,不追求继续扩成更庞大的框架。
因此本轮只做两件事:
- 删除过渡态
- 补齐正式版闭环
不在本轮追求:
- prefab 全面资产管线化
- 动画、音频、shader 全类型导入器
- 远程缓存
- 多项目兼容框架
- 一步到位把所有内部类都拆到最细
---
## 3. 收口后的目标形态
### 3.1 最终数据协议
收口后scene / component 的资产引用协议定为:
- 项目 mesh只写 `meshRef`
- 项目 material只写 `materialRefs`
- 内置 mesh`meshPath=builtin://...`
- 内置 material`materialPaths=builtin://...`
不再允许以下状态作为正式协议存在:
- 项目资产依旧只存普通文件路径
- 项目资产同时写路径和 `AssetRef`
- 反序列化时优先猜测旧字段再兜底
### 3.2 最终运行时边界
收口后各层职责如下:
- `AssetImportService`
- 工程扫描
- `.meta` 管理
- SourceAssetDB / ArtifactDB 维护
- `EnsureArtifact`
- `Refresh`
- `Reimport` / `Clear Library` 入口
- `ProjectAssetIndex`
- 项目资产路径快照
- `AssetRef <-> 项目路径` 映射
- 项目资产查找缓存
- `ResourceManager`
- runtime object cache
- async load coalescing
- artifact runtime load dispatch
- deferred scene load 控制
- Component / Scene
- 只保存最终资产引用
- 不承担旧协议迁移职责
### 3.3 最终用户行为
收口后应达到以下体验:
- 第一次导入可能慢,但之后再打开同一个 scene不应再同步重跑原始 `obj/png/jpg` 导入。
- 打开含有大型 OBJ 的 scene 时,不应长时间卡死 editor 主窗口。
- 命中 artifact 后mesh/material 恢复应尽量走异步路径。
- 关闭 editor 再打开后,项目资产引用应稳定恢复,不出现“模型丢失、材质丢失、内置 sphere 丢失”这类状态回退问题。
- 用户能明确知道当前是“命中缓存”还是“正在导入/重建缓存”。
---
## 4. 本轮必须删除的过渡态
这部分是收口计划的关键,不删掉这些内容,系统就始终处于过渡状态。
### 4.1 删除旧序列化兼容
目标:
- 删除 `MeshFilterComponent` 对旧 `mesh=` 字段的长期兼容读取。
- 删除 `MeshRendererComponent` 对旧 `materials=` 字段的长期兼容读取。
- 删除“项目资产 path 与 `AssetRef` 双写”的长期行为。
允许保留:
-`builtin://` 的显式处理。
禁止保留:
- “先读 path不行再猜 `AssetRef`
- “为了兼容老场景继续支持项目文件路径”
### 4.2 删除场景迁移工具
以下过渡期工具应整体移除:
- `Migrate Scene AssetRefs` 菜单项
- 对应 action / command / project manager migration report
- 专门为旧场景迁移设计的 editor 流程
原因:
- 当前项目只有一个,已有 scene 可以直接重写。
- 继续保留迁移工具,只会让新系统一直背着旧协议。
### 4.3 删除长期双轨测试
需要同步清理测试中的过渡态假设:
- 旧格式 scene 兼容测试
- 双写格式测试
- 迁移工具测试
替换成正式版测试:
- 最终 scene 协议测试
- 关闭 editor 重开后的稳定恢复测试
- artifact 命中路径测试
- 异步恢复与渲染可见性测试
---
## 5. 本轮必须补齐的正式能力
### 5.1 材质与贴图真正 lazy 化
当前模型 artifact 虽然已经存在,但材质恢复后仍然容易把关联贴图一起拉进来,导致:
- 场景虽然不在反序列化阶段阻塞
- 但资源真正恢复时仍然偏重
本轮必须补齐:
- `xcmat` 成为正式稳定 artifact
- `Material` 运行时对象只持有 texture `AssetRef`
- texture runtime handle 按槽位、按需解析
- mesh 恢复不顺手触发整套材质贴图同步加载
这是“缓存命中了但还是觉得重”的核心收口项。
### 5.2 明确导入与运行时边界
虽然最近已经引入:
- `AssetImportService`
- `ProjectAssetIndex`
但本轮要进一步明确:
- `ResourceManager` 外部不再暴露旧式导入心智
- 项目资产查找统一经过 `ProjectAssetIndex`
- artifact 生成统一经过 `AssetImportService`
- `AssetDatabase` 作为底层实现细节继续收口到 service 后面
本轮的目标不是一定把 `AssetDatabase` 拆成三个类,而是先把“对外边界”收干净。
也就是说,本轮要求:
- 类内可暂时还偏胖
- 但对外职责必须已经清晰
### 5.3 缓存运维闭环
正式版至少要有以下最小运维能力:
- 单资源 Reimport
- `Reimport All`
- `Clear Library`
- 项目启动时检查并重建缺失缓存
- 删除源资源后识别 orphan artifact
如果这些没有,系统虽然能工作,但一旦缓存脏掉就难以恢复,仍然不算收口。
### 5.4 可观测性闭环
本轮至少要做到用户能看见:
- 当前资源是命中 artifact 还是触发重导入
- 正在导入哪个资源
- 导入失败原因
- scene 正在等待哪些资源恢复
不要求本轮先做完整面板,但至少要把日志、状态文案、必要的调试输出整理成稳定可用的最小版本。
---
## 6. 实施阶段
## 阶段 A协议定稿与旧兼容删除
### 目标
把当前半兼容、半正式的 scene / component 数据协议收成最终格式。
### 任务
-`MeshFilterComponent`
- 项目资产只写 `meshRef`
- 只对 `builtin://` 保留 `meshPath`
- 删除旧 `mesh=` 历史兼容读取
-`MeshRendererComponent`
- 项目资产只写 `materialRefs`
- 只对 `builtin://` 保留 `materialPaths`
- 删除旧 `materials=` 历史兼容读取
- 直接改写 `project/Assets/Scenes/Main.xc`
- 直接改写 `project/Assets/Scenes/Backpack.xc`
- 如果项目里还有其他 scene / snapshot / prefab 使用旧项目资产路径,一并直接改成最终格式
### 同步删除
- `Migrate Scene AssetRefs` action
- `ProjectCommands` 中对应 migration command
- `ProjectManager` 中对应 migration report / migration logic
- 相关测试
### 阶段完成标准
- 项目场景中不再存在旧项目资产路径协议
- engine/editor 中不再存在迁移工具入口
- 组件反序列化代码只处理最终协议与 builtin 协议
## 阶段 B导入与缓存边界收口
### 目标
`Library` 系统对外呈现为一套明确的正式接口,而不是几个类拼在一起的过渡实现。
### 任务
- 把项目资产索引访问统一走 `ProjectAssetIndex`
- 把 artifact 生成与保证统一走 `AssetImportService`
- 收敛 `ResourceManager` 中剩余的导入数据库耦合
- 梳理 `AssetDatabase` 内部接口,限制它作为 service 内部实现使用
- 增加明确的 `Refresh / Reimport / Clear Library` 入口
### 阶段完成标准
- editor / runtime 外部调用时,心智模型已经稳定为:
- 找项目资产:`ProjectAssetIndex`
- 产出或校验 artifact`AssetImportService`
- 取 runtime object`ResourceManager`
## 阶段 C性能闭环
### 目标
把“看起来已经异步,但恢复仍然偏重”的成本继续压下去。
### 任务
- 材质贴图 lazy resolve
- 减少 mesh 恢复时顺手加载整套关联资源
- 校验首次导入、二次打开、关闭重开三种路径的时间差异
- 清理仍可能在主线程触发的大锁与同步等待点
- 必要时加入轻量 placeholder / loading state 文案
### 阶段完成标准
- 含 OBJ 的 scene 再次打开时editor 主窗口不出现长时间假死
- artifact 命中时恢复成本显著低于首次导入
- 关闭 editor 重开后的恢复链路仍然稳定
## 阶段 D最小工具闭环
### 目标
把这套系统变成“可维护”的,而不是只能靠调试日志救火。
### 任务
- 已完成:增加 `Reimport Asset`
- 已完成:增加 `Reimport All`
- 已完成:增加 `Clear Library`
- 已完成:增加最小导入状态输出
- 已完成:增加 orphan artifact 清理
### 阶段完成标准
- 用户可以主动重建缓存
- 缓存脏掉时不需要手工删文件再碰运气
- 导入失败时能直接看到原因
---
## 7. 验收标准
本轮收口完成,必须同时满足以下条件:
### 7.1 协议层
- 项目资产引用正式统一为 `AssetRef`
- 不再保留旧 scene / component 项目资产路径兼容协议
- 不再保留迁移工具
### 7.2 架构层
- `AssetImportService` / `ProjectAssetIndex` / `ResourceManager` 的对外职责稳定
- 运行时不再承担旧协议解释职责
- `Library` 已经是正式依赖,而不是临时缓存补丁
### 7.3 功能层
- OBJ / 贴图 / 材质二次打开优先命中 artifact
- 关闭 editor 重开后项目 scene 能稳定恢复
- builtin sphere / cube / default material 不会因为缓存系统而丢失
### 7.4 性能层
- 打开含大型 OBJ 的 scene 时不长时间卡死 editor
- 二次打开与首次导入的体感耗时有明显区分
- 命中 artifact 后不再退回源文件同步导入主路径
### 7.5 工具层
- 具备最小 `Reimport / Reimport All / Clear Library` 能力
- 有最小可观测性输出
---
## 8. 本轮不做的内容
为了尽快收口,本轮明确不做以下扩展:
- prefab 全量资产协议翻新
- 动画 / 音频 / shader 新 importer
- 远程缓存
- 多项目历史版本兼容框架
- 完整图形化导入面板
- 一次性把所有 `AssetDatabase` 内部实现拆到最细
这些内容后续可以继续做,但不应该阻塞当前正式收口。
---
## 9. 推荐执行顺序
建议按下面顺序推进,避免边做边反复回滚:
1. 先做阶段 A直接把项目协议和旧兼容删干净。
2. 再做阶段 B把对外边界稳定下来。
3. 然后做阶段 C把“缓存命中了但恢复仍然重”的问题收掉。
4. 最后做阶段 D补齐最小运维与可观测性。
原因是:
- 不先删旧兼容,后面所有逻辑都要双轨维护。
- 不先把边界定清,性能问题会一直和历史兼容问题缠在一起。
- 不先把主链路收稳,工具做出来也只是给过渡态续命。
---
## 10. 本轮涉及的主要代码范围
本轮预计重点落在以下文件:
- `engine/src/Components/MeshFilterComponent.cpp`
- `engine/src/Components/MeshRendererComponent.cpp`
- `engine/include/XCEngine/Core/Asset/ResourceManager.h`
- `engine/src/Core/Asset/ResourceManager.cpp`
- `engine/include/XCEngine/Core/Asset/AssetImportService.h`
- `engine/src/Core/Asset/AssetImportService.cpp`
- `engine/include/XCEngine/Core/Asset/ProjectAssetIndex.h`
- `engine/src/Core/Asset/ProjectAssetIndex.cpp`
- `engine/include/XCEngine/Core/Asset/AssetDatabase.h`
- `engine/src/Core/Asset/AssetDatabase.cpp`
- `editor/src/Managers/ProjectManager.cpp`
- `editor/src/Commands/ProjectCommands.h`
- `editor/src/Actions/EditorActions.h`
- `editor/src/Actions/MainMenuActionRouter.h`
- `tests/core/Asset/test_resource_manager.cpp`
- `tests/Components/test_mesh_render_components.cpp`
- `tests/Scene/test_scene.cpp`
- `project/Assets/Scenes/Main.xc`
- `project/Assets/Scenes/Backpack.xc`
---
## 11. 一句话结论
从这一刻开始,这个模块的目标不再是“继续兼容旧系统”,而是:
把当前已经跑起来的 `Library`、artifact、`AssetRef`、异步恢复链路,收成一套只服务当前项目、无旧包袱、可稳定重开的正式资产系统。

View File

@@ -0,0 +1,567 @@
# Material Inspector与Shader属性面板收口计划
日期2026-04-07
## 1. 背景
当前 Rendering / Shader / Material 主线已经基本建立起正式架构:
- Shader 侧已经具备统一的 authoring/schema 能力。
- Material 运行时与 artifact 路径已经逐步从旧兼容逻辑中收口。
- Editor 中的 Material Inspector 仍然没有完全切换到“由 Shader schema 驱动”的正式工作流。
当前最突出的实际问题有两类:
1. Material 选择 Shader 后Shader 中声明的属性没有被正式暴露到 Inspector 面板上。
2. Material 面板上还残留了一些历史字段或临时 UI用户无法清晰判断哪些是正式能力哪些只是过渡产物。
此外,当前工程条件已经允许做更彻底的清理:
- `project/` 中旧材质资产可直接编辑。
- 当前不存在必须长期兼容的历史材质资产包袱。
因此,这一阶段的目标不是“继续兼容旧面板”,而是把 Material 编辑链路彻底切换到正式路径,并为后续 Shader/Material 编辑器扩展打好基础。
## 2. 本阶段目标
本阶段要完成以下目标:
1. 让 Material Inspector 成为 Shader schema 驱动的正式编辑入口。
2. 让材质面板只暴露当前正式架构中的概念,不再混入旧字段和误导性配置。
3. 保证 Editor 面板、运行时 `Material`、源资产、artifact、reimport 之间的数据一致性。
4. 用单测和必要的编辑器验证把这条链路收口,而不是停留在“能显示”层面。
## 3. 不在本阶段处理的内容
以下内容不属于本阶段主目标,避免范围失控:
- 自定义 Material Drawer 系统。
- Shader Graph / 节点式材质编辑器。
- 面向美术工作流的复杂 Material 预设库。
- SRP 层级的材质检查器定制机制。
- 完整的 Shader GUI 仿 Unity 高级扩展体系。
这些能力后续可以做,但必须建立在当前正式链路已经稳定收口的前提上。
## 4. 当前已确认的问题
### 4.1 Inspector 没有正式反射 Shader 属性
当前 Material Inspector 还没有完整读取 Shader schema 并按类型生成属性控件,导致:
- Shader 中声明的属性无法完整暴露。
- 用户无法直接编辑当前材质真正生效的参数。
- 材质默认值、覆盖值、纹理槽与资源引用状态之间关系不清晰。
### 4.2 材质面板仍存在历史路径残留
之前材质层面曾承担过一些本不应由材质承担的职责,例如:
- 材质自己选择 builtin pass。
- Inspector 里出现与当前正式架构不一致的旧字段。
这类逻辑已经开始清理,但 Editor 面板仍需同步彻底收口。
### 4.3 Editor 与运行时 Material 状态可能脱节
如果面板的编辑状态不是直接围绕正式 `Material` 数据模型建立,就容易出现:
- Inspector 显示值与运行时实际值不一致。
- 资源重载后 UI 状态失真。
- artifact / reimport 后材质参数丢失或回退异常。
### 4.4 缺少围绕正式工作流的测试闭环
仅靠手工点 Inspector 验证不足以支撑后续迭代。必须补足以下覆盖:
- Shader 切换后属性集合重建。
- 默认值与显式覆盖值的切换。
- Texture 属性与资源引用链路。
- Keyword 与 Render State 的持久化。
- artifact/reimport 后数据一致性。
## 5. 设计原则
本阶段严格遵循以下原则:
### 5.1 Shader 定义什么Material 就暴露什么
Material 不是独立定义属性结构的地方。属性结构必须由 Shader schema 决定Inspector 只是将其可视化并允许编辑。
### 5.2 Material 只承载实例数据,不承载管线选择策略
材质应承载:
- Shader 引用
- Shader schema 对应的属性值
- Keyword 状态
- 合法的 render state 覆盖
材质不应再承载:
- 独立指定 builtin pass 的旧路径
- 与 Shader metadata 冲突的临时策略字段
### 5.3 Editor 不发明第二套数据模型
Inspector 的中间态必须服务于正式数据模型,而不是绕开 `Material` 自己维护一套平行逻辑。
### 5.4 面板必须可验证
每一步改动都必须能通过测试或明确的编辑器验证闭环证明正确,不接受只靠目测“看起来差不多”。
## 6. 分阶段执行计划
## Phase 1现状审查与残留路径清点
### 目标
彻底梳理当前 Material Inspector、Material 资源、Shader schema、artifact 序列化之间的实际数据流。
### 任务
- 审查 `InspectorPanel` 当前 Material 面板的数据来源和写回路径。
- 审查 `Material` 当前正式字段与历史遗留字段。
- 审查 `MaterialLoader``AssetDatabase`、artifact schema 当前是否仍保留不必要兼容路径。
- 识别 Material 面板中哪些字段是正式路径,哪些属于旧方案残留。
### 完成标准
- 列清楚当前正式数据流。
- 列清楚必须删除的旧字段/旧 UI。
- 列清楚缺失的 schema 反射入口。
## Phase 2Material Inspector 数据模型收口
### 目标
让 Material 面板的数据模型只围绕正式架构组织。
### 任务
- 移除 Material 层面的旧 pass 选择 UI 与残余兼容路径。
- 整理 Inspector 内部状态结构,只保留:
- Shader 资源引用
- Shader schema 对应属性
- Keywords
- Render Queue / Render State
- Tags仅保留当前正式允许暴露的部分
- 避免 Inspector 保存与运行时 `Material` 不一致的冗余字段。
### 完成标准
- 面板字段与正式 `Material` 模型一一对应。
- 旧字段彻底不再出现在材质编辑界面和保存链路中。
## Phase 3Shader schema 驱动的属性面板生成
### 目标
Material Inspector 能基于 Shader schema 动态生成属性编辑 UI。
### 任务
- 读取 Shader 声明的属性定义与默认值。
- 按属性类型渲染控件:
- `float`
- `int`
- `bool`
- `float2/3/4`
- `texture`
- 正确显示每个属性的:
- 属性名
- 显示名
- 默认值
- 当前覆盖值
- 纹理槽绑定状态
- 资源引用路径/AssetRef 状态
- 明确“未覆盖时使用 Shader 默认值”的表现形式。
### 完成标准
- 选定 Shader 后Inspector 中能稳定暴露该 Shader 的正式属性集合。
- 面板能正确编辑并持久化这些属性。
## Phase 4Editor 与运行时一致性收口
### 目标
保证 Material Inspector 编辑结果与运行时 `Material`、artifact、reimport 行为一致。
### 任务
- 对齐 Inspector 写回逻辑与 `Material` 正式 API。
- 验证 Shader 切换时属性重建、默认值回退、无效属性清理。
- 验证纹理属性在源资产、artifact、异步资源加载中的一致性。
- 验证关键词与 render state 在 reload/reimport 后不丢失。
### 完成标准
- Inspector 改动能被运行时正确读取。
- Reload / Reimport / Artifact Round Trip 后材质数据不漂移。
## Phase 5测试补齐与阶段验收
### 目标
为正式工作流建立可持续回归验证。
### 任务
- 补充或更新 `material_tests`
- 补充或更新 `asset_tests`
- 若材质解析或 builtin pass 匹配受影响,补充必要的 `rendering_unit_tests`
- 重新编译 `XCEditor`,执行人工冒烟验证。
### 验收项
- `material_tests` 全绿。
- `asset_tests` 全绿。
- 必要的 `rendering_unit_tests` 全绿。
- `XCEditor` 编译通过。
- Material Inspector 中 Shader 属性暴露、编辑、保存、重载行为正确。
## 7. 预期交付结果
本阶段完成后,工程应达到以下状态:
1. Material 面板正式切换为 Shader schema 驱动。
2. 材质不再承担旧 pass 选择职责。
3. Inspector 中只剩下当前正式架构允许存在的字段。
4. 材质属性、纹理槽、关键词、render state 都能稳定编辑并正确持久化。
5. Shader / Material 后续扩展拥有清晰入口,不再建立在旧兼容逻辑之上。
## 8. 风险与注意事项
### 8.1 Shader 切换会触发属性重建
必须定义清楚以下规则:
- 与新 Shader schema 匹配的属性如何保留。
- 不匹配的旧属性如何移除。
- 默认值何时回退,何时保留用户覆盖。
### 8.2 Texture 属性不仅是 UI 问题
Texture 属性同时涉及:
- Inspector 显示
- AssetRef
- 资源路径
- artifact 存储
- 延迟加载
因此不能只改面板显示,必须连同资源路径一起验证。
### 8.3 Render State 需要坚持“正式最小集”
Material 面板不应再次演化成随意堆字段的临时入口。所有 render state 暴露都必须建立在当前正式支持的能力之上。
## 9. 建议执行顺序
建议严格按以下顺序落地:
1. 先完成旧字段与旧路径清点。
2. 再重构 Inspector 数据模型。
3. 再接 Shader schema 驱动属性 UI。
4. 再收口 Editor 与运行时一致性。
5. 最后统一补测与验收。
不能反过来先堆 UI再回头补数据模型否则很容易再次生成新的临时方案。
## 10. 阶段结论
当前最应该推进的不是继续增加 Material 编辑功能花样,而是把 Material Inspector 这条正式链路做对、做稳、做干净。
只要这一阶段收口完成,后续无论是:
- 更完整的 Shader authoring
- Material 默认面板
- 针对 Renderer/SRP 的材质体系扩展
- 更接近 Unity 的 Shader/Material 编辑工作流
都会建立在清晰、稳定、可验证的基础之上。
## 11. Phase 1 审查结果
状态:已完成
本阶段已对当前 Material Inspector、运行时 `Material`、Shader schema、material source/artifact 路径进行了实际代码审查,结论如下。
### 11.1 当前 Inspector 数据模型先天不完整
当前 `InspectorPanel::MaterialAssetState` 只维护了以下内容:
- `shaderPath`
- `renderQueue`
- `renderState`
- `tags`
它没有正式承载以下关键数据:
- Shader schema 属性列表
- 材质属性当前值
- 纹理槽与贴图引用
- 关键词状态
- Render State Override 开关本身
这意味着当前 Inspector 不是“少画了几个控件”,而是其内部状态模型本身就无法表示正式的材质编辑数据。
### 11.2 当前 Inspector 保存链路会丢失材质的正式内容
当前 `BuildMaterialAssetFileText()` 仅写出:
- `shader`
- `renderQueue`
- `tags`
- `renderState`
它不会写出:
- `properties`
- `textures`
- `keywords`
因此,只要一个材质已经拥有 Shader 属性、纹理槽或关键词,若用户通过当前 Inspector 保存一次,该材质源文件就可能被覆盖成一个严重简化后的版本,导致正式材质数据丢失。
### 11.3 当前 Inspector 的实时写回同样不完整
当前 `ApplyResolvedMaterialStateToResource()` 仅把面板状态写回到运行时 `Material` 的以下部分:
- `SetShader`
- `SetRenderQueue`
- `SetRenderState`
- `ClearTags` / `SetTag`
它不会写回:
- Shader schema 属性值
- 纹理绑定
- 关键词
因此 Inspector 当前即使支持继续加控件,如果不先重构数据模型,运行时同步仍然会不完整。
### 11.4 Render State Override 当前没有被正式建模
运行时 `Material::SetRenderState()` 会自动把 `HasRenderStateOverride` 置为 `true`
但当前 Inspector
- 没有暴露 “是否启用 Render State Override”
- 保存时始终写出完整 `renderState`
- 应用时始终调用 `SetRenderState`
这意味着只要用户通过当前材质面板保存,材质就会被强制推进到显式 Render State Override 路径。这个行为不符合正式设计,必须在下一阶段一起修正。
### 11.5 运行时底层能力其实已经基本齐备
当前 runtime/resource 层已经具备正式所需的大部分能力:
- `ShaderPropertyDesc` 已包含 `name / displayName / type / defaultValue / semantic`
- `Shader` 已提供 `GetProperties()` / `FindProperty()` / keyword declaration 能力
- `Material` 已提供完整的 `SetFloat/SetInt/SetBool/SetTexture...`
- `Material` 已支持 Shader schema 默认值同步
- `MaterialLoader` 已支持解析 `properties / textures / keywords / tags / renderState`
- material artifact 当前已支持这些正式数据的持久化
也就是说,当前问题的主要矛盾不在资源系统,而在 Editor 侧没有接入正式模型。
### 11.6 当前阶段的根本性结论
下一阶段不能直接在现有材质面板上继续堆控件。
必须先完成:
1. `MaterialAssetState` 的正式重构
2. Save/Reload/Apply 链路对 `properties / textures / keywords / renderState override` 的建模
3. Inspector 与运行时 `Material` 之间的一致性重建
只有先做完这些,后续的 Shader schema 驱动属性 UI 才不会继续建立在错误基础上。
### 11.7 Phase 2 的直接执行范围
基于本阶段审查结果,下一阶段将直接进入以下工作:
1. 扩展 `MaterialAssetState`,让其正式承载属性、纹理槽、关键词与 render state override。
2. 重构 `Populate / Apply / Save / Reload` 这四条关键链路。
3. 彻底消除当前“保存一次就丢属性”的结构性问题。
## 12. Phase 2 执行结果
状态:已完成
本阶段已经完成 Material Inspector 数据模型的第一轮正式收口,重点是先把状态模型与保存链路做正确,而不是提前堆属性 UI。
### 12.1 已完成内容
- `MaterialAssetState` 已扩展为正式承载:
- `keywords`
- `properties`
- `texture bindings`
- `renderState override`
- `PopulateMaterialAssetStateFromResource()` 已从运行时 `Material` 同步:
- Shader 路径
- Render Queue
- Render State
- Render State Override 标志
- Tags
- Keywords
- Properties / Texture Bindings
- `ApplyResolvedMaterialStateToResource()` 已开始完整写回:
- Shader
- Render Queue
- Render State
- Render State Override
- Tags
- Keywords
- Properties / Texture Bindings
- `BuildMaterialAssetFileText()` 已开始正式写出:
- `keywords`
- `properties`
- `textures`
- 仅在启用 override 时才写 `renderState`
- Inspector 已增加 `Render State Override` 开关,避免默认把材质强行推进到显式 override 路径。
### 12.2 本阶段解决的核心问题
本阶段已经解决了最危险的结构性问题:
- 当前 Inspector 再保存材质时,不会像之前那样天然丢掉 `properties / textures / keywords`
- Render State 是否为显式 override已经不再是隐藏副作用而成为正式状态的一部分。
### 12.3 本阶段仍未完成的部分
以下能力还没有在本阶段完成,这是下一阶段的工作重点:
- 基于 Shader schema 的属性 UI 自动生成
- 各属性类型的可视化编辑控件
- 默认值/覆盖值的明确表现
- 纹理槽的正式资源选择 UI
- 关键词与属性在 Inspector 中的可视化编辑
因此Phase 2 的性质是“先把材质状态模型与保存链路做对”,而不是“材质面板功能已经完整”。
## 13. Phase 3 执行结果
状态:已完成
本阶段已经开始把正确的材质状态模型真正暴露到 Inspector 上,重点是基于 Shader schema 生成属性面板,并处理 Shader 切换时的状态重建。
### 13.1 已完成内容
- Inspector 已新增 `Properties` 区块。
- 属性区会基于当前 Shader 的 schema 动态生成,而不是写死字段。
- 当前已接入的属性类型包括:
- `Float / Range`
- `Int`
- `Color`
- `Vector`
- `Texture2D / TextureCube`
- Texture 类型已接入资源选择控件,不再只是文本占位。
- 每个属性当前会直接显示 Shader 中声明的默认值文本,作为当前参数的基线提示。
### 13.2 Shader 切换行为已收口
本阶段同时处理了一个关键一致性问题:
- 当用户切换 Shader 时Inspector 会先基于新 Shader schema 重建 `MaterialAssetState`
- 能与新 Shader 对齐的同名属性会尽量保留原值
- 已不被新 Shader 声明的旧属性不会继续残留在保存结果里
- 与新 Shader 不匹配的旧关键词也会被清理
这样可以避免旧材质属性被继续写回到新 Shader 材质文件中,从而减少生成无效材质源文件的风险。
### 13.3 本阶段仍未完成的部分
以下内容还需要后续阶段继续收口:
- 属性默认值与显式覆盖值的正式“重置/回退”交互
- 关键词的可视化编辑 UI
- 更完整的属性类型与显示策略细化
- 针对 Inspector 材质链路的专门自动化测试
因此Phase 3 的完成标准是“Shader schema 驱动的属性面板已经建立起来”,但还不是最终形态。
## 14. Phase 4 执行结果
状态:已完成
本阶段重点处理的是 authoring-state 与 runtime-state 的一致性问题,避免 Inspector 因为单纯从运行时对象反推而破坏材质源文件的语义。
### 14.1 已完成内容
- Inspector 现在会回读材质源文件中实际 authored 的:
- `properties`
- `textures`
- `keywords`
- `renderState`
- 材质状态中已加入“是否需要序列化回源文件”的 authored 标记。
- 保存材质时,不再无条件把所有运行时属性都写回源文件。
- 对于未在源文件中显式 authored 的属性,当前会继续保持“继承 Shader 默认值”的语义。
- 当用户在 Inspector 中修改属性或贴图后,对应项才会被标记为显式 authored 并写回源文件。
### 14.2 本阶段解决的核心问题
本阶段解决的是一个架构层面的隐患:
- 如果只从运行时 `Material` 反推回材质源文件,打开并保存一次材质,就会把 Shader 默认值全部固化进 `.mat`
- 一旦默认值被固化,后续 Shader 默认值再调整,材质就不再继承新的默认值。
当前这条链路已经收口到更合理的状态:
- 只有显式 authored 的 override 才会写回
- 默认值仍然可以继续作为 Shader 侧的基线被继承
### 14.3 本阶段仍未完成的部分
以下内容仍然需要下一阶段继续完成:
- 针对 Inspector 材质链路的专门自动化测试
- 属性“重置到默认值”的正式交互
- 关键词的可视化编辑 UI
- 更完整的属性类型/显示策略覆盖
因此Phase 4 的性质是“先把 authoring 语义做正确”,为最后的测试与收口创造条件。
## 15. Phase 5 执行结果
状态:已完成
本阶段重点不是继续扩材质面板功能,而是把已经形成的正式链路变成“可持续回归验证”的状态,并把测试面收口到 Inspector 实际依赖的核心逻辑上。
### 15.1 已完成内容
- 新增 `MaterialInspectorMaterialState` / `MaterialInspectorMaterialStateIO` 辅助模块,承载:
- Material Inspector 状态结构
- source authored presence 解析
- Shader 切换时的属性/关键词重同步
- 材质源文件序列化文本生成
- 新增 `tests/editor/test_material_inspector_material_state_io.cpp`,覆盖:
- authored 属性/纹理/关键词标记识别
- Shader 切换时保留兼容 override、清理陈旧字段
- 非 authored 默认值不写回源文件
- 纹理 override 与 render state override 的正式序列化
- `editor_tests` 构建链路已接入上述 helper 与新测试文件。
### 15.2 已执行验证
- `cmake --build build --config Debug --target XCEditor -j 8`
- `cmake --build build --config Debug --target editor_tests -- /v:minimal`
- `build/tests/Resources/Material/Debug/material_tests.exe`
- `build/tests/Core/Asset/Debug/asset_tests.exe`
- `build/tests/Editor/Debug/editor_tests.exe --gtest_filter=MaterialInspectorMaterialStateIOTest.*`
验证结果:
- `XCEditor` 编译通过
- `material_tests`61 / 61 通过
- `asset_tests`56 / 56 通过
- `MaterialInspectorMaterialStateIOTest`4 / 4 通过
### 15.3 当前剩余风险
- 全量 `editor_tests.exe` 在顺序执行 `EditorActionRoutingTest.*` 时仍存在既有的共享状态级别挂起现象。
- 该挂起并非本次新增的材质面板测试本身触发:
- 新增 `MaterialInspectorMaterialStateIOTest` 单独执行通过
- `EditorActionRoutingTest.PlayModeAllowsRuntimeSceneUndoRedoButKeepsSceneDocumentCommandsBlocked` 单独执行通过
- 因此,本阶段围绕 Material Inspector / Shader 属性面板的测试收口已经完成,但 Editor 其余历史测试链路仍需单独排查。

View File

@@ -0,0 +1,656 @@
# Renderer 下一阶段Shader、Material 与 Pass 体系设计
日期:`2026-04-02`
## 1. 阶段判断
当前 Renderer 阶段已经完成的事情,是把下面这条主链正式接通并收口:
`RHI -> Rendering -> Editor Scene/Game Viewport`
当前已经具备:
- `SceneRenderer -> CameraRenderer -> RenderPipeline` 的主执行边界
- scene camera request 组织能力
- built-in forward 主几何绘制
- `object-id` 渲染与 editor picking
- built-in post-process 入口
- editor viewport 宿主接入
- 对应的 renderer/editor 自动化测试闭环
这意味着 Renderer 已经不再是“RHI 之上的一堆零散 draw call”而是已经形成了真实的模块边界。
但这并不意味着 Renderer 已经进入“可长期扩展”的状态。
当前阶段的真正短板,不是 render graph而是
- shader 还没有进入正式 renderer 主路径
- material 还不是正式 GPU 参数绑定载体
- pass contract 还不完整
- 三后端虽然都能跑,但 shader authoring 仍是内建硬编码
所以 Renderer 的下一阶段主线,不应优先做 render graph而应优先完成
- `Shader`
- `Material`
- `Builtin Pass Contract`
- `Renderer-owned Feature Contract`
---
## 2. 为什么下一阶段不是 Render Graph
`render graph` 不是简单优化项,它本质上是更高一层的资源依赖与多 pass 调度框架。
但当前工程还没有满足它最该承接的前提:
1. 还没有足够正式的 pass 分类体系
2. 还没有正式的 shader / material 执行契约
3. editor helper pass 与 runtime pass 还没有统一语义
4. 还没有稳定的 renderer feature 输入输出边界
如果现在直接上 render graph会出现一个问题
- graph 框架先做了
- 真正的 shader/material/pass 契约还没收紧
- 最后 graph 里承载的还是一批语义松散的临时 pass
这会让架构“看起来高级”,但基础层仍然不稳。
因此下一阶段正确顺序应当是:
1. 先收紧 shader/material/pass contract
2. 再把更多 renderer feature 统一为正式能力
3. 等真正的多 pass 复杂度上来后,再引入 render graph
---
## 3. 当前 Renderer 的真实问题
### 3.1 Shader 仍未进入正式主路径
当前 built-in forward pipeline 的 shader 仍然是直接硬编码在 C++ 中:
- D3D12: HLSL
- OpenGL: GLSL 430
- Vulkan: GLSL 450
这意味着:
- `Material::GetShader()` 虽然存在,但不控制当前主渲染
- shader 资源尚未成为正式运行时契约
- 新增 pass 或 shader 变体时,仍然需要直接改 pipeline C++
这不符合后续 Unity 风格 SRP 的方向。
### 3.2 Material 还是“资源状态载体”,不是正式 GPU 材质实例
当前 `Material` 已具备:
- render queue
- rasterizer / blend / depth-stencil render state
- tag
- property
- texture binding
- shader 引用
但真正进入 GPU 执行链路的内容,仍然很少:
- per-object constant
- 一张主纹理
- 一个 sampler
- 少量 pass metadata 过滤
也就是说:
- material property 还没有正式映射到 GPU layout
- material constant buffer 还没有进入正式绑定链路
- texture binding 还没有从“约定名字查一张图”升级为“按 pass layout 正式绑定”
### 3.3 Pass contract 仍然不够完整
当前比较明确的 pass 只有:
- forward 主几何
- object-id
- grid
- selection outline
- debug mask
但如果后面要走 Unity 风格 renderer至少需要明确区分
- `ForwardLit`
- `Unlit`
- `DepthOnly`
- `ShadowCaster`
- `ObjectId`
- editor helper pass
否则后面一旦加入阴影、深度预通道、材质分流、后处理和 SRP 注入就会重新回到“if/else 管线”。
### 3.4 三后端能跑,但还不是正式 shader 资产体系
当前三后端运行没问题,不代表 shader 体系已经成熟。
当前缺的是:
- 统一的 shader 资产描述
- 每个 shader pass 的 backend variant 管理
- 统一的 descriptor / constant layout 描述
- renderer 内部的 pipeline cache key 规范
现在只是“每个 backend 有一份能工作的内建 shader”离正式体系还有明显距离。
---
## 4. 下一阶段的核心目标
下一阶段目标不是“把所有渲染功能做完”,而是建立正式可扩展的 renderer 执行契约。
核心目标分四层。
### 4.1 正式建立 Shader Asset Contract
下一阶段应把 `Shader` 从资源占位,提升为 renderer 正式消费的资源。
建议 shader 资产至少包含:
- shader 名称与 GUID
- pass 列表
- 每个 pass 的逻辑名称
- 每个 pass 的 tag例如 `LightMode`
- 每个 pass 的 property layout
- 每个 pass 的 resource binding layout
- 每个 backend 的 shader variant
建议的概念模型:
```text
ShaderAsset
-> ShaderPassDesc[]
-> passName
-> tags
-> propertyLayout
-> backendVariants
```
这里的关键点不是一开始就做复杂 shader graph而是先明确
- renderer 以后创建 pipeline不再直接从 C++ 字符串取 shader
- renderer 应从 shader asset 的某个 pass 中取当前 backend 对应 variant
### 4.2 正式建立 Material Instance Contract
`Material` 下一阶段要从“资源状态容器”升级为“可绑定的材质实例”。
Material 至少应当明确:
- 它引用哪个 shader
- 它选择 shader 的哪个 pass
- 它当前有哪些 property override
- 它有哪些 texture binding
- 它导出的 render state 是什么
下一阶段不要求一开始就做复杂材质编辑器,但必须完成:
- property -> GPU 常量区布局
- texture binding -> descriptor binding
- pass 过滤规则
- material instance 的缓存与脏标记
### 4.3 正式建立 Builtin Pass Contract
下一阶段应当把当前 renderer 内建 pass 明确分层:
- 几何主 pass
- 深度/阴影类 pass
- object-id/editor helper pass
- post-process / overlay pass
建议第一批正式化的 pass 名称:
- `ForwardLit`
- `Unlit`
- `DepthOnly`
- `ShadowCaster`
- `ObjectId`
说明:
- `ForwardLit` 支撑当前主线
- `Unlit` 用于 editor helper、gizmo、调试对象、简单 UI mesh
- `DepthOnly``ShadowCaster` 为后面阴影与可见性阶段铺路
- `ObjectId` 让 editor/runtime picking 有正式 renderer 合约
### 4.4 正式建立 Renderer Feature Contract
当前 grid / outline / object-id / debug mask 已经部分进入 renderer但仍然带有明显 editor 来路。
下一阶段应继续把它们定义为 renderer feature而不是 editor 特判:
- object-id output
- selection / mask debug
- overlay helper contract
- camera request 上的 feature request
目标不是马上做完整 feature graph而是明确
- 哪些 feature 属于 renderer
- 哪些输入由 editor 组装
- 哪些输出由 renderer 提供
---
## 5. 三后端 Shader 策略
这一节必须进一步说透两个问题:
1. 三后端语言不同shader 资产到底怎么组织
2. shader authoring 到底采用“Unity 式一份 shader 里写多个 stage”还是把 vertex / fragment 拆成独立文件
### 5.1 当前阶段不建议直接追求“单源码全平台自动转译”
理论上可以追求:
- 统一 HLSL
- 再编到 SPIR-V / GLSL
但这会立刻引入:
- 工具链依赖
- shader reflection
- backend 兼容差异处理
- 调试复杂度
对于当前工程,这不是下一阶段最优先的问题。
### 5.2 下一阶段建议采用“统一逻辑资产 + 后端分 variant”的务实方案
建议下一阶段的 shader 策略是:
- 逻辑上一个 shader asset
- 资产里按 pass 持有多个 backend variant
- renderer 根据 backend 选择对应源码/二进制
例如:
```text
BuiltinLit.shader
Pass: ForwardLit
D3D12 -> HLSL
OpenGL -> GLSL 430
Vulkan -> GLSL 450 / SPIR-V
```
这样做的优点:
- 三后端路径清晰
- 不引入过早的跨编译复杂度
- 仍然能在资产层统一 shader 逻辑身份
- 后续要切换成统一 authoring 也有演进空间
### 5.3 Vulkan 的长期方向
Vulkan 长期更适合进入:
- 预编译 SPIR-V
- 反射生成 binding layout
但这属于再下一阶段的工程化增强。
当前下一阶段只要求:
- Vulkan 不再依赖 pipeline cpp 内嵌 shader 字符串的散乱模式
- Vulkan variant 被纳入正式 shader asset contract
### 5.4 推荐的 Shader 资产组织方式
建议下一阶段采用:
- **逻辑上一个 ShaderAsset**
- **资产内部按 Pass 组织**
- **每个 Pass 内再按 Stage 与 Backend 持有 variant**
推荐概念模型:
```text
ShaderAsset
-> Pass: ForwardLit
-> Stage: Vertex
-> D3D12 : xxx.vs.hlsl
-> OpenGL : xxx.vs.glsl
-> Vulkan : xxx.vs.vk.glsl / xxx.vs.spv
-> Stage: Fragment
-> D3D12 : xxx.ps.hlsl
-> OpenGL : xxx.fs.glsl
-> Vulkan : xxx.fs.vk.glsl / xxx.fs.spv
-> Pass: DepthOnly
-> ...
```
也就是说:
- 对 renderer 来说,真正识别的是一个 `ShaderAsset`
- 对 pass 来说,拿到的是“这个 pass 在当前 backend 下对应的各 stage 变体”
- 对后端来说,最终看到的仍然是它自己能吃的 shader 源码或二进制
这样处理后:
- shader 逻辑身份是统一的
- backend 差异被收进 variant 层
- pass / stage / backend 三个维度都清楚
### 5.5 不建议直接照搬 Unity ShaderLab 的单文件大一统方案
如果完全模仿 Unity最直观的形式是
- 一份 shader 文件
- 里面写 `Pass`
- `Pass` 里面再写 `Vertex/Fragment`
这种方式的优点是:
- 对材质和 pass 关系表达很强
- 很适合后续 editor / inspector / C# SRP 暴露
但它当前直接落地的缺点也很明显:
- 你现在有三个 backend
- backend shader 语言并不统一
- 还没有自己的 shader import / include / preprocess / reflection 工具链
如果现在直接做成 Unity 那种单文件 DSL等于同时要解决
- shader 语法设计
- parser
- include 系统
- multi-pass 语义
- backend variant 分发
- material property layout
这会把下一阶段的复杂度一下子拉爆。
### 5.6 下一阶段更务实的做法
下一阶段建议采用“两层模型”:
#### 第一层:逻辑层接近 Unity
保留 Unity 风格的核心语义:
- 一个 shader 有多个 pass
- 每个 pass 有名字和 tag
- material 绑定的是 shader 与 pass
#### 第二层:物理文件层先按 stage 分开
实际文件先拆成:
- `*.vs.hlsl`
- `*.ps.hlsl`
- `*.vs.glsl`
- `*.fs.glsl`
- `*.vs.vk.glsl`
- `*.fs.vk.glsl`
或者编译后:
- `*.spv`
也就是说:
- **逻辑上用 Unity 式“一个 shader 拥有多个 pass”**
- **物理落地上暂时不用 Unity 式“一个文件里硬塞所有 backend/stage”**
这是当前阶段最稳妥的方案。
### 5.7 对“vertex / fragment 是合一还是分开”的明确结论
结论分两层:
#### 从逻辑资产视角看
应当是“合一”的。
也就是:
- 一个 `ShaderAsset`
- 下面有一个或多个 `Pass`
- 一个 `Pass` 同时拥有 vertex / fragment 等 stage
这和 Unity 的思路一致。
#### 从实际源码文件视角看
应当先“分开”。
也就是:
- vertex shader 单独文件
- fragment shader 单独文件
- backend variant 单独文件
原因:
- 更容易做 backend 分发
- 更容易调试编译错误
- 更容易做最小 shader import
- 更适合你当前三后端并行维护
所以不要把“逻辑合一”和“源码物理文件合一”混为一谈。
最终建议是:
- **逻辑模型采用 Unity 风格**
- **文件组织先采用分 stage、分 backend**
### 5.8 未来再向 Unity ShaderLab 靠拢的演进路径
等下一阶段把下面这些都做稳之后:
- shader asset contract
- material property binding
- backend variant 选择
- pass contract
后面再往上加一层更接近 Unity ShaderLab 的 authoring 语法,就顺理成章:
```text
ShaderLab-like Authoring
-> Shader Importer
-> ShaderAsset / Pass / Variant
-> RenderPipeline Runtime
```
也就是说:
- 现在先做 runtime contract
- 以后再做更高级的 shader authoring front-end
这样不会把工程顺序做反。
---
## 6. 建议的新分层
建议 Renderer 下一阶段形成下面这套更稳定的分层:
```text
Scene / Components / Resources
-> RenderSceneExtractor / RenderRequestPlanner
-> Shader & Material Runtime
-> CameraRenderer / RenderPipeline
-> Builtin Feature Passes
-> RHI
-> D3D12 / OpenGL / Vulkan
```
其中新增的重点层是:
### 6.1 Shader & Material Runtime
负责:
- 解析 shader asset / material asset
- 生成 pass 级 binding layout
- 维护 material GPU 数据与脏标记
- 提供 pipeline cache key
### 6.2 Builtin Feature Passes
负责:
- object-id
- grid
- outline
- shadow/depth 等 builtin pass
这样可以让:
- `RenderPipeline` 更聚焦于场景主流程组织
- 各 pass 更聚焦于自己真正的职责
---
## 7. 推荐的落地顺序
### 阶段 AFormalize Builtin Pass Metadata
先完成:
- `ForwardLit`
- `Unlit`
- `DepthOnly`
- `ObjectId`
需要落地的内容:
- pass name
- pass tag
- renderer 如何选择某个 material 的 pass
- builtin pipeline 不再依赖模糊字符串判断
完成标志:
- `MatchesBuiltinPass(...)` 不再只是当前这种最小过滤,而是更接近正式 pass contract
### 阶段 BMaterial GPU Binding 最小闭环
先完成:
- material 常量数据打包
- texture binding 正式映射
- sampler 策略统一
- material 脏标记 -> GPU 缓存更新
完成标志:
- forward pipeline 不再只会找一张 `_MainTex` 风格贴图
- material property 真正进入 shader 执行链
### 阶段 CShader Asset 真正进入 Render Pipeline
先完成:
- builtin shader 资产化
- 每个 builtin shader 具备 backend variant
- pipeline state 从 shader asset pass 创建
完成标志:
- `BuiltinForwardPipeline.cpp` 中的大段后端 shader 字符串不再是长期正式实现
### 阶段 DRenderer-owned Feature Contract 收口
先完成:
- object-id request/output 正式化
- outline/grid 继续从 editor 逻辑脱耦
- camera request 上的 feature request 更明确
完成标志:
- editor 侧更多只做 request 装配,而不是 feature 逻辑承担者
### 阶段 E验证与回归
必须补的测试:
- renderer unit tests
- shader/material runtime unit tests
- pass metadata 选择测试
- backend integration smoke tests
- editor viewport regression
---
## 8. 下一阶段明确不做的内容
以下内容不进入下一阶段主线:
- render graph
- 完整 shader graph
- 完整 deferred renderer
- 大规模后处理栈
- 完整阴影系统产品化
- C# SRP 真正脚本驱动落地
原因不是这些不重要,而是它们依赖下一阶段先把基础契约做稳。
---
## 9. 与 Unity 风格架构的承接关系
如果后面目标是做 Unity 风格的 C# SRP那么下一阶段必须先把“原生 renderer 可被脚本驱动”的基础层做好。
Unity 风格承接关系应理解为:
```text
Shader / Material / Pass Contract
-> Native Render Pipeline Runtime
-> ScriptableRenderContext / CommandBuffer
-> C# RenderPipelineAsset / RenderPipeline
```
也就是说:
- 当前下一阶段做的不是 SRP 本身
- 但做的是 SRP 能否成立的地基
如果这一层继续缺失,后面脚本层会直接耦合到一堆临时内建逻辑上,最后 SRP 只会沦为“脚本包装的硬编码 forward pipeline”。
---
## 10. 阶段成功标准
这一阶段完成时,至少应满足:
1. shader asset 已进入 renderer 主路径
2. material property 与 texture binding 已形成正式 GPU 绑定链
3. builtin pass contract 已具备最小完整集
4. 三后端 shader 不再依赖 pipeline cpp 中散乱硬编码作为长期实现
5. object-id / outline / grid 等 renderer feature 边界进一步明确
6. renderer/editor 对应测试体系同步补齐
---
## 11. 一句话总结
Renderer 下一阶段的正确主线不是 render graph而是
- 先把 `Shader`
- `Material`
- `Pass Contract`
- `Renderer Feature Contract`
做成正式能力。
只有这一层站稳之后,后面的:
- 阴影
- 更多 pass
- render graph
- C# SRP
才会是顺势生长,而不是继续堆临时方案。

View File

@@ -0,0 +1,841 @@
# Renderer 下一阶段Unity 风格 Shader 体系正式化计划
日期:`2026-04-06`
## 1. 阶段结论
当前 renderer 主线已经可以阶段性收口,但 `Shader / Material / Pass` 体系还没有真正统一。
现在仓库里的 shader 体系处于一个过渡态:
- 逻辑上已经有 `Shader -> Pass -> Variant` 模型
- authoring 外观上已经接近 Unity ShaderLab
- 运行时已经能按 pass 和 backend variant 选择 shader
- 三后端已经能稳定跑通 builtin shader
但它仍然不是 Unity 风格的正式体系,因为当前 authoring 仍然暴露了太多 backend 与 binding 细节:
- `.shader` 文件里仍然显式写 `#pragma backend D3D12/OpenGL/Vulkan`
- `.shader` 文件里仍然显式写 `Resources { name(type, set, binding) }`
- material 仍然可以显式指定 `shaderPass`
- shader 关键字、变体、include、pass state、SubShader 选择还没有真正成体系
所以这一阶段的主线不是继续做新渲染效果,而是把 shader 体系升级成:
- **authoring 层完全按 Unity 风格书写**
- **三后端编译路径统一收敛到 importer / compiler 层**
- **runtime 只消费正式 shader artifact / material contract**
这一步不是 SRP 本身,但它是后续 SRP 能否成立的硬地基。
---
## 2. 阶段目标
本阶段要达成的核心目标只有一件事:
**把当前“伪 ShaderLab + 后端直连”的过渡体系升级为“Unity 风格 authoring + 引擎内部统一 shader IR + 三后端编译产物”的正式体系。**
完成后应达到:
1. shader authoring 采用 Unity 风格 `.shader` 语法,不再要求作者显式写 backend variant 分发表。
2. 新语法不再要求作者手写 `set/binding` 级资源绑定表。
3. HLSL 成为 raster shader 的单一 authoring 语言源。
4. D3D12 / Vulkan / OpenGL 的差异退到 importer / compiler / artifact 层。
5. material 只管 property / keyword / texture / render state不再负责点名 pass。
6. renderer 按 `LightMode` / pass contract 选 pass而不是靠 material 的临时字符串兜底。
7. builtin shader 全部迁移到新体系并保持三后端回归稳定。
8. 保留 legacy shader 兼容层,避免一次性炸掉现有工程内容。
---
## 3. 非目标
本阶段明确不做:
- SRP 本体
- render graph
- deferred / clustered
- Shader Graph
- Surface Shader
- 完整 Unity ShaderLab 100% 全语法一次性覆盖
- volume 系统
- 更多新渲染效果
本阶段也不追求一口气把 Unity 的所有 authoring 特性补完,例如:
- `Fallback`
- `UsePass`
- `CustomEditor`
- `GrabPass`
- tessellation / geometry / ray tracing authoring
这些可以后续补,但不应阻塞当前阶段把“统一 shader 体系”先做正确。
---
## 4. 当前真实状态与根本问题
### 4.1 当前已经具备的能力
当前工程已经具备:
- `.shader` 文件解析能力
- `Shader` 的 pass / property / resource / variant 数据模型
- builtin shader 资产化
- material property / texture / render state / tag 载体
- renderer 中按 builtin pass metadata 选择可用 shader pass
这意味着当前不是从零开始设计。
### 4.2 当前最根本的问题
当前最大的问题不是“没有 shader 体系”而是“authoring 层和 runtime 层的边界还没收干净”。
具体表现为:
1. **authoring 层暴露后端差异**
- `.shader` 文件直接写 `#pragma backend D3D12/OpenGL/Vulkan`
- shader 作者必须知道后端与源码文件映射
2. **authoring 层暴露 RHI binding 细节**
- `.shader` 文件显式写 `Resources { ConstantBuffer / Texture2D / Sampler, set, binding }`
- 这更像 Vulkan/D3D12 binding 清单,不是 Unity 风格 shader authoring
3. **material 还带着临时 pass 选择职责**
- `Material::SetShaderPass()` 仍然存在
- renderer 仍然优先吃 material 显式指定的 pass
- 这会阻碍未来 RendererFeature / SRP 规范化
4. **关键字与变体体系缺失**
- 没有正式的 `multi_compile / shader_feature`
- 没有变体剥离与编译缓存策略
5. **include 与共享库体系缺失**
- 没有正式的 shader include 搜索路径、预处理、公共库组织
6. **pass state 仍然不在 shader authoring 的统一语义内**
- 诸如 `Cull / ZWrite / ZTest / Blend / ColorMask / Stencil` 还没有完整进入 shader authoring contract
7. **三后端仍然是物理三套源码直连**
- 当前虽然“逻辑上一个 shader asset”
- 但作者本质上还在维护三套 shader stage 文件
---
## 5. 核心设计结论
### 5.1 目标不是“看起来像 Unity”而是“真正采用 Unity 风格 authoring 模型”
最终目标应当是:
- 一个 `.shader` 文件描述一个逻辑 shader
- shader 内部有 `Properties / SubShader / Pass / Tags / State / Program`
- renderer 消费的是 import 后的统一 IR / artifact
- backend 差异不暴露给 shader 作者
### 5.2 HLSL 作为单一 authoring 语言源
本阶段必须明确:
- **新体系下 raster shader 统一使用 HLSL authoring**
- D3D12 直接编 HLSL
- Vulkan 由 HLSL 编到 SPIR-V
- OpenGL 由 HLSL 编到 SPIR-V再转 GLSL 430
原因:
- 如果 authoring 仍然保留 GLSL/HLSL 三套并行,永远不可能真正统一写法
- 只有 single-source authoring才能接近 Unity 的真实体验
### 5.3 backend 差异必须退到 importer / compiler 层
新 authoring 文件中不应再出现:
- `#pragma backend ...`
- backend 专属 stage 文件路径表
这些内容应由 importer 根据 target backend 生成产物。
### 5.4 resource binding 不再由 shader 作者手写 `Resources(set,binding)`
Unity 风格 shader authoring 不要求作者手写 descriptor set / binding。
因此新体系下应改为:
- material 暴露属性来自 `Properties`
- engine 内建 constant buffer / texture / sampler 来自约定与 reflection
- importer 通过 HLSL reflection + 约定库推导 runtime resource layout
也就是说:
- authoring 层写“语义”
- importer 层生成“绑定布局”
- runtime 层消费“绑定布局”
### 5.5 pass 选择必须回归 renderer而不是 material
新体系中:
- material 只绑定 shader 与 property / keyword / texture
- renderer 按 `LightMode` 选 pass
- `Material::shaderPass` 进入弃用与最终移除路径
这与 Unity 的 `ShaderTagId / LightMode` 思路对齐,也更利于未来 SRP。
### 5.6 必须保留 legacy 兼容层
当前仓库已经有一批 builtin shader 和测试资产。
因此不能激进地“一刀切重做”,而应:
- legacy `.shader` 继续可加载
- 新 Unity 风格 `.shader` 进入新 importer 路径
- builtin shader 分批迁移
- runtime 统一落在同一套 `Shader` / artifact / variant 模型上
---
## 6. 目标架构
建议把 shader 体系正式分成 5 层。
### 6.1 Authoring 层
职责:
- 让开发者以 Unity 风格书写 shader
建议语法子集:
- `Shader`
- `Properties`
- `SubShader`
- `Pass`
- `Tags`
- `LOD`
- `HLSLINCLUDE`
- `HLSLPROGRAM`
- `ENDHLSL`
- `#pragma vertex`
- `#pragma fragment`
- `#pragma target`
- `#pragma multi_compile`
- `#pragma shader_feature`
- `#pragma shader_feature_local`
- `Cull`
- `ZWrite`
- `ZTest`
- `Blend`
- `ColorMask`
- `Stencil`
- `Offset`
### 6.2 Importer / Parser 层
职责:
- 解析 Unity 风格 `.shader`
- 生成统一的内部 `ShaderIR`
建议引入:
- `ShaderAuthoringParser`
- `ShaderIR`
- `ShaderSubShaderIR`
- `ShaderPassIR`
- `ShaderKeywordDecl`
- `ShaderPassStateDesc`
- `ShaderProgramIR`
### 6.3 Compiler / Reflection 层
职责:
- 编译 authoring 中的 HLSL
- 为不同 backend 生成最终编译产物
- 生成 resource layout / constant layout / keyword variant metadata
建议技术路径:
- D3D12`DXC -> DXIL/DXBC`
- Vulkan`DXC -> SPIR-V`
- OpenGL`DXC -> SPIR-V -> SPIRV-Cross -> GLSL 430`
输出:
- 每个 pass / stage / keyword-set / backend 的编译产物
- 反射出的 constant buffer / texture / sampler 布局
### 6.4 Artifact 层
职责:
- 保存运行时真正消费的 shader 产物
建议引入新版 artifact
- `xcshader2` 或继续升级现有 `xcshader`
artifact 内容至少包含:
- shader 名称 / guid
- properties
- subshader / pass tags
- pass state
- keyword declarations
- keyword variant table
- backend binaries / backend source payload
- reflected resource layout
- include 依赖与 hash
### 6.5 Runtime 层
职责:
- renderer 根据 pass contract、keywords、backend 选择最终 variant
- material 根据 property/texture 生成常量与资源绑定
- pipeline cache 根据 shader variant + render state 建 key
---
## 7. Unity 风格 authoring 范围定义
### 7.1 第一阶段必须支持的语法
第一阶段建议正式支持:
```shaderlab
Shader "XCEngine/Example/Lit"
{
Properties
{
_BaseColor ("Base Color", Color) = (1,1,1,1)
_BaseMap ("Base Map", 2D) = "white" {}
_Cutoff ("Alpha Cutoff", Range(0,1)) = 0.5
}
HLSLINCLUDE
#include "ShaderLibrary/Core.hlsl"
ENDHLSL
SubShader
{
Tags { "RenderType"="Opaque" "Queue"="Geometry" }
LOD 200
Pass
{
Name "ForwardLit"
Tags { "LightMode"="ForwardLit" }
Cull Back
ZWrite On
ZTest LEqual
Blend One Zero
HLSLPROGRAM
#pragma target 4.5
#pragma vertex Vert
#pragma fragment Frag
#pragma multi_compile _ XC_MAIN_LIGHT_SHADOWS
#pragma shader_feature_local _ XC_ALPHA_TEST
ENDHLSL
}
}
}
```
### 7.2 第一阶段暂不支持的语法
第一阶段可暂缓:
- `Fallback`
- `UsePass`
- `GrabPass`
- `CustomEditor`
- `Category`
- `Dependency`
- Surface Shader
- CG fixed-function 时代遗留语义
这些需要列入兼容性说明,但不应阻塞首版落地。
---
## 8. 统一的 shader library 与 include 体系
这一层是“写法统一”能否成立的关键。
### 8.1 必须引入正式的 include 库
建议新增:
- `engine/assets/shaderlib/ShaderLibrary/Core.hlsl`
- `engine/assets/shaderlib/ShaderLibrary/Common.hlsl`
- `engine/assets/shaderlib/ShaderLibrary/SpaceTransforms.hlsl`
- `engine/assets/shaderlib/ShaderLibrary/Lighting.hlsl`
- `engine/assets/shaderlib/ShaderLibrary/MaterialInput.hlsl`
- `engine/assets/shaderlib/ShaderLibrary/Shadow.hlsl`
目标:
- builtin shader 共用统一宏与公共函数
- authoring 层不再重复声明一堆 per-object / lighting 结构
### 8.2 统一的内建常量组
建议统一为接近 Unity 的内建分组:
- `UnityPerFrame``XCPerFrame`
- `UnityPerCamera``XCPerCamera`
- `UnityPerDraw``XCPerDraw`
- `UnityPerMaterial``XCPerMaterial`
建议引擎内部最终保留 `XC*` 前缀实现名,但 authoring 宏层提供 Unity 风格别名。
### 8.3 内建纹理/采样器由 include 库与 reflection 管理
例如:
- 主纹理
- 阴影图
- 环境图
- sampler state
这些都不再由 `.shader` 手填 `Resources(set,binding)`
---
## 9. Material 体系同步改造
shader 统一如果不带 material 一起改,最后会停在半路。
### 9.1 material 的职责边界
新体系里 material 负责:
- 选择 shader
- 保存 property override
- 保存 texture override
- 保存 keyword 开关
- 保存材质级 render queue / tag override如保留
新体系里 material 不再负责:
- 指定 `shaderPass`
- 硬编码 backend 资源名
- 猜测 shader 内的 descriptor set / binding
### 9.2 material constant buffer 正式化
必须建立:
- `Properties` -> `UnityPerMaterial/XCPerMaterial` 布局
- importer 生成 property layout
- material 按 layout 打包 GPU 常量
- layout/hash 进入 pipeline/material cache key
### 9.3 keyword 体系正式化
建议引入:
- `global keywords`
- `local keywords`
- material keyword set
- variant lookup key
material 应持有:
- `ShaderKeywordSet`
renderer 运行时根据:
- shader
- pass
- keyword set
- backend
选择最终 shader variant。
---
## 10. Renderer 运行时契约调整
### 10.1 pass 选择规则统一为 `LightMode`
renderer 选 pass 时只看:
- 当前 pipeline 阶段需要的 `LightMode`
- shader/subshader/pass 是否匹配
- backend 是否有有效 variant
例如:
- 主几何:`ForwardLit` / `Unlit`
- 阴影:`ShadowCaster`
- 深度:`DepthOnly`
- ObjectId`ObjectId`
- FinalOutput`FinalColor`
### 10.2 material 显式 `shaderPass` 进入弃用路径
建议执行顺序:
1. 第一阶段保留字段,但标记为 legacy
2. runtime 优先按 pass contract / LightMode 选 pass
3. 只有 legacy 资产才允许 fallback 到 `shaderPass`
4. migration 完成后移除 `shaderPass` 主路径职责
### 10.3 builtin pass metadata 继续保留,但收进 importer/runtime
当前基于 semantic 的 builtin pass binding 解析仍然有价值,但应改成:
- authoring/IR 层表达语义
- compiler/reflection 层生成 binding plan
- runtime 只消费 binding plan
而不是继续靠散落的名字匹配和 fallback。
---
## 11. 三后端统一策略
### 11.1 D3D12
目标:
- 直接消费 HLSL 编译产物
- 反射得到 root signature / resource layout 所需元数据
第一阶段可继续沿用 `ps_5_0 / vs_5_0`,但建议同时规划升级:
- 后续逐步转 `SM 6.x`
### 11.2 Vulkan
目标:
- 统一吃由 HLSL 编到 SPIR-V 的产物
- 摆脱独立 `.vk.glsl` 长期维护
### 11.3 OpenGL
目标:
- 不再长期维护独立 `.glsl` authoring 文件
- importer 自动生成 OpenGL 目标 GLSL 430
这一步会是整个阶段最大的工程风险之一,但它是“写法统一”绕不开的核心点。
### 11.4 迁移期间的策略
在新体系落稳前,允许:
- legacy backend-specific variant 继续存在
- 新 Unity 风格 shader 走统一 HLSL single-source 路径
两套 importer 并行一段时间,最终再逐步淘汰 legacy path。
---
## 12. 分阶段实施计划
### Phase A冻结目标与建立兼容边界
目标:
- 明确“什么叫 Unity 风格 shader”
- 明确 legacy 与新 authoring 的兼容边界
工作项:
1. 写清 Unity 风格支持子集。
2. 明确旧 `.shader` 的 legacy 模式规则。
3. 明确新 authoring 中禁止出现:
- `#pragma backend`
- `Resources(set,binding)`
4. 明确 material 中 `shaderPass` 的弃用策略。
完成标准:
- 文档、命名、兼容边界全部写死
### Phase B建立新的 Shader Authoring Parser 与 IR
目标:
-`.shader` authoring 能导入到统一 `ShaderIR`
工作项:
1. 新增 parser支持
- `Shader / Properties / SubShader / Pass / Tags`
- `HLSLINCLUDE / HLSLPROGRAM`
- `#pragma vertex / fragment / target / multi_compile / shader_feature`
- pass state DSL
2. 生成 `ShaderIR`
3. 支持 include 依赖收集
4. 保留 legacy importer
完成标准:
- authoring parser 单测齐全
- 可以把一个 Unity 风格 shader 解析成稳定 IR
### Phase C建立单一 HLSL 编译链
目标:
- 打通 `HLSL -> D3D12/Vulkan/OpenGL` 编译管线
工作项:
1. 接入 DXC 编译 HLSL。
2. Vulkan 产出 SPIR-V。
3. OpenGL 产出 GLSL 430。
4. 建立 reflection 数据抽取:
- cbuffer
- texture
- sampler
- entry point
- keywords
5. 缓存编译产物与依赖 hash。
完成标准:
- 一份 HLSL authoring 能生成三后端产物
- OpenGL 不再依赖手写 `.glsl` 作为新体系长期主路径
### Phase DMaterial 与 property/keyword/runtime binding 正式化
目标:
- material 能正式驱动新 shader artifact
工作项:
1. 引入正式 property layout。
2. 引入 material keyword set。
3. 生成 `PerMaterial` 常量缓冲布局。
4. texture/sampler 绑定从 reflection/约定生成。
5. 让 material 运行时不再关心 `set/binding`
完成标准:
- material property / texture / keyword 真正接入 GPU 绑定链
### Phase Erenderer pass 选择与 pipeline cache 收口
目标:
- renderer 完全按 pass contract 驱动 shader
工作项:
1.`LightMode` 选 pass。
2. `shaderPass` 降级为 legacy fallback。
3. pipeline cache key 引入:
- shader artifact id
- pass id
- keyword variant id
- render state
4. builtin pass 的 runtime contract 全部切到新 artifact。
完成标准:
- renderer 主路径不再依赖 material 显式 pass 指定
### Phase F分批迁移 builtin shader
建议迁移顺序:
1. `unlit`
2. `forward-lit`
3. `depth-only`
4. `shadow-caster`
5. `object-id`
6. `skybox`
7. `color-scale-post-process`
8. `final-color`
完成标准:
- builtin shader 全部有新 authoring 版本
- 旧版 backend 分发文件不再是长期主定义来源
### Phase G文档、测试、旧路径收口
目标:
- 让新旧体系的边界最终收口
工作项:
1. 更新 `tests/TEST_SPEC.md` 中 shader/material 测试矩阵。
2. 增加 authoring parser / compiler / runtime 回归测试。
3. 更新开发文档。
4. 标记 legacy 路径弃用阶段。
完成标准:
- 新体系文档、测试、builtin 迁移都完成
---
## 13. 测试策略
### 13.1 Parser / Importer 单测
必须覆盖:
- Properties 解析
- SubShader / Pass / Tags 解析
- HLSLINCLUDE / HLSLPROGRAM 解析
- pragma 解析
- pass state 解析
- include 依赖收集
- legacy / 新 authoring 双路径兼容
### 13.2 Compiler 单测
必须覆盖:
- 单一 HLSL 源能生成三后端产物
- reflection 结果稳定
- keyword variant 正确展开
- 编译错误日志可读、可定位到 authoring 源文件
### 13.3 Material 单测
必须覆盖:
- property 默认值
- property override
- texture binding
- keyword set
- 常量缓冲布局打包
### 13.4 Rendering 单测
必须覆盖:
- renderer 按 `LightMode` 选 pass
- legacy `shaderPass` fallback 行为
- keyword variant 参与 pipeline cache key
- final color / post-process / shadow / object-id 不回退
### 13.5 集成测试
至少回归:
- `material_state_scene`
- `transparent_material_scene`
- `camera_stack_scene`
- `directional_shadow_scene`
- `multi_light_scene`
- `skybox_scene`
- `post_process_scene`
- `final_color_scene`
- `object_id_scene`
要求:
- 三后端全部跑通
- GT 不回退
---
## 14. 风险与控制策略
### 风险 1OpenGL 是统一写法最难的一环
原因:
- OpenGL 当前直接吃 GLSL
- 统一 authoring 要求它改为编译链生成目标 GLSL
控制策略:
- 先把 importer/IR 做好
- OpenGL 先走“生成 GLSL 文本产物”路径
- legacy OpenGL GLSL 文件在迁移期保留 fallback
### 风险 2一次性追 full Unity 语法会把阶段拖爆
控制策略:
- 明确 first-class 子集
- 先做 SRP 真正依赖的 authoring 基础
- 非关键语法延后
### 风险 3material / pass 迁移会破坏当前 builtin renderer
控制策略:
- legacy runtime path 保留一段时间
- builtin shader 分批迁移
- 每迁移一个 shader 就跑对应 integration
### 风险 4编译错误如果不可读会极大拖慢落地
控制策略:
- 必须做 authoring 源到 backend 编译日志的映射
- 错误日志要带 shader 名、pass 名、stage、backend、源文件行号
---
## 15. 收口判定
满足下面条件时,本阶段可视为完成:
1.`.shader` authoring 采用 Unity 风格子集。
2. 新体系 shader authoring 中不再出现 `#pragma backend`
3. 新体系 shader authoring 中不再出现 `Resources(set,binding)`
4. HLSL single-source 能生成 D3D12 / Vulkan / OpenGL 三后端产物。
5. material 已正式接入 property / keyword / texture binding runtime。
6. renderer 按 `LightMode` 正式选择 pass。
7. `shaderPass` 只剩 legacy fallback不再是主路径。
8. builtin shader 已完成新体系迁移。
9. 三后端关键集成测试全部通过。
---
## 16. 与后续 SRP 的承接关系
这一阶段完成后,才能真正自然地承接:
- `RenderPipelineAsset`
- `RenderPipeline`
- `RendererFeature`
- `ScriptableRenderPass`
- C# 层对 shader/material/keyword 的控制
承接关系应当是:
```text
Unity-style Shader Authoring
-> Shader Importer / IR / Artifact
-> Native Material & Pass Runtime
-> Native Renderer Pass Contract
-> C# SRP / RendererFeature
```
也就是说:
- 这一阶段不是 SRP
- 但这是 SRP 成立前必须先做完的最后一层底座
---
## 17. 一句话总结
当前 shader 体系不是没有,而是还停在“过渡态”。
下一阶段的正确方向不是继续堆更多 shader 功能,而是:
- **把 `.shader` 的 authoring 真正统一成 Unity 风格**
- **把 backend 差异与 binding 细节收回 importer / compiler 层**
- **把 material / pass / variant/runtime contract 一次性做正式**
只有这样,后面的 SRP 才不会建立在一层伪统一的 shader 体系上。

View File

@@ -0,0 +1,462 @@
# Renderer 下一阶段:方向光阴影与光照闭环计划
日期:`2026-04-04`
## 1. 阶段背景
当前 `shader / material / rendering` 主线已经完成了这一阶段应有的基础闭环:
- `Shader` 已具备 `properties / passes / resources / backend variants` 运行时契约
- `Material` 已具备 schema 驱动的属性、纹理、常量布局与 pass resource binding plan
- `SceneRenderer / CameraRenderer / BuiltinForwardPipeline` 已经打通
- `ObjectId / DepthOnly / ShadowCaster` 已具备独立 pass 与 request 骨架
- 三后端 `D3D12 / OpenGL / Vulkan` 的当前渲染集成测试已全绿
但这仍然只是“能稳定出图的基础 forward renderer”还不是“能承担引擎默认场景渲染”的完整运行时。
下一阶段不应该优先做 `render graph`,也不应该先追求更复杂的编辑器功能,而应该把当前 renderer 推进成一个真正可用的默认前向渲染器。
这一阶段的主线目标只有一句话:
**把当前 renderer 从“无阴影的基础出图器”推进到“具备方向光、阴影、基础多光源闭环,并可稳定承接 Scene/Game 视图”的运行时渲染器。**
## 2. 为什么下一步是这个
当前代码结构已经说明了下一阶段的最短主路径:
- `RenderSceneExtractor` 里已经有 `RenderLightingData.mainDirectionalLight`
- `BuiltinForwardPipeline` 已经在 per-object constants 中消费主方向光方向和颜色
- `CameraRenderRequest` 已经有 `shadowCaster / depthOnly / objectId` request
- `BuiltinShadowCasterPass / BuiltinDepthOnlyPass` 已经存在
也就是说:
1. 光照数据通路已经有最小入口
2. 阴影 pass 的执行骨架已经有了
3. 缺的是把这些骨架真正接成 frame 级闭环
如果这时跳去做 `render graph`,只会把尚未收紧的运行时逻辑包上一层更复杂的调度壳。
如果这时去做更复杂的 editor 特效也是在建立在“runtime lighting 还不完整”的地基上。
所以本阶段应当严格沿着 Unity 风格的自然演进路径推进:
1. 先把默认前向运行时补完整
2. 再谈更高层调度与优化
## 3. 与 Unity 式架构的对齐原则
本阶段继续遵循现有总设计,不偏离 `RHI -> Renderer -> Editor/Runtime` 这条主分层:
- `RHI` 只负责统一 GPU 抽象,不承载场景渲染逻辑
- `Renderer` 负责场景提取、光照数据组织、shadow/depth/object-id/forward 等 pass 执行
- `Editor` 只是 renderer 的宿主与附加 overlay/pass 使用方,不拥有独立的一套 runtime 渲染逻辑
与 Unity 对齐时,要注意以下边界:
- 阴影图、主光照、相机渲染请求,这些属于 runtime renderer 的正式能力
- grid、outline、gizmo、icon这些属于 editor 专属叠加能力
- editor 需要复用 renderer但不能反向污染 runtime 主链
因此这一阶段做的方向光阴影、基础多光源、GameView/SceneView 统一接入,都是正式主线。
`GPU picking`、editor outline、gizmo 美术化这些,都不应抢主线优先级。
## 4. 当前真实现状
从当前代码看renderer 已具备但尚未闭环的点如下。
### 4.1 已经具备的能力
- `SceneRenderer` 已支持多 camera request、camera stack、surface render area
- `CameraRenderer` 已支持 `pre -> shadowCaster -> depthOnly -> main pipeline -> objectId -> post`
- `BuiltinForwardPipeline` 已支持 `ForwardLit / Unlit` 的统一 shader/material contract
- `BuiltinObjectIdPass` 已正式接入 object-id 渲染路径
- `BuiltinDepthOnlyPass / BuiltinShadowCasterPass` 已经具备 pass 级执行能力
- `RenderSceneExtractor` 已能提取主方向光
### 4.2 尚未闭环的能力
- 阴影图尚未由 `SceneRenderer/CameraRenderer` 正式规划、分配、执行与回收
- forward 主通道尚未消费 shadow map 结果
- 光照仍停留在“单主方向光最小数据”,没有正式多光源提交模型
- shadow request 目前更像通用 hook而不是 renderer 自动生成的正式帧请求
- 缺少以“阴影正确性”为目标的正式集成测试场景
- 缺少以“多光源正确性”为目标的正式集成测试场景
### 4.3 这意味着什么
当前 renderer 的问题已经不再是“架构没有”,而是:
**架构有了,但 runtime lighting/shadow 这条主业务链尚未贯通。**
## 5. 本阶段总体目标
本阶段拆成四个连续目标:
1. 建立正式的方向光阴影闭环
2. 建立正式的前向多光源数据通路
3. 统一 SceneView / GameView 对 runtime renderer 的使用方式
4. 为下一阶段的 post-process 与 renderer 扩展收紧边界
其中优先级严格如下:
1. `Directional Light + Shadow Map`
2. `Forward 多光源`
3. `Scene/Game 视图统一使用正式 renderer 能力`
4. `补文档、补测试、清理旧临时路径`
## 6. 分阶段实施计划
## 6.1 Phase A方向光阴影闭环
### 目标
让场景中的主方向光真正生成 shadow map并在主 forward pass 中被采样,形成跨三后端稳定一致的阴影结果。
### 具体工作
#### A1. 正式定义 shadow frame 数据模型
新增或收紧 renderer 内部数据结构,至少明确:
- 主方向光是否需要阴影
- shadow map 尺寸与格式
- light-space view/projection 矩阵
- shadow caster 渲染 surface
- forward receiver 采样所需的阴影参数
这里的目标不是先做复杂 cascades而是先做单张 directional shadow map MVP。
#### A2. 由 renderer 自动生成 shadow caster request
不能继续依赖测试或上层调用者手工拼 `shadowCaster` request。
应由 `SceneRenderer``CameraRenderer` 在主 camera 渲染前自动生成:
- 主方向光对应的 shadow camera data
- shadow surface
- clear flags
- shadow pass 执行顺序
也就是说,要把“有 shadow pass 骨架”提升成“runtime renderer 正式调度 shadow pass”。
#### A3. 收紧 `BuiltinShadowCasterPass`
确认并补齐以下行为:
- 只渲染 `castShadows = true` 的可见物体
- 正确处理 section/material pass 选择
- 只依赖 shadow caster 所需最小资源
- 在三后端下都使用统一的深度输出语义
#### A4. 在 `BuiltinForwardPipeline` 中消费 shadow map
forward pass 至少补齐:
- shadow map SRV 绑定
- light-space position 计算
- shadow compare
- 基础 bias
- 基础 PCF 或最小稳定采样
这一阶段不追求高级阴影质量,但必须追求:
- 没有明显自阴影灾难
- 没有跨后端严重不一致
- 测试图可稳定固化 GT
#### A5. 增加阴影集成测试
新增至少一个正式场景:
- `tests/Rendering/integration/directional_shadow_scene`
场景要求:
- 至少包含一盏方向光
- 至少包含一个会投影的物体
- 至少包含一个接收阴影的地面或大平面
- 阴影边界、方向、遮挡关系都足够稳定,适合 GT 比对
### 验收标准
- 三后端都能稳定生成方向光阴影
- forward pass 正式消费 shadow map
- `directional_shadow_scene` 三后端 GT 全绿
- 不破坏现有全部 rendering integration
## 6.2 Phase B前向多光源闭环
### 目标
把当前只支持主方向光的 lighting 数据模型,推进为可正式承接多个灯光的前向运行时。
### 具体工作
#### B1. 扩展 `RenderLightingData`
从当前的:
- `mainDirectionalLight`
扩展到至少可描述:
- `main directional light`
- `additional directional lights`
- `point lights`
- `spot lights`
注意这里不一定一步到位做完整 Unity 灯光体系,但要保证数据模型不会很快被推翻。
#### B2. 明确本阶段多光源策略
当前阶段建议使用:
- 单主方向光
- 有上限的 additional lights
- CPU 侧整理一份稳定 light list
- GPU 侧通过常量缓冲或结构化数据提交
本阶段**不做**
- clustered lighting
- tiled lighting
- deferred lighting
这是为了保证先把可验证的前向路径收紧。
#### B3. 扩展 forward shader/material contract
补齐多光源所需的 shader 输入:
- additional light count
- light position / direction / color / range / spot angle
- shadowed main light 与 non-shadowed additional lights 的职责边界
要求仍沿用当前的 shader/material/pass contract不要回退成硬编码散乱常量。
#### B4. 新增多光源集成测试
新增至少两个场景:
- `multi_light_scene`
- `spot_light_scene`
场景目标:
- 验证 point/spot 的衰减与照明范围
- 验证 additional lights 会真实影响画面
- 验证三后端输出保持一致
### 验收标准
- `RenderSceneExtractor` 能提取正式多光源数据
- `BuiltinForwardPipeline` 能消费多光源
- 新增多光源场景三后端 GT 全绿
- 方向光阴影能力不被破坏
## 6.3 Phase CSceneView / GameView runtime 接入收紧
### 目标
让 editor 的场景与游戏视图都建立在同一套 runtime renderer 能力上,而不是继续沿着临时 editor 路径分叉。
### 具体工作
#### C1. 明确 runtime pass 与 editor overlay pass 的边界
正式定义:
- runtime 正式 passshadow caster、depth only、forward、object-id、offscreen copy 等
- editor 附加 passgrid、outline、icon、gizmo 等
要求:
- runtime pass 可脱离 editor 独立工作
- editor pass 只能叠加,不能挟持 runtime 主流程
#### C2. GameView 走正式相机渲染请求
GameView 必须通过标准 `CameraRenderRequest` 驱动 renderer不能再依赖 editor 特殊逻辑直接拼接。
#### C3. SceneView 继续复用 renderer
SceneView 应:
- 复用正式相机渲染链
- 在其上叠加 editor overlay
- 允许 object-id / outline / grid 等继续作为 editor 增量能力存在
### 验收标准
- SceneView 与 GameView 都走正式 renderer 主链
- editor 专属 overlay 不污染 runtime pass
- 不出现“editor 正常、runtime 不正常”或反之的分叉
## 6.4 Phase D收口与稳定性整理
### 目标
在新能力落地后,把这一阶段的测试、文档、边界彻底收紧。
### 具体工作
#### D1. 补齐测试矩阵
至少确保以下持续可跑:
- `shader_tests`
- `material_tests`
- `mesh_tests`
- `rendering_unit_tests`
- 全部 `tests/Rendering/integration`
新增场景至少包括:
- `directional_shadow_scene`
- `multi_light_scene`
- `spot_light_scene`
#### D2. 清理临时路径
逐项检查并收紧:
- 是否仍有测试手工拼 shadow request
- 是否仍有 runtime/editor 职责混用
- 是否仍有与 shader/material contract 相冲突的旧 lighting 常量路径
#### D3. 文档归档
这一阶段结束后,应补一份阶段收口说明,并把过期计划归档到 `docs/plan/used/`
### 验收标准
- 阴影、多光源、Scene/Game 接入均通过测试
- 当前计划中的临时方案被收紧到清晰边界内
- 下一阶段可以自然承接 skybox/post-process而不是继续补地基
## 7. 测试策略
这一阶段的测试必须比前一阶段更严格,因为它开始影响真正的场景表现。
### 7.1 单元测试
重点补以下测试:
- `RenderSceneExtractor` 的多光源提取
- shadow request 自动生成逻辑
- shadow matrix / light camera 参数构建
- forward shader resource binding 对 shadow map 的消费
- additional lights 排序与裁剪规则
### 7.2 集成测试
必须新增:
- `directional_shadow_scene`
- `multi_light_scene`
- `spot_light_scene`
保底回归集:
- `textured_quad_scene`
- `unlit_scene`
- `object_id_scene`
- `backpack_scene`
- `backpack_lit_scene`
- `camera_stack_scene`
- `transparent_material_scene`
- `cull_material_scene`
- `depth_sort_scene`
- `material_state_scene`
- `offscreen_scene`
### 7.3 三后端要求
本阶段所有新增集成测试都必须同时覆盖:
- `D3D12`
- `OpenGL`
- `Vulkan`
如果某一步只在单后端通过,不算完成。
这一阶段绝不接受“先在一个后端跑通,另外两个后面再补”的收口标准。
## 8. 明确不做
为了避免主线失控,这一阶段明确不做下面这些:
- `render graph`
- `deferred renderer`
- `clustered/tiled lighting`
- `cascaded shadow maps`
- `PCSS / VSM / EVSM` 等高级阴影方案
- `post-process` 大框架
- `shader graph`
- editor gizmo 的进一步美术化与交互打磨
这些都应该建立在“方向光阴影 + 基础多光源 + runtime renderer 稳定闭环”完成之后。
## 9. 风险点与处理策略
### 9.1 风险:阴影路径把 pass/resource contract 搞散
处理策略:
- 阴影采样与 shadow caster 仍必须走正式 shader/material/pass contract
- 不允许为了赶进度,在 pipeline 内重新堆一套散乱硬编码绑定
### 9.2 风险editor 需求重新污染 runtime 主线
处理策略:
- SceneView 只复用 renderer
- grid/outline/gizmo 始终作为 editor overlay
- runtime 主链以 GameView/真实场景渲染为准
### 9.3 风险:三后端阴影精度差异导致 GT 不稳定
处理策略:
- 第一版 shadow scene 场景构图应保守
- 阈值控制应严格,但允许合理的小误差
- 优先追求稳定一致,而不是追求复杂阴影表现
### 9.4 风险:多光源一步做太大
处理策略:
- 先做“有限 additional lights 的前向提交”
- 不提前引入 forward+ 或 deferred
- 以可验证场景为主,不以理论最优为目标
## 10. 提交与执行节奏
这一阶段继续按“每一步可验证、每一步可提交”的节奏推进:
1. 先做 `Phase A` 的数据模型与 shadow request 自动生成
2. 测试通过后提交
3. 再做 `ShadowCaster -> Forward` 的 shadow map 消费
4. 测试通过后提交
5. 再做 `Phase B` 的多光源数据模型与 shader 消费
6. 测试通过后提交
7. 最后做 `Phase C / D` 的接入收口与文档归档
每一步的“通过”都必须包含:
- 至少相关 unit tests 通过
- 至少相关 integration tests 通过
- 如影响主线,必须补跑 rendering regression
## 11. 成功标准
本阶段完成时,应满足以下判断:
- renderer 能正式生成并消费方向光阴影
- renderer 能正式消费基础多光源
- SceneView 与 GameView 都建立在统一 runtime renderer 主链上
- editor overlay 与 runtime pass 边界清晰
- rendering 测试体系在三后端下持续稳定
## 12. 一句话总结
下一阶段的核心不是“做更多花哨渲染功能”,而是:
**把当前已经具备架构基础的 renderer推进成一个真正能承担默认场景渲染的 Unity 风格前向运行时。**

View File

@@ -0,0 +1,556 @@
# Renderer模块设计与实现
## 1. 背景
XCEngine 当前已经完成了较为可用的 RHI 抽象层,且已经具备:
- `Scene + GameObject + Component` 基础场景模型
- `CameraComponent` / `LightComponent` 等基础组件
- `Mesh` / `Material` / `Texture` / `Shader` 等资源类型
- D3D12 / OpenGL 双后端 RHI 抽象与测试体系
下一阶段不应该继续封闭式打磨 RHI而应该在 RHI 之上正式建立 **Renderer 模块**
这里的 Renderer 模块不是“最终形态的 SRP”而是
- 先建立一层 **原生渲染运行时**
- 先让场景对象能够以正式渲染链路被绘制
- 同时在设计上预留未来 **C# Scriptable Render PipelineSRP** 的接入点
也就是说,当前阶段的正确目标不是直接实现 Unity 的 URP/HDRP而是先建立一套 **与 Unity 渲染架构方向一致的原生基础层**,后续让 C# SRP 驱动它。
---
## 2. 设计目标
Renderer 模块的目标分为两层:
### 2.1 当前阶段目标
先完成一套最小但完整的原生渲染链路:
-`Scene` 中提取可渲染对象
- 通过 `Camera` 构建视图与投影数据
- 通过 `Material` / `Mesh` / `Texture` 构建 GPU 绘制数据
- 在 RHI 之上完成正式的 frame 渲染
- 支持 swapchain 输出与离屏输出
- 建立独立于 editor 的渲染宿主模型
### 2.2 面向未来 C# SRP 的目标
当前阶段的实现必须为后续演进预留稳定边界:
- 未来允许用 C# 定义 `RenderPipelineAsset` / `RenderPipeline`
- 未来允许用 C# 组织 render pass
- 未来允许 editor `SceneView` / `GameView` 通过同一套 renderer 输出
- 未来允许 C# 脚本控制 camera 渲染、pass 排序、目标输出与 command buffer
因此,当前阶段的原生 Renderer 不能做成一个写死的“大一统内建渲染函数”,而应该一开始就具备“可被上层 pipeline 驱动”的结构。
---
## 3. 与 Unity 渲染架构的对应关系
当前建议的路线与 Unity 的总体方向是对齐的,但要注意分层位置。
### 3.1 推荐分层
```text
Scene / Components / Resources
Renderer 模块(原生渲染运行时)
未来 C# SRP 层(脚本化渲染管线)
RHI 抽象层
D3D12 / OpenGL / Vulkan 后端
```
### 3.2 各层职责
#### Scene / Components / Resources
负责描述“要渲染什么”,例如:
- 场景对象
- 相机
- 灯光
- 网格
- 材质
- 贴图
这一层不应该直接持有后端 API 对象。
#### Renderer 模块(本阶段核心)
负责描述“如何从场景变成 draw call”例如
- 渲染对象抽取
- 可见性裁剪
- GPU 资源缓存
- camera frame 数据组织
- render target / depth target 管理
- render pass 调度
- 内建前向管线
这一层是未来 C# SRP 的原生支撑层。
#### 未来 C# SRP 层
负责描述“以脚本方式控制渲染流程”,例如:
- `RenderPipelineAsset`
- `RenderPipeline`
- `ScriptableRenderContext`
- `CommandBuffer`
- `RenderPassEvent`
- pass 注入与重排
这一层不应该直接绕过 Renderer 模块去操作后端 API。
#### RHI 抽象层
负责统一 GPU 接口与资源对象,是渲染系统的执行后端,而不是场景渲染逻辑本身。
### 3.3 与 Unity 的概念映射
| Unity 概念 | XCEngine 当前/规划对应 |
|---|---|
| `Camera` | `CameraComponent` |
| `Light` | `LightComponent` |
| `MeshFilter` | 计划新增 `MeshFilterComponent` |
| `MeshRenderer` | 计划新增 `MeshRendererComponent` |
| `RenderPipelineAsset` | 未来 Renderer 模块上的 pipeline asset 抽象 |
| `RenderPipeline` | 未来 Renderer 模块上的 pipeline 实例抽象 |
| `ScriptableRenderContext` | 未来 Renderer 模块对脚本暴露的原生 render context |
| `CommandBuffer` | 未来 Renderer 模块对脚本暴露的命令缓冲抽象 |
| `GraphicsDevice` / native render backend | 当前 RHI + 后端实现 |
结论是:
- **方向上符合 Unity 渲染架构**
- **当前阶段实现的应是 Unity 渲染体系中的原生底座**
- **而不是直接跳到最终的脚本化 SRP**
---
## 4. 核心设计原则
### 4.1 先建立原生渲染运行时,再开放脚本化管线
如果现在直接做 C# SRP而原生 Renderer 边界还不存在,后续会出现:
- C# API 直接耦合 RHI
- editor viewport 与 runtime camera 逻辑混杂
- 资源对象与 GPU 对象生命周期混乱
因此必须先收敛原生 Renderer 模块。
### 4.2 Scene 层只描述逻辑对象,不持有后端对象
`GameObject``Component``Mesh``Material` 等对象只能描述逻辑与资源,不应该直接持有 D3D12/OpenGL 私有对象。
GPU 对象应由 Renderer 内部缓存层负责创建和复用。
### 4.3 editor 只是渲染宿主,不是渲染逻辑本体
`GameView` / `SceneView` 最终只是 Renderer 的输出宿主。
Renderer 本身必须先支持:
- 输出到 swapchain
- 输出到离屏纹理
然后 editor 再把离屏纹理接进 ImGui 面板。
### 4.4 为未来 SRP 预留 pipeline 抽象
即使第一阶段先做内建前向渲染,也不应该把逻辑写死成单一 `SceneRenderer::DrawEverything()`
应该从一开始就保留:
- `RenderPipeline`
- `RenderPipelineAsset`
- `RenderContext`
- camera 列表驱动
- pass 分阶段执行
这样未来 C# 只是在这个原生结构上做绑定,而不是重做一遍架构。
### 4.5 测试体系与渲染层分离
`tests/RHI/` 继续只验证 RHI。
Renderer 模块应建立自己的测试体系:
- `tests/Rendering/unit/`
- `tests/Rendering/integration/`
这样职责边界才清晰。
---
## 5. 模块划分建议
建议新增 `Rendering` 模块,作为场景与 RHI 之间的正式中间层。
### 5.1 推荐目录结构
```text
engine/
├── include/XCEngine/Rendering/
│ ├── RenderSurface.h
│ ├── RenderContext.h
│ ├── RenderPipeline.h
│ ├── RenderPipelineAsset.h
│ ├── SceneRenderer.h
│ ├── RenderSceneExtractor.h
│ ├── RenderCameraData.h
│ ├── VisibleRenderObject.h
│ ├── RenderResourceCache.h
│ └── Pipelines/
│ └── BuiltinForwardPipeline.h
└── src/Rendering/
├── RenderSurface.cpp
├── SceneRenderer.cpp
├── RenderSceneExtractor.cpp
├── RenderResourceCache.cpp
└── Pipelines/
└── BuiltinForwardPipeline.cpp
```
### 5.2 组件层建议
为了尽可能对齐 Unity而不是做一个临时过渡方案建议直接采用
- `MeshFilterComponent`
- `MeshRendererComponent`
其中:
#### `MeshFilterComponent`
负责“这个对象使用哪一个 mesh”
- `ResourceHandle<Mesh>`
#### `MeshRendererComponent`
负责“这个对象如何被渲染”:
- 材质数组
- cast shadow / receive shadow
- render queue / layer / enable 状态
- 未来可扩展 light probe / motion vector / static batching 标记
这样做的好处是:
- 更贴近 Unity 的对象模型
- 更容易映射未来 C# API
- 更容易在 editor Inspector 中呈现
- 更容易为 `SkinnedMeshRenderer``SpriteRenderer` 等后续组件扩展留位置
### 5.3 Renderer 内部运行时对象
#### `RenderSurface`
统一表示渲染输出目标:
- 交换链输出
- 离屏 color/depth 输出
- editor viewport 输出
#### `RenderSceneExtractor`
负责从 `Scene` 中提取本帧可渲染对象:
- mesh
- material
- transform
- bounds
- render state
#### `RenderResourceCache`
负责把资源模块对象转成 GPU 可用对象:
- mesh -> vertex/index buffer
- texture -> RHI texture / resource view
- material -> descriptor set / uniform buffer / pipeline key
- shader pass -> pipeline state
#### `RenderContext`
作为原生渲染执行上下文,未来用于承接脚本化 pipeline 的调度。
它应封装:
- 当前 frame 的 command list
- render target 设置
- clear / draw / submit
- camera 相关渲染上下文
#### `RenderPipeline`
用于抽象具体渲染流程。
第一阶段只有一个原生内建实现:
- `BuiltinForwardPipeline`
未来再开放:
- native 可切换 pipeline
- C# 绑定的 scriptable pipeline
---
## 6. 第一阶段实现边界
第一阶段只做最小可用链路,不做“大而全”。
### 6.1 第一阶段要做
- `Rendering` 模块骨架
- `MeshFilterComponent` / `MeshRendererComponent`
- `RenderSurface`
- `RenderSceneExtractor`
- `RenderResourceCache`
- `SceneRenderer`
- `BuiltinForwardPipeline`
- 单 camera
- 单方向的 opaque forward 渲染
- 深度测试与深度写入
- 交换链输出
- 离屏输出
### 6.2 第一阶段先不做
- 阴影
- 后处理
- 延迟渲染
- 完整 PBR
- render graph
- C# SRP 真正落地
- editor viewport 完整交互
- 多 camera 叠加
### 6.3 第一阶段材质能力建议
建议先支持两档:
1. `UnlitTexture`
2. `SimpleLit`
其中:
- `UnlitTexture` 用于先打通最小链路
- `SimpleLit` 用于验证灯光、法线与材质基础通路
---
## 7. 面向未来 C# SRP 的预留设计
虽然第一阶段先做原生内建渲染,但必须提前约束下面这些方向。
### 7.1 先定义 pipeline 边界,再定义内建实现
正确顺序应当是:
1. 先定义 `RenderPipeline` 抽象
2. 再实现 `BuiltinForwardPipeline`
3. 后续 C# SRP 只是在这个边界上做脚本绑定
而不是:
1. 先写死一个 `SceneRenderer`
2. 以后再强行拆成 pipeline
第二种方式后续返工会很大。
### 7.2 Renderer 模块应向未来脚本层暴露的概念
当前阶段不一定全部实现,但结构上要留位置:
- `RenderPipelineAsset`
- `RenderPipeline`
- `RenderContext`
- `CullingResults`
- `DrawingSettings`
- `FilteringSettings`
- `ShaderTag`
- `CommandBuffer`
- `RendererList`
这些概念不一定要立刻与 Unity 一字不差,但应该在职责上能对应上。
### 7.3 材质与 Shader 资产模型不能停留在“单 shader 文件 + 属性包”
未来做 SRP 时shader pass 选择、render queue、tag、render state 都是必要能力。
因此当前阶段即使先不全量实现,也不能把资产模型彻底锁死在过于简单的结构上。
这一点单独列为 issue。
---
## 8. 分阶段推进建议
### 阶段 ARenderer v0 骨架
目标:
- 建立 `Rendering` 模块
- 建立 `MeshFilterComponent` / `MeshRendererComponent`
- 建立 `RenderSurface`
- 建立 `BuiltinForwardPipeline`
验收:
- 可以通过 Renderer 正式绘制一个 textured quad 场景
- 输出到 swapchain
- 输出到离屏 RT
### 阶段 B真实资源场景接入
目标:
- 接入 mesh / texture / material 资源模块
- 跑通 `backpack` 这样的真实模型场景
验收:
- 真实 obj 资源经资源模块导入后可通过 Renderer 正式绘制
- D3D12 / OpenGL 双后端结果一致
### 阶段 C基础光照
目标:
- 接入 `LightComponent`
- 跑通最基础的单方向光前向渲染
验收:
- `sphere` / `backpack` 存在正确基础明暗
- 材质参数与法线链路可验证
### 阶段 Dpipeline 抽象显式化
目标:
- 把内建前向渲染切到 `RenderPipeline` 抽象之下
- 支持 camera 列表驱动
- 为未来 C# SRP 绑定准备原生接口
验收:
- 原生内建 pipeline 通过统一接口驱动
- renderer 不再依赖单一路径写死执行
### 阶段 Eeditor viewport 接入
目标:
- `SceneView` / `GameView` 使用 Renderer 的离屏输出
验收:
- editor 面板只是渲染宿主
- 不额外复制一套渲染逻辑
### 阶段 FC# SRP 桥接
目标:
- 在既有 Renderer 模块基础上绑定脚本化 pipeline
验收:
- C# 可以控制 camera 渲染流程
- 原生 Renderer 继续负责底层资源、上下文与执行
---
## 9. 测试体系建议
Renderer 模块需要独立测试体系。
### 9.1 单元测试
建议放在:
- `tests/Rendering/unit/`
测试内容:
- render object 抽取
- material 参数打包
- pipeline key 构建
- GPU cache 命中与失效
- render surface 创建与 resize
### 9.2 集成测试
建议放在:
- `tests/Rendering/integration/`
建议场景:
1. `textured_quad_scene`
2. `backpack_scene`
3. `lit_sphere_scene`
仍然维持当前 RHI 抽象测试的好习惯:
- 一场景一张 `GT.ppm`
- D3D12 / OpenGL 都与同一张 GT 比对
### 9.3 与 RHI 测试的关系
`tests/RHI/` 继续用于验证:
- API 抽象正确性
- 后端行为一致性
- 资源 / 命令 /格式映射等底层问题
`tests/Rendering/` 则验证:
- 场景渲染链路
- 组件与资源到渲染结果的闭环
---
## 10. 当前已识别的不适配问题
以下问题不适合直接塞进本设计文档正文实现里,而应该独立跟踪:
1. `Scene / Components` 层还没有 `MeshFilter / MeshRenderer` 抽象
2. `Editor` 还没有 viewport 的离屏渲染宿主接入层
3. `Material / Shader` 资产模型还不足以支撑未来 SRP 的 pass/tag 语义
对应 issue
- `docs/issues/Renderer模块_Scene层缺少MeshFilter与MeshRenderer抽象.md`
- `docs/issues/Renderer模块_EditorViewport缺少RenderSurface接入层.md`
- `docs/issues/Renderer模块_Material与Shader资产模型暂不满足SRP演进需求.md`
---
## 11. 结论
当前 Renderer 阶段的正确方向是:
- 在 RHI 之上建立 **原生渲染运行时**
- 用它先承接基础前向渲染
- 同时提前为未来 **C# SRP** 留出清晰接口
因此,下一阶段的 Renderer 规划如果按本文执行,是与 Unity 渲染架构方向相容的,而且比“先做一个临时内建 renderer后面再拆”更稳。
一句话概括:
- **现在做的是 Unity 式渲染体系的原生底座**
- **以后在这个底座之上接 C# SRP**

View File

@@ -0,0 +1,415 @@
# Renderer 结构收口与代码正式化计划
日期:`2026-04-05`
## 1. 阶段定位
当前 Rendering 主线在功能上已经完成了相当多闭环:
- 三后端统一的 runtime renderer 主链已经建立
- directional shadow、multi-light、object-id、editor overlay 等能力都已接入
- SceneView / GameView 基本共用了同一条 runtime 渲染路径
但从代码结构和职责边界上看,这一阶段还没有真正收口。现在的问题已经不再是“某个功能没接上”,而是:
**renderer 的核心模块里仍然混有明显的阶段性写法、特殊分支、职责堆叠和 editor/runtime 边界不清的问题。**
如果此时直接继续往上叠 skybox、环境、后处理、更多 renderer feature后面会越来越难拆最终重新把已经相对稳定的 renderer 主链拖回到“能跑但很难维护”的状态。
因此,本阶段的唯一目标不是加新功能,而是:
**把当前 renderer 这一阶段真正做成可持续演进的正式结构,为后续 Skybox / Environment / PostProcess / 更正式的 SRP 承接清掉结构债。**
## 2. 为什么现在必须先做结构收口
这不是“目录看着乱一点”的表面问题,而是已经影响后续演进的实质性架构问题。
### 2.1 `CameraRenderer` 仍然存在特殊通道
当前 `CameraRenderer` 虽然已经具备请求规划与多阶段执行能力,但 `object-id` 仍然是单独的一套特殊路径,而不是正式 frame composition 里的统一 pass 节点。
这带来的问题:
- 相机级执行顺序不是单一模型,而是“主链 + 特判”
- 后续 skybox / post-process / capture / debug target 更难正规接入
- 单元测试里被迫维护特殊 mock pass 类型,而不是统一的 pass contract
关键文件:
- `engine/include/XCEngine/Rendering/ObjectIdPass.h`
- `engine/include/XCEngine/Rendering/CameraRenderer.h`
- `engine/include/XCEngine/Rendering/CameraRenderRequest.h`
- `engine/src/Rendering/CameraRenderer.cpp`
### 2.2 `BuiltinForwardPipeline.cpp` 已经是典型 god file
这个文件里当前同时混着:
- pass wrapper
- shader pass resolve
- graphics pipeline 创建
- descriptor set layout 规划
- descriptor set 资源写入
- lighting 常量打包
- material fallback
- draw submission
这已经不是“文件有点长”而是职责拆分失败。后续任何修改都会把高层语义、资源绑定、RHI 细节、draw 级逻辑一起牵动,测试也只能做大颗粒回归,无法精准保护。
关键文件:
- `engine/src/Rendering/Pipelines/BuiltinForwardPipeline.cpp`
### 2.3 `RenderMaterialUtility.h` 混合了契约、兼容层和运行时解析
当前这个头里至少混了五类职责:
- builtin pass contract 定义
- shader/property/binding 查询
- descriptor layout 规划
- legacy/material fallback 兼容
- runtime material resolve 与绑定辅助
这会导致:
- “正式 contract” 与 “过渡兼容逻辑” 难以分开演进
- 很多 renderer 代码只能依赖一个超大工具头
- 头文件膨胀,职责不可读,接口边界不清
关键文件:
- `engine/include/XCEngine/Rendering/RenderMaterialUtility.h`
### 2.4 editor / debug pass 仍然混在 runtime renderer 核心层里
grid、outline 这些能力现在已经走到了比较正式的 runtime host path但它们在 engine 里的组织方式仍然更接近“把 editor 需求塞进 renderer 核心”。
风险在于:
- runtime 核心会继续被 editor 语义污染
- 后续 scene/game/editor 三条宿主路径边界会再次变模糊
- 玩家运行时和编辑器专用渲染能力的依赖关系难以长期维护
关键文件:
- `engine/include/XCEngine/Rendering/Passes/BuiltinInfiniteGridPass.h`
- `engine/include/XCEngine/Rendering/Passes/BuiltinObjectIdOutlinePass.h`
### 2.5 文件拆分层次仍然不干净
例如 `BuiltinDepthStylePassBase.cpp` 的底部还直接放着 `BuiltinDepthOnlyPass``BuiltinShadowCasterPass` 具体实现,这说明“抽象基类”和“具体 pass”仍然没有彻底分层。
关键文件:
- `engine/src/Rendering/Passes/BuiltinDepthStylePassBase.cpp`
### 2.6 少量稳定性问题仍然暴露出“临时写法”
比如 scene extractor 里 visible item 的稳定排序仍然用 raw pointer 作为 tie-breaker而 additional light 已经升级成了稳定的 `GameObject::ID` 语义。
这类问题虽然不大,但非常能说明当前代码里仍混有阶段性临时写法,必须顺手清理干净。
关键文件:
- `engine/src/Rendering/RenderSceneExtractor.cpp`
## 3. 本阶段的核心设计原则
本阶段继续严格遵循当前工程既定设计理念,并与 `RHI模块总览` 中的核心原则保持一致:
1. `RHI` 只负责 GPU 抽象,不感知 object-id、grid、outline、skybox、post-process 等高层语义。
2. `Renderer` 负责 scene extraction、frame composition、material/shader contract、runtime pass orchestration。
3. `Editor` 只作为 renderer 的宿主和扩展使用方,不把 editor 语义反向污染 RHI。
4. 兼容层和正式 contract 必须拆开,不能继续把“临时兜底”混在正式主链里。
5. 不引入 `render graph`。本阶段先把现有 renderer 结构做正式化,不跳级优化。
6. 不做“修修补补式”文件搬家,必须同时修职责边界、执行路径和测试结构。
## 4. 阶段总目标
本阶段收口完成后,应达到以下状态:
1. `CameraRenderer` 形成单一、明确、可测试的 frame composition 模型。
2. runtime pass 与 object-id / editor-debug pass 的边界清晰,接入点正式化。
3. `BuiltinForwardPipeline` 不再由一个 god file 承担所有责任。
4. `RenderMaterialUtility` 被拆分为“正式 contract 层”和“兼容/运行时辅助层”。
5. renderer 文件结构与代码结构一致,抽象基类、具体 pass、绑定辅助、compat helper 各归其位。
6. 当前所有 rendering / editor 相关测试继续通过,不破坏已闭环功能。
## 5. 非目标
本阶段明确不做:
- `render graph`
- deferred / clustered / tiled lighting
- 新一轮 editor 视觉特效堆叠
- 大规模 shader authoring 体系重写
- point / spot shadow
- 重新设计 RHI
## 6. 分阶段执行方案
## 6.1 Phase ACamera Frame Composition 正式化
### 目标
消灭 `CameraRenderer` 里 object-id 的特殊执行通道,把相机级执行模型统一成正式 frame composition。
### 要解决的根因
- 现在相机渲染顺序不是单一 contract
- `ObjectIdPass` 是旁路抽象,不利于后续继续扩展 composition
- 测试里存在针对 object-id 的特殊 mock pass 体系
### 具体工作
1. 重新审视 `CameraRenderRequest` 的阶段描述,明确:
- pre-scene
- shadow/depth
- scene pipeline
- auxiliary offscreen passes
- post-scene
- overlay
2. 去掉 `ObjectIdPass` 作为并行特例抽象的地位。
3. 把 object-id 统一纳入正式 pass 执行序列,必要时通过 pass category / target intent 标识语义,而不是再保留独立虚函数族。
4. 简化 `CameraRenderer` 执行逻辑让失败传播、目标准备、pass 顺序只走一套主链。
5. 同步收敛相关单元测试,让测试验证“阶段顺序”和“失败传播”,而不是验证某个特判分支。
### 验收标准
- `CameraRenderer` 不再对 object-id 走特判主逻辑
- `test_camera_scene_renderer` 等单测仍覆盖 object-id 顺序与失败传播
- editor viewport object-id picking 不回退
### 计划提交点
这一阶段完成后立即提交推送一次。
## 6.2 Phase BBuiltinForwardPipeline 职责拆分
### 目标
`BuiltinForwardPipeline.cpp` 从 god file 拆成正式的职责层次,但不改变现有 forward runtime 的对外行为。
### 要解决的根因
- pipeline resolve、resource layout、descriptor write、material resolve、lighting packing、draw submission 全部耦合
- 任何小修改都会波及整个文件
- 难以为 skybox / post-process / future pipeline 承接建立稳定接口
### 具体工作
1. 先按职责切出独立模块,优先拆成以下几层:
- shader/pass resolve
- pipeline cache/build
- resource binding layout / descriptor planning
- frame-scoped lighting / pass constants upload
- draw item submission
2.`BuiltinForwardPipeline` 保留 orchestration 职责,而不是继续承载全部细节。
3. 清理与 `RenderMaterialUtility` 的交叉依赖,为下一阶段拆 contract 做准备。
4. 保证 unlit / lit / object-id / depth-only / shadow-caster 的绑定逻辑不被混淆。
### 验收标准
- `BuiltinForwardPipeline.cpp` 明显缩小,核心职责清晰
- 新拆出的模块命名与职责稳定,不是单纯“工具类化”
- forward 相关单测、集成测试全部不回退
### 计划提交点
这一阶段完成后立即提交推送一次。
## 6.3 Phase CRenderMaterialUtility 正式拆层
### 目标
把 shader/material/pass 的正式 contract 与 legacy/compat/runtime helper 拆开。
### 要解决的根因
- 正式接口和过渡逻辑混在一起
- 任何依赖 `RenderMaterialUtility.h` 的代码都会被迫包含大量不相干能力
- 后续 shader/material 演进会被兼容逻辑长期绑死
### 具体工作
1. 明确拆成三层语义:
- `contract`builtin pass 名称、标准 binding 名称、正式解析规则
- `runtime resolve`:材质/着色器运行时查询、pass 选择、绑定规划
- `compat`legacy property 名称、历史 fallback、过渡适配
2. 避免再把大段实现继续塞在头文件里,能下沉到 `.cpp` 的尽量下沉。
3. 对外只暴露最小且稳定的正式接口。
4. 给 compat 层加清晰边界,避免以后继续被当作默认主路径使用。
### 验收标准
- `RenderMaterialUtility.h` 体量显著下降,职责单一
- renderer 主链依赖的是正式 contract / runtime resolve而不是 compat 大杂烩
- 现有 shader/material 行为与测试结果保持一致
### 计划提交点
这一阶段完成后立即提交推送一次。
## 6.4 Phase DRuntime Pass 与 Editor/Debug Pass 边界重整
### 目标
明确 engine runtime rendering core 与 editor/debug-oriented rendering extension 的边界。
### 要解决的根因
- grid、outline 等语义虽然已经可用,但组织上仍偏临时
- engine 核心层里混有 editor 专用概念
- 后续 camera frame composition 扩展容易再次被 editor 需求污染
### 具体工作
1. 明确哪些是 runtime 正式能力,哪些是 editor/debug extension。
2. 把 editor/debug pass 的注册与宿主接入方式整理成正式 extension seam。
3. 保持 SceneView / GameView 继续复用 runtime renderer 主链,但 editor overlay / outline / grid 不侵入 runtime scene composition。
4. 补足必要文档,说明 engine、renderer、editor 三者的责任边界。
### 验收标准
- editor/debug pass 不再作为 runtime renderer 核心概念扩散
- SceneView / GameView 显示、grid、outline、gizmo 宿主路径不回退
- 新增代码结构能自然承接后续 icon/light gizmo/camera gizmo 等扩展
### 计划提交点
这一阶段完成后立即提交推送一次。
## 6.5 Phase E稳定性清扫、文件收口与文档归档
### 目标
清掉这一阶段剩余的临时写法,让实现、测试、文档口径再次一致。
### 具体工作
1. 修正 `RenderSceneExtractor` 里仍然使用 raw pointer 的稳定排序 tie-breaker。
2.`BuiltinDepthStylePassBase.cpp` 中具体 pass 实现拆出到独立文件。
3. 全面复查 renderer 相关文件命名、目录结构、头源分布是否仍有明显反模式。
4. 更新 `tests/TEST_SPEC.md` 与相关 renderer / editor guide。
5. 阶段完成后,把已过期 plan 归档到 `docs/used`
### 验收标准
- renderer 核心目录结构与职责边界基本一致
- 没有明显残留的阶段性临时代码入口
- 文档、测试矩阵、实现状态三者一致
### 计划提交点
这一阶段完成后立即提交推送一次。
## 7. 测试策略
本阶段的测试必须是“每阶段落地即验证”,不能到最后一次性回归。
### 7.1 Unit
重点保护:
- `CameraRenderer` 阶段顺序与失败传播
- `RenderSceneExtractor` 的稳定输出
- `BuiltinForwardPipeline` 的绑定与材质解析
- material/shader contract 拆层后的接口行为
优先关注:
- `tests/Rendering/unit/test_camera_scene_renderer.cpp`
- `tests/Rendering/unit/test_builtin_forward_pipeline.cpp`
- 与 material utility / scene extractor 相关的 unit tests
### 7.2 Editor / Runtime Integration
重点回归:
- object-id picking
- SceneView / GameView runtime 渲染链
- overlay / outline / grid
- backpack / shadow / multi-light / camera stack / offscreen 等现有场景
至少覆盖:
- `tests/editor/test_viewport_render_flow_utils.cpp`
- `tests/editor/test_scene_viewport_overlay_renderer.cpp`
- `tests/editor/test_viewport_object_id_picker.cpp`
- 现有 rendering integration matrix 中与 lighting、object-id、camera flow 相关的场景
### 7.3 编译与宿主验证
每一阶段至少执行:
1. 相关 test target 编译
2. 相关 unit / integration tests
3. 必要时编译 `XCEditor`
4. 对 editor 中 SceneView / GameView 做 smoke 验证
## 8. 风险与控制
### 风险 1把“结构重构”做成单纯的文件搬家
后果:
- 文件名变了,职责没变
- 代码仍然继续跨层互相依赖
控制策略:
- 每次拆分都要同时调整接口边界和测试保护点
### 风险 2为了图省事继续保留 object-id 特判
后果:
- Camera frame composition 永远无法正式化
- 后续 skybox / post-process 会继续引入更多特判
控制策略:
- 第一阶段必须先砍掉这类特殊旁路
### 风险 3compat 逻辑继续侵入正式 contract
后果:
- shader/material 体系长期混乱
- 之后 Unity 风格 shader authoring 很难落地
控制策略:
- compat 层必须显式命名、显式隔离、显式限定使用场景
### 风险 4editor/debug pass 重整时破坏现有 editor 体验
后果:
- 影响当前 SceneView 主线
- 把结构收口又变成功能回退
控制策略:
- 每一阶段都要做 editor smoke 和既有测试回归
## 9. 阶段完成判定
满足以下条件时,本阶段才算真正收口:
1. `CameraRenderer` 已统一成正式 frame composition 执行模型。
2. `BuiltinForwardPipeline``RenderMaterialUtility` 已完成职责拆分,核心 god file 问题消除。
3. runtime pass 与 editor/debug pass 边界清晰,不再混成一团。
4. 现有 rendering / editor tests 继续稳定通过。
5. `docs/plan``docs/used` 的 plan 入口重新清晰,不再保留已过期的执行入口。
## 10. 与当前主线的关系
这份计划不是替代“Skybox 环境与 Frame Composition 正式化”方向,而是它的前置收口。
顺序必须是:
1. 先做 renderer 结构收口与代码正式化
2. 再做 skybox / environment / post-process 的正式接入
3. 最后才考虑更高阶的 renderer feature 与未来 SRP 承接
否则就是在结构债未清的情况下继续加层,后面只会越收越难。

View File

@@ -0,0 +1,523 @@
# Renderer阶段收口旧兼容路径清理与正式化计划
日期:`2026-04-08`
## 1. 背景
当前 `Rendering` 模块的主执行架构已经基本成型:
- `RenderSceneExtractor`
- `SceneRenderRequestPlanner`
- `SceneRenderer / CameraRenderer`
- built-in forward / shadow / object-id / outline / final-color / skybox
这些主链路已经能稳定支撑:
- runtime 场景渲染
- editor scene/game viewport
- 多光源、阴影、object-id、outline、skybox 等现有能力
因此,当前 Rendering 的主要问题已经不再是“能不能画出来”,而是:
- 还残留一些旧路线兼容代码
- 一些 built-in 运行契约仍然依赖隐式推断
- 少量路径仍然带有明显的过渡期实现痕迹
如果这些问题不在当前阶段彻底收口,后续继续推进:
- Renderer 模块扩展
- Material / Shader editor
- Unity 风格 SRP 底层承接
就会持续建立在一层“虽然能跑,但不是正式规则”的兼容逻辑之上。
这不符合当前阶段的目标。
当前阶段的正确方向不是新增更多渲染功能,而是:
- 清理旧兼容路径
- 去掉运行时语义猜测
- 把 built-in shader / material / pass contract 进一步正式化
---
## 2. 当前已确认的问题
基于本轮对 `engine/include/XCEngine/Rendering``engine/src/Rendering``engine/src/Resources/Shader``engine/src/Resources/Mesh` 的代码审查,当前确认存在以下问题。
### 2.1 Mesh 导入仍可生成“无 shader / 无 schema”的旧材质路线
当前 `MeshLoader` 导入子材质时,仍然直接写入:
- `baseColor`
- `baseColorTexture`
- `opacity`
- `twoSided`
而不是直接落到正式 shader schema 对应的属性名与纹理槽位。
这导致 runtime 渲染阶段仍然需要兜底兼容这些旧名字。
典型位置:
- `engine/src/Resources/Mesh/MeshLoader.cpp`
- `engine/include/XCEngine/Rendering/Materials/RenderMaterialResolve.h`
### 2.2 Rendering 仍通过属性别名表推断 built-in 材质语义
当前 `RenderMaterialResolve.h` 中,仍然保留了大量 builtin 属性/纹理别名表,例如:
- `baseColor`
- `_BaseColor`
- `color`
- `_Color`
- `baseColorTexture`
- `_BaseColorTexture`
- `_MainTex`
- `texture`
这意味着 runtime 当前并不是“按 shader schema 正式解析”,而是:
- 优先找 semantic
- 找不到就继续按一批旧属性名字猜
这属于典型过渡兼容逻辑,不应成为正式长期实现。
### 2.3 BuiltinForward / Depth / Shadow 仍存在 per-material fallback constant 路线
当前如果材质没有正式 schema constant layout管线仍会临时构造
- `FallbackPerMaterialConstants`
并继续提交 draw。
这说明 runtime 仍允许“非正式材质实例”继续进入正式绘制链路。
这条路径虽然提高了兼容性,但本质上绕开了已经建立的 shader/material 正式模型。
### 2.4 Built-in pass resource binding 仍依赖隐式硬编码
当前 builtin shader pass 如果未显式声明 `resources`,运行时仍会通过:
- `TryBuildImplicitBuiltinPassResourceBindings`
自动补一套绑定布局。
这意味着资源绑定契约并不完全存在于 shader 资产中,而是仍有一部分硬编码在 C++ 中。
这会带来两个问题:
1. shader 资产与 runtime 存在双份真相
2. 后续继续演进 shader/material/editor 时,容易再次产生隐式规则
### 2.5 HLSL register 重写仍保留 legacy alias
当前 `ShaderVariantUtils.h` 仍保留:
- `ResolveLegacyHlslBindingDeclarationAlias`
以及基于 `gBaseColorTexture` / `gLinearSampler` 一类旧命名的重写逻辑。
这说明 shader runtime 编译阶段仍在兼容旧命名风格。
这属于典型“过渡兼容层”,应在 built-in shader 显式资源契约完成后清掉。
### 2.6 Built-in pass 选择仍存在隐式默认规则
当前如果 shader 没有显式 builtin metadata`MatchesBuiltinPass(...)` 仍会把它默认当成:
- `ForwardLit`
这意味着 shader 即使没有明确声明自己属于哪个 built-in pass也有可能继续进入主几何管线。
这不利于长期正式化。
### 2.7 Shader artifact 仍兼容多代旧 schema
当前 shader artifact loader 仍兼容:
- `XCSHD01`
- `XCSHD02`
- `XCSHD03`
- `XCSHD04`
- 当前 schema
但 shader artifact 本质上是 `Library` 中的可重建中间产物,不属于必须长期 runtime 兼容的用户资产格式。
如果继续保留多代 schema 分支,会让 shader 资源链路长期背着历史包袱。
---
## 3. 本阶段设计原则
本计划执行时,必须严格遵守以下原则。
### 3.1 正式路径只能有一条
对 built-in shader / material / pass 来说,正式路径必须是:
`导入/authoring -> shader schema -> material instance -> explicit pass contract -> render pipeline`
不能继续允许 runtime 依赖旧命名、旧别名、旧格式去自动猜测。
### 3.2 兼容应尽量前移到导入/重建阶段,而不是留在 runtime
如果确实存在历史资产问题,应优先采用:
- 重新导入
- 重新生成 artifact
- 一次性迁移
而不是继续在 runtime loader / renderer 中保留长期兼容分支。
### 3.3 Built-in shader 契约必须显式写进 shader 资产
以下内容必须属于 shader/pass 资产本身,而不是 runtime 猜出来:
- pass 类型
- pass metadata
- resource binding
- property semantic
### 3.4 Rendering 不再为“无正式 shader/schema 的材质”兜底渲染
当前阶段的目标是“收口”,不是“继续最大化兼容”。
因此:
- 非正式材质应尽快在导入层修正
- runtime 应逐步拒绝无 schema 的正式绘制路径
### 3.5 每一步都必须可验证
每个阶段完成后必须配套:
- unit test
- 必要的 integration test
- editor 编译/回归
不能只凭画面“看起来没问题”判断完成。
---
## 4. 本阶段目标
本阶段完成后Rendering 模块应达到以下状态:
1. Mesh 导入出来的材质直接走正式 shader/material 体系
2. runtime 不再依赖 `baseColor` / `_MainTex` 等别名表去维持 built-in 主链
3. built-in pass resource binding 由 shader 资产显式声明,不再依赖隐式硬编码补全
4. built-in pass 分类必须显式声明,不再存在“默认 ForwardLit”
5. shader artifact runtime loader 不再长期兼容多代旧 schema
6. 对应测试体系同步升级,保证收口后功能不回退
---
## 5. 明确不在本阶段处理的内容
以下内容不属于本阶段目标:
- render graph
- deferred renderer
- 新一轮后处理功能扩展
- C# SRP 脚本侧 API
- ShaderGraph
- 高级材质编辑器功能扩展
这些方向都依赖本阶段先把底层 contract 收紧。
---
## 6. 分阶段执行计划
## Phase 1建立基线与目标测试
### 目标
先把当前遗留兼容路径的行为边界用测试钉住,并同步写出“目标行为”的新测试。
### 任务
- 审查并整理当前覆盖以下行为的测试:
- `RenderMaterialResolve`
- builtin forward pipeline resource binding
- mesh material import
- shader artifact load
- 新增/调整测试,使其明确区分:
- 当前历史兼容行为
- 本阶段目标正式行为
- 对以下目标先写失败测试或待切换测试:
- imported mesh material 必须绑定正式 builtin shader
- imported material property 必须落到正式 schema 名称
- builtin pass 若无显式 metadata不得进入主 pipeline
- builtin shader 若无显式 resources不得依赖隐式 binding 补全
### 验收标准
- 能清楚列出哪些测试在保护旧行为,哪些测试在保护目标行为
- 后续每个阶段都能基于这些测试判断是否真正收口
---
## Phase 2收口 Mesh 导入材质到正式 shader/material 路径
### 目标
彻底去掉 imported mesh material 的“无 shader / 裸属性名”旧路线。
### 任务
- 调整 `MeshLoader` 导入逻辑:
- imported material 直接绑定正式 builtin shader
- 默认按现有主线落到 builtin lit/forward 合同
- 导入属性与纹理时,直接写正式 property name / texture slot
- 例如 `_BaseColor`
- `_MainTex`
- `_Cutoff`
- 其他已正式声明的 builtin 属性
- 不再向 imported material 写入仅靠 runtime 别名识别的裸字段:
- `baseColor`
- `baseColorTexture`
- `color`
- `texture`
- 更新 mesh import 相关测试、render extractor 测试、相关 integration 资源测试
### 验收标准
- mesh import 结果中的材质都带有正式 shader 引用
- mesh import 结果中的属性/纹理绑定名称与 shader schema 对齐
- 不再需要 runtime 靠旧别名才能让导入材质正常渲染
---
## Phase 3移除 runtime builtin 材质语义别名与 fallback 常量路径
### 目标
让 built-in pipeline 只吃正式 schema 材质,不再继续兼容旧材质命名。
### 任务
- 清理 `RenderMaterialResolve.h` 中的旧别名解析表:
- base color property alias
- base texture alias
- skybox texture alias
- alpha cutoff alias
- 保留并强化基于 `shader property semantic` 的正式解析路径
- 移除 `FallbackPerMaterialConstants` 路线
- 当材质未携带正式 schema constant layout 时:
- 显式报错 / 记录诊断
- 拒绝进入需要正式材质常量的绘制路径
- 调整 forward / depth / shadow / skybox 相关单测
### 验收标准
- builtin pipeline 不再依赖属性别名表维持主链
- builtin pipeline 不再手工构造 per-material fallback constant 继续绘制
- runtime 只接受正式 shader/material 契约
---
## Phase 4显式化 builtin pass resource binding contract
### 目标
让 builtin shader pass 的资源绑定契约完全存在于 shader 资产中,而不是藏在 runtime 硬编码里。
### 任务
- 为所有 builtin shader pass 补齐显式 `resources` 描述
- 覆盖至少以下 shader
- `forward-lit.shader`
- `depth-only.shader`
- `shadow-caster.shader`
- `object-id.shader`
- `skybox.shader`
- `final-color.shader`
- 其他当前仍在主链中的 builtin shader
- 清理 `TryBuildImplicitBuiltinPassResourceBindings`
- 清理 `ShaderVariantUtils.h` 中围绕 implicit/legacy binding 的兼容逻辑:
- legacy alias register rewrite
- 依赖 `gXxx` 名称重写的分支
- 调整 shader loader / rendering pipeline / builtin pass 单测
### 验收标准
- builtin shader pass 缺少显式资源绑定时,构建或运行应明确失败
- runtime 不再替 shader 资产自动补 binding layout
- HLSL runtime 编译不再依赖 legacy alias register 重写
---
## Phase 5显式化 builtin pass metadata 与 pass 选择规则
### 目标
去掉“默认 ForwardLit”一类隐式 pass 归类规则。
### 任务
- 收紧 `BuiltinPassMetadataUtils`
- built-in pass 匹配必须依赖显式 pass name / tag
- 删除“无 metadata 默认归 ForwardLit”的逻辑
- 审查并统一 builtin shader 的 pass metadata
- `Name`
- `LightMode`
- 其它当前正式要求的 tag
- 对进入 builtin 主线的 shader 建立硬约束:
- 没有显式 builtin metadata 的 shader不得继续被当作主几何 shader 使用
- 更新 pass 匹配测试和 shader authoring 测试
### 验收标准
- builtin pass 选择全部基于显式 metadata
- 不存在 runtime 默认猜一个 pass 类型的行为
---
## Phase 6清理旧 shader artifact schema 兼容
### 目标
让 shader artifact runtime loader 与 material artifact 一样,收口到 current schema。
### 任务
- 清理 `ShaderArtifactLoader.cpp` 中对旧 schema 的分支兼容:
- `XCSHD01`
- `XCSHD02`
- `XCSHD03`
- `XCSHD04`
- 将旧 `Library` artifact 的处理方式改为:
- 识别为过期
- 触发重新导入 / 重新生成
- 或直接报错要求重建 `Library`
- 更新 asset database / shader load 相关测试
- 明确记录此阶段会带来的影响:
-`Library` 无法直接沿用
- 需要一次性刷新或重建
### 验收标准
- shader artifact loader 只接受 current schema
- 对旧 artifact 的处理边界清晰且可测试
---
## Phase 7全量验证与阶段收口
### 目标
确认 Rendering 在去掉旧兼容层之后没有破坏现有功能。
### 任务
- 编译并运行:
- `material_tests`
- `rendering_unit_tests`
- `asset_tests`
- `editor_tests`
- 受影响的 mesh/shader 资源测试
- 重新编译 `XCEditor`
- 重点回归:
- scene viewport
- game viewport
- object-id picking
- selection outline
- skybox
- 阴影
- 多光源
- backpack / sphere / quad 等 integration scene
- 形成阶段收口报告
### 验收标准
- 所有直接相关测试通过
- editor 编译通过
- 关键 integration scene 渲染行为不回退
- 能明确宣告 runtime 旧兼容路径已移除
---
## 7. 风险与注意事项
### 7.1 这是一次“切正式路径”的收口,不是小修小补
本计划一旦执行,就会主动删除一部分兼容逻辑。
因此不能以“尽量少改代码”为目标,而应以:
- 正式路径唯一
- contract 清晰
- 后续 SRP 可承接
为目标。
### 7.2 `Library` 重建属于预期影响
一旦收掉旧 shader artifact schema 兼容,旧 `Library` 里的 shader artifact 失效是正常现象。
这不应被视为回归,而应被视为阶段性收口的合理代价。
### 7.3 必须避免引入新的“临时兼容层”
执行过程中需要特别警惕以下错误做法:
- 新加一层 alias 表,试图“先兼容一下”
- 把 runtime fallback 换个名字继续保留
- 在 editor 或 import 层再次引入一套过渡数据模型
如果遇到结构性问题,正确做法是:
- 直接改到正式模型
- 同步补测试
而不是再加一层短期兜底。
---
## 8. 建议执行顺序
建议严格按以下顺序推进:
1. `Phase 1` 测试基线整理
2. `Phase 2` mesh 导入材质正式化
3. `Phase 3` runtime 材质别名与 fallback 常量清理
4. `Phase 4` builtin pass 显式资源绑定
5. `Phase 5` builtin pass metadata 显式化
6. `Phase 6` shader artifact schema 收口
7. `Phase 7` 全量验证
原因是:
- 如果不先把 imported material 拉回正式路径
- 后面的 runtime alias / fallback 清理就一定会打断现有资源链路
---
## 9. 本阶段完成后的预期状态
本计划完成后Rendering 模块应达到以下状态:
1. built-in shader/material/pass contract 全部走正式显式路径
2. runtime 不再依赖旧命名猜测材质语义
3. runtime 不再替非正式材质拼接 fallback 常量布局
4. builtin shader 资源绑定契约完全由 shader 资产声明
5. builtin pass 类型选择完全依赖显式 metadata
6. shader artifact runtime loader 不再背负旧 schema 包袱
7. 整个 Rendering 模块更适合作为后续 Unity 风格 SRP 的底层承接
---
## 10. 一句话总结
当前 Rendering 真正需要的不是继续加功能,而是把残留的旧兼容路径彻底拔干净。
这一阶段的本质,是把:
- imported material
- built-in shader binding
- pass metadata
- shader artifact
全部拉回到同一套正式 contract 上,为后续 Renderer / Material / Shader / SRP 的继续推进打地基。

View File

@@ -0,0 +1,71 @@
# Renderer 阶段收口补充Object ID Picking 正式化
日期:`2026-04-02`
## 1. 这次补充收口解决什么
本次补充只收一件事:
- `SceneView` 选中主链路正式切到 `GPU object-id`
本次明确不做:
- render graph
- renderer 内更完整的多 pass 调度
- game/runtime 通用 picking 服务
原因很简单:这些属于下一阶段架构演进,不应该继续污染当前阶段的收口边界。
## 2. 本次收口后的正式行为
当前 `SceneView` 选中行为统一定义为:
1. 场景渲染时生成 `object-id` 纹理
2. 鼠标点击时读取对应像素
3. 颜色解码为实体 ID
4. `0` 视为“未选中任何对象”,但这仍然是一次成功的 GPU 采样
关键变化:
- editor 不再把 `CPU ray picking` 作为 `SceneView` 点击选中的静默回退主链路
- `CPU ray picking` 继续保留为独立几何工具能力,不再承担当前正式选中流程
- `object-id` 读取失败会被显式标记为 readback failure而不是与“没有有效帧”混在一起
## 3. 为什么这才算收口
之前的问题不是没有 `object-id pass`,而是“主路径”和“兜底路径”的语义不够硬:
- 成功采样
- 无有效 object-id 帧
- GPU 读回失败
这三种状态以前没有被清晰区分。
现在已经收紧为显式结果类型:
- `Unavailable`
- `Success`
- `ReadbackFailed`
这意味着:
- renderer/editor 的 `object-id` 交互已经形成可测试契约
- `0 id` 与“采样失败”不再混淆
- 后续若要继续升级成异步 readback、共享 picking 服务,也有稳定边界可接
## 4. 当前阶段完成后的边界
到这里,当前阶段可以正式视为完成:
- editor viewport 宿主链路已打通
- renderer 的 builtin post-process 已形成稳定接口
- `SceneView` 选中正式以 GPU object-id 为主链路
- 回归测试已覆盖 object-id 读回状态语义
下一阶段真正该做的是:
- renderer 内正式 render graph / pass graph
- 更完整的 renderer-owned picking 服务
- editor / runtime shared picking contract
而不是继续在这个阶段里反复修补 viewport host。

View File

@@ -0,0 +1,164 @@
# Renderer阶段收口说明
## 1. 目标
本文用于正式收口当前 Renderer 阶段,明确:
- 本阶段已经完成什么
- 哪些能力已经进入稳定边界
- 哪些事项明确延期到下一阶段
- 后续开发不应再继续把新功能塞回本阶段
当前收口日期:`2026-04-02`
---
## 2. 本阶段已完成能力
### 2.1 Renderer 主体边界
当前已经形成稳定分层:
- `RHI` 负责后端抽象与资源/命令执行
- `Rendering` 负责场景提取、camera request、pipeline、builtin pass
- `Editor` 负责 viewport 宿主、输入、overlay、编辑态请求装配
关键点:
- `CameraRenderer` 已经承担统一 camera 渲染执行职责
- `SceneRenderer` 已经承担 scene -> camera request 的组织职责
- editor scene viewport 不再自己拼装 renderer 执行逻辑
### 2.2 内建后处理边界
本阶段内建编辑态后处理已经收敛为 renderer 自己的通用请求能力:
- `BuiltinPostProcessRequest`
- `BuiltinPostProcessPassPlan`
- `BuiltinPostProcessPassSequenceBuilder`
这意味着:
- renderer 公共接口不再暴露 `SceneView` 专有命名
- grid / selection outline / debug mask 已归入 renderer 侧 builtin post-process 能力
- editor 只负责“是否启用、传什么数据、把哪些 render target 绑定进 request”
### 2.3 Editor Scene Viewport 接入
当前 editor scene viewport 已具备:
- renderer 离屏输出接入
- object-id 帧输出接入
- CPU picking 回退链路
- selection outline
- infinite grid
- built-in post-process 请求装配
其中:
- grid 和 outline 仍然服务于 editor scene viewport
- 但执行入口已经下沉到 renderer
- editor 只保留宿主与编辑器语义
### 2.4 自动化测试体系
当前已经具备稳定回归闸门:
- `tests/Rendering/unit`
- `tests/Rendering/integration`
- `tests/Editor`
- `rendering_phase_regression`
当前阶段收口依赖的关键验证包括:
- renderer unit tests
- editor tests
- 全 rendering integration 场景
- `XCEditor` smoke launch
---
## 3. 本阶段稳定边界
以下内容从现在开始视为本阶段稳定边界:
1. renderer 公共请求以 `CameraRenderRequest` 为核心,而不是 editor 自定义执行入口。
2. editor scene viewport 的内建后处理数据由 editor 组装,但 pass 执行由 renderer 负责。
3. builtin post-process 的公共语义是 renderer 语义,不是 `SceneView` 语义。
4. rendering regression 失败时,优先视为阶段回归,而不是“可接受的小问题”。
---
## 4. 本阶段明确延期项
以下事项明确不再继续塞入本阶段,转入下一阶段:
### 4.1 真正的多 pass / render graph 框架
当前已有 pass sequence 与 builtin post-process但这还不是完整的 renderer 多 pass 架构。
延期内容:
- renderer 级 render graph
- 更正式的 pass phase / event 模型
- 更通用的资源读写依赖管理
### 4.2 GPU Object ID 正式方案
当前 editor selection 相关链路已经能工作,但还不是最终方案。
延期内容:
- renderer 内正式 object-id pass/attachment 规范化
- editor picking 从 CPU fallback 继续向 GPU object-id 正式方案收敛
- editor/game shared picking contract
### 4.3 Gizmo 最终渲染体系
当前 gizmo 与 scene viewport 已经能工作,但不属于本阶段 renderer 收口范围。
延期内容:
- 更成熟的 gizmo 渲染架构
- 更统一的 gizmo draw pass / picking / overlay 体系
- 与后续 renderer 多 pass 的正式对接
### 4.4 C# SRP 对接
当前 renderer 的职责边界已经为 SRP 预留好了方向,但本阶段不做真正脚本化 pipeline 落地。
延期内容:
- `RenderPipelineAsset` / `RenderPipeline` 脚本绑定
- `ScriptableRenderContext`
- `CommandBuffer`
- renderer 与脚本侧的正式桥接层
---
## 5. 阶段退出标准
当前阶段只有在以下条件全部满足时才视为完成:
1. renderer/editor 边界中不再存在新的 `SceneView` 语义向 renderer 公共接口泄漏。
2. scene viewport 的 builtin post-process 组合链路具备稳定自动化回归覆盖。
3. `rendering_phase_regression` 保持通过。
4. 新功能开发转入下一阶段,不再回头污染本阶段边界。
截至本文落地时,这些退出标准已经满足。
---
## 6. 下一阶段入口
Renderer 下一阶段应当正式转向:
- renderer 内更完整的多 pass / phase 模型
- editor/game shared render feature 契约
- object-id 正式化
- 为后续 C# SRP 搭建真正可扩展的 renderer 接口
一句话总结:
- 当前阶段已经把“Renderer 从 RHI 之上独立出来,并接通 editor scene viewport”这件事做完
- 下一阶段不该继续修补这一层,而应开始建设更正式的 renderer 扩展框架

View File

@@ -0,0 +1,631 @@
# Scene Viewport Overlay 与 Gizmo 正规化重构方案
日期:`2026-04-02`
## 0. 当前进度 Checkpoint
截至 `2026-04-02`,本方案已有以下落地结果:
- `Phase 1` 已完成:
- `CameraRenderRequest` 已新增 `overlayPasses`
- `CameraRenderer` 已在 builtin postprocess 之后执行 `overlayPasses`
- `ViewportHostService` 已接入 editor overlay pass sequence
- `Phase 2` 已完成首批迁移:
- `camera frustum`
- `directional light gizmo`
- `camera/light scene icon`
- 上述内容已不再走 ImGui world draw而是走 renderer overlay pass
- `scene icon` 的命中数据已开始收口:
- `SceneViewPanel` 不再自己扫描 scene 构建 icon draw data
- icon hit test 已改为消费 `SceneViewportOverlayBuilder::Build()` 产出的同类 frame data
- `transform gizmo` 的统一命中已开始接线:
- `SceneViewportEditorOverlayData.h` 已扩展为通用 `handleRecords`
- `SceneViewportOverlayHandleBuilder.h` 已可把 move/rotate/scale gizmo draw data 转为 canonical handle records
- `SceneViewPanel` 中 gizmo 的 hover / click-begin 已开始走统一 `HitTestSceneViewportOverlayHandles(...)`
- `transform gizmo` 的绘制迁移已开始接线:
- `SceneViewportEditorOverlayPass` 已支持 screen-space triangle primitive
- `ViewportHostService` 已可在 host 侧根据 `SceneViewPanel` 提交的 overlay 与 gizmo handle build inputs 构建 transient transform overlay frame data
- transform gizmo 的 handle build inputs 组装 helper 已开始从 `SceneViewPanel``SceneViewportOverlayHandleBuilder.h` 收口
- transform gizmo 的 selection/context/refresh/cancel helper 已开始从 `SceneViewPanel``SceneViewportTransformGizmoFrameBuilder.h` 收口
- move / rotate / scale gizmo 已不再直接依赖 `DrawSceneViewportOverlay()` 的 ImGui gizmo 绘制分支出图
- `SceneViewportOverlayRenderer.cpp` 已收缩回 HUD/orientation 责任,不再承担 transform gizmo / scene icon / scene line 的 ImGui world draw
- `SceneViewPanel` 内部交互前命中与交互后绘制的 gizmo 刷新链路已开始复用同一套 helper重复的 context/update/submit 逻辑已明显收缩
- interaction overlay frame 已改为 host 按传入的 transform gizmo inputs 现场组合,`SceneViewPanel` 不再为 hit test 预先写入 transient overlay 缓存
- render 阶段使用的 transient transform gizmo frame data 也已改为 host 基于缓存的原始 overlay + inputs 现场构建
当前仍未完成的关键点:
- `transform gizmo` 的 drag solver / 变换求解仍然保留在各自 gizmo 类中
- `SceneViewPanel` 里仍保留 transform gizmo 的 draw data 生成、交互仲裁与 transient overlay 提交逻辑
- `SceneViewPanel` 仍直接控制 transform gizmo 的最终绘制 overlay 提交时机host 尚未完全接管这一层 frame orchestration
- `ViewportHostService` 的 canonical overlay frame data 仍未直接承载 transform gizmo尚未收敛到单帧单份 canonical overlay 数据
当前阶段结论:
**方案方向已经验证正确,下一步不应该回头继续扩写 ImGui world overlay而应该继续推进 canonical overlay data 与统一命中系统。**
## 1. 方案结论
当前 `Scene Viewport` 的问题,不是某一个 `Directional Light Gizmo` 画丑了,而是整条 editor overlay 链路本身没有收口:
- `grid` 已经是正规 renderer pass
- `transform gizmo / camera icon / light icon / camera frustum / directional light gizmo` 仍然是 ImGui overlay
- 输入命中和绘制几何不是同一份数据
- `SceneViewPanel.cpp` 同时承担 panel UI、输入调度、世界转屏幕、overlay 构建、命中仲裁,职责已经失控
结论只有一个:
**不能再继续往 `SceneViewPanel.cpp` 和 ImGui world overlay 上堆功能。必须把场景中的 editor 可视化正式收口成一套 renderer 级 overlay pass 和统一 handle 数据。**
---
## 2. 当前链路梳理
### 2.1 正规链路Grid
当前 `grid` 的路径是正规的 renderer pass
`ViewportHostService -> SceneRenderer -> CameraRenderer -> BuiltinPostProcessPassSequenceBuilder -> BuiltinInfiniteGridPass`
关键文件:
- `editor/src/Viewport/ViewportHostService.h`
- `editor/src/Viewport/ViewportHostRenderFlowUtils.h`
- `engine/src/Rendering/CameraRenderer.cpp`
- `engine/src/Rendering/Passes/BuiltinPostProcessPassSequenceBuilder.cpp`
- `engine/src/Rendering/Passes/BuiltinInfiniteGridPass.cpp`
这条链路的特征是:
- 在 scene 几何渲染完成后,由 GPU pass 正式叠加
- 有明确的 render request 输入
- 有独立 pass 边界
- 不依赖 ImGui draw list
### 2.2 非正规链路Editor World Overlay
当前绝大多数 editor 可视化不是 renderer pass而是
1. `ViewportHostService` 渲出 scene viewport 纹理
2. `RenderViewportPanelContent()` 在 ImGui 面板中显示这张纹理
3. `SceneViewPanel.cpp` 在这张纹理之上继续用 ImGui draw list 手搓 world overlay
关键文件:
- `editor/src/panels/ViewportPanelContent.h`
- `editor/src/panels/SceneViewPanel.cpp`
- `editor/src/Viewport/SceneViewportOverlayRenderer.cpp`
当前放在这条链上的内容包括:
- move gizmo
- rotate gizmo
- scale gizmo
- camera icon / light icon
- camera frustum
- directional light gizmo
- orientation gizmo
其中 `orientation gizmo` 本质上是固定在右上角的 HUD放在 ImGui 问题不大。真正失控的是那些锚定在世界空间中的 overlay。
---
## 3. 当前架构的核心问题
### 3.1 绘制职责放错层
`SceneViewPanel.cpp` 不应该知道:
- camera frustum 怎么构造几何
- directional light gizmo 怎么构造几何
- icon 如何转屏幕矩形
- 各种 gizmo 如何排序、如何遮挡
这些本质上都属于 viewport overlay 系统,不属于 panel UI。
### 3.2 命中和绘制分裂
当前很多交互是:
- 一套代码负责画
- 另一套代码负责 hover / click / drag
这会导致:
- 看见的和能点的不是同一个东西
- 改样式时经常忘改命中
- 优先级只能靠条件链硬拼
### 3.3 世界空间对象被当成 2D UI 处理
camera/light icon、frustum、light gizmo、transform gizmo 本质上都是世界空间 editor overlay。
但它们现在被塞进 ImGui draw list 后,就天然失去:
- 正规的渲染顺序语义
- 稳定的深度/遮挡策略
- 统一的 primitive 渲染方式
- GPU 级别的扩展能力
### 3.4 `SceneViewPanel.cpp` 已经过胖
当前它同时负责:
- tools/top bar UI
- tool mode 切换
- gizmo context 组装
- gizmo hover/click 仲裁
- icon hit test
- overlay 世界几何构建
- scene picking
- scene camera 输入
这已经不再是“面板”,而是一个巨型调度器加半个渲染系统。
### 3.5 视觉风格无法稳定收敛
Directional Light 这次暴露得最明显:
- 需求是“圆形底盘上的光线分布”
- 当前实现却是在 panel 里临时拼几根线
这不是调几个参数能根治的问题,而是底层 primitive 表达和系统边界不对。
---
## 4. 重构目标
这次重构的目标不是“顺手把几个 gizmo 再修漂亮一点”,而是把 Scene Viewport overlay 彻底正规化。
最终目标如下:
### 4.1 分离两类 overlay
#### A. HUD 类 overlay
固定在面板坐标系的内容继续留在 ImGui
- 顶部工具栏
- 左侧 tools 按钮
- 右上角 orientation gizmo
- 状态提示文字
#### B. World Anchored Overlay
锚定在世界空间里的 editor 可视化统一进入 renderer overlay pass
- move / rotate / scale gizmo
- camera / light scene icon
- camera frustum
- directional light gizmo
- 后续 collider bounds / helper shapes / volume gizmo
### 4.2 统一绘制数据与命中数据
所有可交互 gizmo handle 必须来自同一份 canonical data
- 画什么
- 颜色是什么
- 层级优先级是什么
- handle id 是什么
- 哪里可以点
都不能再分散在不同类里各算一套。
### 4.3 建立 renderer 级 editor overlay pass
目标顺序应为:
`Scene Geometry -> ObjectId -> Builtin Post Process(Grid/Outline) -> Editor Overlay Pass -> ImGui HUD`
也就是说editor 世界 overlay 必须成为正式 render stage而不是纹理上的二次手绘。
### 4.4 让 gizmo 类回归“控制器/求解器”角色
`Move / Rotate / Scale Gizmo` 类应主要负责:
- drag 状态机
- 轴向约束
- plane 约束
- 变换求解
- 交互反馈求解
不再继续兼任:
- 实际几何绘制器
- 实际命中主仲裁器
---
## 5. 推荐的目标架构
## 5.1 Render Request 层新增 `overlayPasses`
当前 `CameraRenderRequest` 里有:
- `preScenePasses`
- `postScenePasses`
- `builtinPostProcess`
但没有真正适合 editor world overlay 的最后一层。
建议新增:
- `overlayPasses`
执行顺序调整为:
1. `preScenePasses`
2. scene geometry
3. object id
4. `postScenePasses`
5. `builtinPostProcess`
6. `overlayPasses`
这样 world overlay 才能稳定压在 grid 和 outline 之上,再由 ImGui 负责最后的 HUD。
### 5.2 新建 `SceneViewportOverlayFrameData`
建议新增一个独立的 frame data 结构,承载这一帧 Scene Viewport 的 editor overlay 数据。
建议字段:
- `linePrimitives`
- `trianglePrimitives`
- `billboardSprites`
- `handleRecords`
- `renderLayer`
- `depthMode`
- `screenSpaceThickness`
其中:
- primitive 用于绘制
- handle record 用于命中
- 两者共享相同的 `handleId`
### 5.3 新建 `SceneViewportOverlayBuilder`
职责:
- 接收 scene overlay context
- 收集 selected objects
- 构建 camera frustum
- 构建 directional light 圆形底盘 gizmo
- 构建 scene icons
- 构建 transform gizmo handles
- 输出统一的 `SceneViewportOverlayFrameData`
建议位置:
- `editor/src/Viewport/SceneViewportOverlayBuilder.h`
- `editor/src/Viewport/SceneViewportOverlayBuilder.cpp`
### 5.4 新建 `SceneViewportOverlayHitTester`
职责:
- 基于 `SceneViewportOverlayFrameData::handleRecords` 做统一命中
- 输出唯一的 hovered handle
- 同一份数据同时服务 hover / click / drag begin
建议位置:
- `editor/src/Viewport/SceneViewportOverlayHitTester.h`
- `editor/src/Viewport/SceneViewportOverlayHitTester.cpp`
### 5.5 新建 `SceneViewportEditorOverlayPass`
职责:
- 读取 `SceneViewportOverlayFrameData`
- 用 GPU 绘制 line / fill / billboard
- 负责世界空间 editor overlay 的正式渲染
建议位置:
- `editor/src/Viewport/Passes/SceneViewportEditorOverlayPass.h`
- `editor/src/Viewport/Passes/SceneViewportEditorOverlayPass.cpp`
### 5.6 `SceneViewPanel` 的目标职责
重构后 `SceneViewPanel` 只负责:
- 顶部栏和 tools UI
- tool mode / pivot / local-global 状态
- 输入汇总
- 与 viewport host service 交互
- 显示固定 HUD
不再负责:
- world overlay 几何构建
- icon 转屏幕
- frustum / light gizmo 线框拼装
- world overlay 主渲染
---
## 6. 模块职责重新划分
### 6.1 `SceneViewPanel`
保留:
- 面板 UI
- 工具模式切换
- 快捷键
- 鼠标/键盘输入汇总
- orientation gizmo
移出:
- world overlay primitive 构建
- scene icon world/screen 几何生成
- camera/light 线框绘制逻辑
### 6.2 `ViewportHostService`
新增职责:
- 组装 `SceneViewportOverlayFrameData`
- 把 overlay pass 接到 render request
保留职责:
- scene view camera
- viewport render target 管理
- scene render request 提交
- object id picking
### 6.3 Gizmo 求解器
`SceneViewportMoveGizmo / RotateGizmo / ScaleGizmo` 保留:
- 拖拽求解
- 激活态
- 交互反馈数据
逐步移除:
- 直接操作 ImGui draw data 的职责
- 各自内部封闭的 hit test 决策权
### 6.4 Overlay Pass
只负责 GPU 绘制,不处理业务判断。
输入必须已经是“可直接画”的 primitive 数据,避免 pass 内部再知道 camera/light/gizmo 业务语义。
---
## 7. 推荐执行阶段
这次重构不能一次性大爆炸改完,但必须每一步都朝最终架构收敛,不能做过渡性屎层。
### Phase 0冻结错误扩展方向
目标:
- 停止继续向 `SceneViewPanel.cpp` 添加新的 world overlay 绘制逻辑
- 停止继续扩写 `SceneViewportOverlayRenderer.cpp` 为 ImGui world renderer
产出:
- 文档确认
- 后续新增 world gizmo 一律走 overlay builder / pass 方向
### Phase 1打通 `overlayPasses` 通道
目标:
-`CameraRenderRequest` 新增 `overlayPasses`
-`CameraRenderer` 中调整执行顺序
-`ViewportHostService` 中接入 editor overlay pass sequence
产出:
- renderer 支持 scene 之后再画 editor overlay
- 这一步允许先画空 pass不做功能迁移
验收:
- 不影响现有 scene / grid / selection outline
- `overlayPasses` 具备独立初始化、执行、释放边界
### Phase 2迁移纯显示型 world overlay
优先迁移:
- camera frustum
- camera/light scene icon
- directional light gizmo
原因:
- 这些内容交互复杂度低
- 最容易先把 `SceneViewPanel.cpp` 中世界几何拼装代码减掉
Directional Light 本阶段的目标形态:
- 圆形底盘
- 光线分布在圆环或圆盘采样点上
- 明确的世界朝向
- 稳定屏幕线宽
验收:
- 这些 overlay 不再由 ImGui draw list 直接绘制
- `SceneViewPanel.cpp` 不再负责生成对应线框
### Phase 3迁移 Transform Gizmo 的绘制
目标:
- move / rotate / scale gizmo 的显示改为 overlay pass primitive
- gizmo 类转为 handle builder + drag solver
当前进度:
- transform gizmo 已开始转成 transient overlay frame data
- overlay pass 已可消费一批 screen-space triangle primitive 来绘制 gizmo 屏幕几何
- 但 transient gizmo overlay 仍然由 `SceneViewPanel` 在帧末提交,尚未完全收口到 host / builder 的 canonical 路径
说明:
- 这一阶段只迁移“怎么画”
- 可以暂时保留现有 drag 求解逻辑
验收:
- transform gizmo 已不依赖 ImGui world draw
- gizmo 视觉反馈仍然可用
### Phase 4统一命中系统
目标:
- 所有 world overlay 的 hover / click / drag begin 统一使用 `handleRecords`
- 彻底删除 panel 里的多套 hit test 拼接逻辑
当前进度:
- `scene icon` 已完成
- `transform gizmo` 的 hover / click-begin 已经开始接入统一 `handleRecords`
- `drag begin` 之后的求解与 active 状态仍然保留在 gizmo 类与 `SceneViewPanel` 现有链路中
涵盖对象:
- transform gizmo
- scene icon
- 后续 camera/light/world helper handles
验收:
- 命中结果只由一份 canonical handle 数据决定
- 不再依赖大量互相屏蔽的布尔条件
### Phase 5删除旧世界 overlay 路径
目标:
- 删除 `SceneViewPanel.cpp` 中遗留的 world overlay 构建逻辑
- 缩减 `SceneViewportOverlayRenderer.cpp` 到只保留 HUD 类渲染或直接拆分
最终保留:
- ImGui HUD
- renderer world overlay
最终移除:
- ImGui world overlay
---
## 8. 第一阶段建议改动范围
如果按最小风险起步,第一轮只做下面这些:
- `engine/include/XCEngine/Rendering/CameraRenderRequest.h`
- `engine/src/Rendering/CameraRenderer.cpp`
- `editor/src/Viewport/ViewportHostService.h`
- `editor/src/Viewport/ViewportHostRenderFlowUtils.h`
- 新增 `editor/src/Viewport/Passes/SceneViewportEditorOverlayPass.*`
第一轮不碰:
- move/rotate/scale 的求解逻辑
- Scene icon 的交互优先级逻辑
- SceneViewPanel 的大面积交互重写
这样可以先把 renderer 通道立住,再分批迁移业务内容。
---
## 9. 方案边界
这次重构明确不做的内容:
- 不顺手做 local mode 新行为
- 不顺手做 runtime 通用 debug draw 系统
- 不顺手把所有 editor widget 一次性改成 pass
- 不在本轮引入 render graph
这次只做一件事:
**把 Scene Viewport 中锚定世界空间的 editor overlay从 ImGui 手搓模式收口为正式 renderer overlay 系统。**
---
## 10. 风险与控制
### 10.1 风险:一次性迁移过大
控制方式:
- 先打通 pass 通道
- 再迁静态 overlay
- 最后迁 transform gizmo 与命中
### 10.2 风险:命中系统重写影响交互稳定性
控制方式:
- handle record 和旧逻辑短期并存
- 先让新系统服务 hover
- 再切 click / drag begin
### 10.3 风险D3D12-only pass 与后端扩展
控制方式:
- 第一阶段允许 editor overlay pass 先只支持 D3D12
- 但数据结构和 pass 边界必须 backend-neutral
### 10.4 风险:继续出现“画的是一个,点的是另一个”
控制方式:
- 明确规定 overlay primitive 和 hit proxy 必须同源
- 不能再允许绘制与命中分别各算一套几何
---
## 11. 最终验收标准
当以下条件全部满足时,说明收口完成:
- `SceneViewPanel.cpp` 不再承担 world overlay 几何构建职责
- world anchored editor overlay 全部进入 renderer pass
- transform gizmo / scene icon / camera frustum / light gizmo 使用统一 overlay frame data
- hover / click / drag begin 使用统一 handle record
- ImGui 只负责 HUD不再负责世界空间 gizmo 主绘制
- 新增一种 world gizmo 时,不需要再把世界转屏幕逻辑写回 panel
---
## 12. 对本次 Directional Light Gizmo 的直接指导
在该重构方案下Directional Light Gizmo 的正确实现方式应是:
- 它属于 `World Anchored Overlay`
- 它的几何由 `SceneViewportOverlayBuilder` 负责生成
- 它的线段/圆环由 `SceneViewportEditorOverlayPass` 负责绘制
- 它的样式使用“圆形底盘 + 圆周分布光线”,不再在 panel 中临时拼矩形列线
也就是说Directional Light Gizmo 不应该被当成一个局部修补任务继续留在 `SceneViewPanel.cpp`
---
## 13. 本文后的执行原则
在本方案审核通过之前:
- 允许修 bug
- 不建议继续扩写新的 ImGui world overlay 逻辑
在本方案审核通过之后:
- 新增 world overlay 功能,优先接入 overlay builder / overlay pass
- `SceneViewPanel.cpp` 只减不增

View File

@@ -0,0 +1,247 @@
# Shader 与 Material 下一阶段ShaderLab 正式化与 Builtin Shader 资产布局计划
日期:`2026-04-07`
## 1. 阶段结论
上一阶段已经完成了最关键的主线收口:
- `.shader` 现在只表示 authoring shader不再兼容 JSON manifest。
- 旧的 manifest 主路径已经从运行时主流程移除。
- shader / material / editor 相关测试已经回归通过。
- 当前 shader 主线终于从“过渡态”进入了“可以继续正规化”的状态。
这意味着接下来不应该再围绕“兼容旧双路径”打补丁,而应该开始正式推进:
- `ShaderLab authoring`
- `Material contract`
- `builtin shader asset layout`
- `runtime pass contract`
一起向 Unity 风格继续收口。
---
## 2. 当前真实状态
当前已经成立的事实:
1. `.shader` 主语义已经统一。
2. authoring parser 已经能承载基础的 `Shader / Properties / SubShader / Pass / Tags / HLSLPROGRAM / pragma / 基础状态`
3. runtime 已经有 `Shader -> Pass -> Variant` 数据模型。
4. builtin shader 已经基本都迁入 authoring 主路径。
但当前还没有完全完成的部分也很明确:
1. 语法还只是 Unity ShaderLab 的一个子集。
2. builtin shader 资产目录结构还带有明显的过渡痕迹。
3. material 与 shader 的契约虽然比之前干净,但还没完全达到 Unity 式心智模型。
4. renderer 对 pass contract 的消费还可以继续正规化。
---
## 3. Builtin Shader 资产目录结论
这里先把结论写死:
- `engine/assets/builtin/shaders` 下的**主入口 shader 文件**,不需要再一 shader 一子文件夹。
- 既然当前主入口已经都是单个 `.shader` 文件,那么更合理的结构应该是:
```text
engine/assets/builtin/shaders/
forward-lit.shader
unlit.shader
depth-only.shader
shadow-caster.shader
object-id.shader
object-id-outline.shader
skybox.shader
color-scale-post-process.shader
final-color.shader
```
- 需要保留子目录的,不是 builtin shader 入口文件本身,而是**公用 include / shader library**。
- 因此公共代码应该独立成类似:
```text
engine/assets/shaderlib/
Core.hlsl
Common.hlsl
Lighting.hlsl
SpaceTransforms.hlsl
Shadow.hlsl
MaterialInput.hlsl
```
也就是说:
- `builtin/shaders/`:放“逻辑 shader 资产入口”
- `shaderlib/`:放“共享 include 库”
而不是继续维持“每个 shader 一个文件夹,文件名还重复一遍”的结构。
这更符合现在的真实资产形态,也更利于后续继续扩展 builtin shader 数量。
---
## 4. 下一阶段目标
下一阶段的目标不是做更多渲染效果,而是把 shader/material 底座继续正规化,达到可以稳定承接后续 SRP 的程度。
这一阶段的目标分成四件事:
1. 收口 builtin shader 资产布局。
2. 扩展 ShaderLab authoring 子集,继续向 Unity 靠拢。
3. 继续压缩 material 中残留的临时职责。
4. 让 renderer 对 pass / keyword / variant 的消费边界更正式。
---
## 5. 分阶段执行
### Phase ABuiltin Shader 资产布局拍平
目标:
-`engine/assets/builtin/shaders/*/* .shader` 收口成单层 `.shader` 文件布局。
- 同步清理 `BuiltinResources` 中的路径映射和命名。
工作项:
1. 拍平 builtin shader 文件路径。
2. 更新 `BuiltinResources.cpp/.h` 中的 builtin shader relative path 表。
3. 回归所有 builtin shader loader 测试。
4. 回归 editor / renderer 中依赖 builtin shader path 的测试。
完成标准:
- `engine/assets/builtin/shaders/` 单层化。
- 所有 builtin shader 路径 helper 仍稳定工作。
### Phase B扩展 ShaderLab authoring 子集
目标:
- 把当前 authoring 语法从“基础可用”推进到“真正像 Unity ShaderLab 的工程可用子集”。
优先支持:
- `BlendOp`
- `Offset`
- `Stencil`
- `UsePass`
- 更完整的 `Tags`
- 更稳的 `SubShader` 级状态继承与覆盖规则
工作项:
1. 扩 parser / IR。
2. 为新增语法补单测。
3. 为 builtin shader 和后续材质/渲染用例补回归用例。
完成标准:
- 这些语法不再停留在计划里,而是进入实际 parser / runtime contract。
### Phase CMaterial 契约继续收口
目标:
- 让 material 更接近 Unity 的角色定位:只管理 shader、properties、textures、keywords、必要的 render state override。
工作项:
1. 继续压缩 legacy `shaderPass` 的主路径影响范围。
2. 梳理 property 到 constant buffer 的稳定映射。
3. 梳理 keyword 集与 variant lookup 的契约边界。
4. 审查 material loader 中是否还存在对旧 shader 体系的隐式兼容假设。
完成标准:
- material 不再承担本应属于 renderer 的 pass 选择职责。
### Phase DRenderer 消费链继续正规化
目标:
- 让 renderer 更正式地围绕 `LightMode / pass contract / keywords / backend` 选用 pass 与 variant。
工作项:
1. 审查 builtin pipeline 中的 pass 选择逻辑。
2. 审查 keyword 参与 variant 选择与 pipeline cache 的路径。
3. 清理仍然依赖旧约定字符串兜底的代码。
完成标准:
- shader/material/runtime 三者的职责边界更加稳定,不再互相越界兜底。
---
## 6. 测试要求
这一阶段必须保持“每做一层就立刻回归”,不能再先堆实现后补测试。
至少要持续回归:
- `shader_tests`
- `material_tests`
- `editor_tests` 中 shader path / viewport render flow / overlay 相关用例
- `XCEditor` 编译
- 受影响的 rendering 单测与关键集成测试
如果 builtin shader 资产布局拍平,必须额外回归:
- builtin shader loader
- object-id / outline / grid / final-color / skybox 相关路径与运行时消费
---
## 7. 风险与控制
### 风险 1目录结构重构把路径引用打坏
控制策略:
- 先只拍平 builtin shader 主入口文件。
- `shaderlib` 不混入 `builtin/shaders` 同层迁移,避免一次改太多。
- 先跑 loader / editor path / renderer path 回归,再考虑下一层。
### 风险 2语法扩展过快把当前稳定 authoring 再次打回过渡态
控制策略:
- 只扩“明确服务于 Unity 风格主线”的语法。
- 不引入新的双路径兼容层。
- 任何新语法都必须先建测试,再接运行时。
### 风险 3material 与 renderer 职责再次混淆
控制策略:
- 每做一项都用“这件事在 Unity 里是谁负责”来校验职责归属。
---
## 8. 收口判定
满足下面条件时,这一阶段可以认为完成:
1. builtin shader 资产目录已经拍平到单层主入口结构。
2. `BuiltinResources` 与相关路径 helper 已同步完成。
3. ShaderLab authoring 子集新增一轮关键语法支持并有测试覆盖。
4. material 对旧路径的临时兼容进一步缩小。
5. renderer 的 pass / variant 消费逻辑进一步正规化。
6. shader / material / editor / XCEditor 回归全部稳定。
---
## 9. 下一步执行顺序
建议的实际执行顺序如下:
1. 先做 builtin shader 资产布局拍平。
2. 立刻回归 shader/material/editor 路径相关测试。
3. 再开始扩 ShaderLab 子集。
4. 然后收 material 与 renderer 的契约边界。
也就是说,**下一步最应该先做的不是再加语法,而是先把 builtin shader 资产布局收干净。**

View File

@@ -0,0 +1,506 @@
# Shader 与 Material 系统下一阶段计划
日期:`2026-04-03`
## 1. 阶段结论
当前 Renderer 这一轮主线已经完成收口,但完成的是“基础运行时闭环”,不是“最终的 Unity 风格 shader/material 体系”。
已经完成并应视为当前基线的内容:
- `Shader` 运行时契约已具备 `properties / passes / resources / backend variants`
- builtin shader 资源已经外置,运行时不再依赖 C++ 内嵌 fallback
- `Material` 对 builtin forward 的基础属性解析已经优先走 shader semantic
- `BuiltinForwardPipeline` 已按 shader pass `resources` 合约生成 pipeline layout 与 descriptor binding
- `Shader` 已接入 `AssetDatabase / Library` 流程shader import 会生成 `main.xcshader`
- `ShaderLoader` 已支持加载 `.xcshader` artifact
- shader manifest 依赖与 `Material -> Shader` 依赖已进入资产追踪链
- `rendering_unit_tests`
- `rendering_integration_textured_quad_scene`
- `rendering_integration_backpack_lit_scene`
- `shader_tests`
- `material_tests`
三后端验证当前是稳定的:
- D3D12通过
- OpenGL通过
- Vulkan通过
但这仍然只是“Shader / Material Runtime 的第一层骨架”。
当前真正还没有完成的是:
- Unity 风格的 shader authoring 入口
- 正式的 material schema / instance contract
- 从 shader property layout 到 GPU material layout 的通用映射
- 从 builtin forward 扩展到更通用 pass 的正式执行模型
## 2. 旧计划归档说明
以下两份计划文档已经完成历史使命,应归入 `docs/used/`
- `Renderer模块设计与实现.md`
- `Renderer下一阶段_ShaderMaterial与Pass体系设计.md`
原因不是它们“写错了”,而是:
- 第一份解决的是 Renderer 模块从无到有的问题,当前骨架已经落地
- 第二份解决的是“为什么下一阶段先做 shader/material/pass contract而不是 render graph”的阶段判断这份判断已经部分兑现整体已过期
本文件接手它们之后的主线,只保留对当前 checkout 仍然有效的目标。
## 3. 当前真实问题
### 3.1 Shader 运行时有了,但 authoring 还没有正式化
现在的运行时已经能消费:
- shader property
- pass tag
- pass resource binding
- backend variant
但作者侧仍然不是最终形态。
当前还缺:
- 面向用户的 Unity 风格 `.shader` 语法入口
- import 阶段把 authoring 语法转换为 runtime contract 的正式流程
- shader 资产与 Library artifact 的稳定产物边界
### 3.2 Material 仍偏“资源容器”,还不是正式材质实例系统
当前 `Material` 已有:
- shader 引用
- render state
- property / texture 覆盖
- tag / queue
但它还缺少真正用于 Renderer 执行的正式约束:
- 基于 shader property schema 的类型验证
- property 默认值与 override 的统一解析
- per-pass material constant layout
- texture / sampler / buffer 到 pass resource 的正式映射
- renderer 侧可缓存、可失效、可复用的 material binding plan
### 3.3 现有 pass contract 仍偏 builtin-forward 视角
当前 forward 主链已经能跑,但完整的 pass contract 还没有正式化为可扩展系统。
后续至少要能稳定承接:
- `ForwardLit`
- `Unlit`
- `DepthOnly`
- `ShadowCaster`
- `ObjectId`
否则后面一旦开始做阴影、深度预通道、更多 editor/runtime helper pass就会重新退化回 pipeline 内部的条件分支拼装。
### 3.4 三后端问题的本质不是“语法不同”,而是“资产如何统一”
当前真正要解决的,不是简单回答“到底用 GLSL 还是 HLSL”而是明确三层边界
1. 对外 authoring 语法是什么
2. import 后的内部运行时资产是什么
3. 每个 backend 最终执行的 variant 是什么
这三层不分开,后面一定会把 authoring、runtime、backend 编译链搅在一起。
## 4. 下一阶段的目标
下一阶段只做一件事:把 `Shader``Material` 从“能支撑当前 builtin forward 的运行时拼装”升级为“能长期承接 Unity 风格渲染架构的正式系统”。
### 4.1 对外 authoring 语法目标:严格向 Unity 对齐
最终对外公开的 shader 语法目标,必须与 Unity 的使用方式保持一致。
目标形态应当是:
- 单个 `.shader` 文件作为逻辑 shader 入口
- `Shader / Properties / SubShader / Pass` 的层级结构
- pass 内通过 `HLSLPROGRAM ... ENDHLSL` 或等价块组织代码
- 通过 `#pragma vertex` / `#pragma fragment` 指定 stage 入口
也就是说:
- 对外 authoring 视角应当是“Unity 风格的一体化 shader 文件”
- 不是要求作者直接去维护一堆 runtime JSON manifest
- 也不是让上层逻辑直接感知 D3D12/OpenGL/Vulkan 各自的底层差异
### 4.2 对内 runtime 资产目标:继续保留 contract 模型
虽然 authoring 目标要严格向 Unity 靠拢,但 runtime 不应直接拿 authoring AST 当执行数据。
运行时仍应落到清晰的 contract
```text
Shader Asset
-> Properties
-> Passes
-> Tags
-> Resource Bindings
-> Backend Variants
```
原因很直接:
- Renderer 需要稳定、扁平、可缓存的数据结构
- 三后端最终执行的仍然是 backend variant
- material schema 与 pass binding 都需要基于 import 结果,而不是原始文本
结论是:
- 外部写法要像 Unity
- 内部执行模型继续使用现在这套 runtime contract并进一步完善
### 4.3 Material 目标:从资源对象升级为正式材质实例
Material 下一阶段的核心不是“多支持几个 SetFloat”而是建立正式实例语义。
Material 至少要明确:
- 引用哪个 shader
- 使用哪个 pass 或 pass 策略
- 每个 property 的默认值、覆盖值、类型与序列化规则
- 每个 pass 对应的 material constant block 如何布局
- 每个 texture / sampler / buffer 如何映射到 pass resource
Renderer 侧则必须能把这些内容稳定编译成:
- material binding key
- material constant payload
- descriptor update plan
- pipeline compatibility key
## 5. 推荐架构
### 5.1 分成三层,不混写
推荐明确拆成三层:
```text
Unity-like Shader Authoring (.shader)
-> Shader Importer
-> Runtime Shader Contract
-> Backend Variants / Material Binding Plan
```
三层职责分别是:
- authoring 层:给人写、给 editor 看
- importer 层:把 authoring 语法转成稳定运行时资产
- runtime 层:给 renderer 执行、缓存、绑定、测试
### 5.2 Shader 的 public contract 与 backend contract 分离
下一阶段不建议把“Unity 风格语法”直接等同于“单源码自动跨平台编译已完全成熟”。
更务实的路线是:
- public contract 先统一成 Unity 风格 `.shader`
- importer 先产出统一 runtime contract
- backend variant 暂时仍允许按 backend 持有各自的编译输入或中间产物
这意味着:
- 作者看到的是统一 shader
- Renderer 消费的是统一 runtime contract
- backend 最终执行的仍然可以是不同 variant
这个分层既不违背 Unity 风格目标,也不会过早把工程拖进复杂的全平台 shader 编译链泥潭。
### 5.3 Vertex / Fragment 的外部写法按 Unity 组织,内部可拆分
对外语义上vertex / fragment 应当属于同一个 pass。
也就是说public authoring 角度要符合 Unity
- 一个 shader
- 一个或多个 subshader
- 一个或多个 pass
- 每个 pass 里通过 pragma 指定 vertex / fragment
但内部 import/runtime 完全可以把它们拆成:
- pass descriptor
- vertex stage variant
- fragment stage variant
外部合一,内部拆开,这是最稳妥的做法。
## 6. 下一阶段实施顺序
### 阶段 D0先打通 Shader Import / Artifact 基础设施(已完成)
这是当前 checkout 在 `2026-04-03` 已经完成的新增里程碑。
完成内容:
- `ShaderImporter` 已接管 `.shader / .hlsl / .glsl / .vert / .frag / .geom / .comp`
- shader import 结果会写入 `Library/Artifacts/.../main.xcshader`
- `ShaderLoader` 已支持直接读取 `.xcshader`
- shader manifest 中声明的 stage 源文件会进入依赖追踪
- `Material` 对引用 shader 的直接依赖也已进入依赖追踪
- `shader_tests``material_tests` 已覆盖 shader artifact 生成、加载与重导场景
这一步的意义不是“最终方案已完成”,而是先把 shader 纳入和 texture/material/mesh 一致的资产闭环。
没有这一步,后续不管做 Unity 风格 frontend还是做 material schema都会一直建立在“运行时临时解析源码”的不稳定基础上。
### 阶段 0当前基线确认
这部分已经完成,不再作为待办:
- runtime shader contract 已建立
- builtin forward 已按 pass resources 驱动
- 三后端渲染回归通过
### 阶段 A建立 Unity 风格 Shader Authoring Frontend
目标:
- 新增 Unity 风格 `.shader` authoring 入口
- importer 能解析最小闭环子集
第一批建议支持的子集:
- `Shader`
- `Properties`
- `SubShader`
- `Tags`
- `Pass`
- `HLSLPROGRAM / ENDHLSL`
- `#pragma vertex`
- `#pragma fragment`
交付标准:
- builtin `forward-lit`
- builtin `unlit`
- builtin `object-id`
- builtin `infinite-grid`
至少迁移其中一条主线并成功跑通三后端测试。
### 阶段 B建立正式的 Material Schema 与 Instance Contract
目标:
- shader importer 输出可供 material 消费的 property schema
- material 对 property override 做类型校验与默认值回退
- 为 pass 生成 material constant layout 与 resource mapping
交付标准:
- material 不再只靠 builtin alias 名字兜底
- shader property semantic 变成正式主路径,而不是兼容性补丁
- renderer 能从 shader schema 生成 material binding payload
当前建议把这一阶段作为下一步主线。
原因:
- shader artifact 与依赖追踪已经到位shader 现在可以作为稳定 schema 来源
- material 仍然缺少基于 shader property 的正式类型校验、默认值回退和资源映射
- renderer 目前虽然能消费 pass resources但 material binding 仍偏 builtin-forward 特判
当前进展(`2026-04-03`
- 已完成shader schema 驱动的 property 类型校验与默认值回退
- 已完成source `.material``properties` authoring 入口
- 已完成material constant layout runtime contract
- `Material` 现在会生成正式的 constant layout 元数据
- layout 字段包含 `name / type / offset / size / alignedSize`
- renderer 读取的已不再只是裸字节 payload而是 `layout + payload` 组合
- 已完成builtin pass resource mapping / material binding plan runtime contract
- `RenderMaterialUtility` 现在统一提供 `PassResourceBindingLocation / BuiltinPassResourceBindingPlan`
- 显式 shader pass `resources` 与 legacy builtin forward fallback 已走同一套解析与校验路径
- `BuiltinForwardPipeline` 已改为消费通用 binding plan而不是继续内联 forward 特判绑定逻辑
- 已验证:`rendering_unit_tests` 57/57`material_tests` 51/51
- 下一步:把这套 pass binding plan 继续推到 `Unlit / ObjectId` 等 pass收敛成真正共享的 shader/material 执行边界
### 阶段 C把 Pass Binding 扩展为正式材质执行链路
目标:
- 不只是 builtin forward 能吃 pass resources
- `Unlit``ObjectId` 也逐步切到同一套 shader/material contract
- pipeline state key 与 descriptor binding plan 从“按功能写逻辑”升级到“按 shader pass contract 解析”
交付标准:
- 至少 `ForwardLit + Unlit + ObjectId` 共用同一套 shader/material 执行边界
- 新增 pass 不再默认要求先写一套新的硬编码 binding 路径
当前进展(`2026-04-04`
- 已完成builtin `ObjectId` pass 接入通用 pass binding plan
- builtin object-id shader 已显式声明 `PerObject` 资源合约
- `BuiltinObjectIdPass` 已改为消费通用 binding plan不再硬编码 `set0/binding0` 常量布局
- 显式 shader `resources` 与 legacy object-id fallback 现在走同一套解析与校验路径
- 已完成builtin `Unlit` shader / pipeline 主线接入共享执行边界
- 新增 builtin `unlit` shader 资产与 `BuiltinResources` 入口
- `BuiltinForwardPipeline` 现在会在 `ForwardLit + Unlit` 之间按 material/shader metadata 解析目标 pass
- `Unlit``ForwardLit` 现在共用同一套 input layout、material schema、binding plan 与 descriptor 组装路径
- 已完成:抽出 `ForwardLit / Unlit / ObjectId` 共用的 pass layout / descriptor set 组装骨架
- `RenderMaterialUtility` 现在统一提供 `BuiltinPassSetLayoutMetadata``TryBuildBuiltinPassSetLayouts(...)`
- `BuiltinForwardPipeline``BuiltinObjectIdPass` 现在都复用同一套 `binding plan -> set layout -> pipeline layout` 组装路径
- forward 侧只保留 set0 compatibility fallback 与 draw/update 逻辑object-id 侧只保留自身约束校验与 per-object 常量写入
- 已完成builtin `DepthOnly / ShadowCaster` shader 与独立 pass skeleton 落地
- 新增 builtin `depth-only``shadow-caster` shader 资产,以及 `BuiltinResources` 对应入口
- 新增 `BuiltinDepthOnlyPass / BuiltinShadowCasterPass`,作为独立 `RenderPass` 复用同一套 shared pass-layout skeleton
- 两个 pass 当前先收敛到 `PerObject` 常量路径opaque 物体走 builtin fallback`ShadowCaster` 额外尊重 `MeshRenderer.castShadows`
- 这一步解决的是“pass contract 与执行骨架缺失”,还没有把 shadow map / light-space request flow 一次性做完
- 已完成:`CameraRenderRequest + CameraRenderer` 正式接入 `DepthOnly / ShadowCaster` request 流程
- 新增 `depthOnly / shadowCaster` request支持独立 surface、clear flags / clear color以及可选 `RenderCameraData` override
- `CameraRenderer` 现在按 `ShadowCaster -> DepthOnly -> Forward -> ObjectId` 的顺序执行这些请求,`BuiltinDepthStylePassBase` 也会按 request clear flags 清理目标
- 已验证:`rendering_unit_tests` 73/73
- 已验证:`rendering_integration_textured_quad_scene` 3/3D3D12 / OpenGL / Vulkan
- 已验证:`rendering_integration_unlit_scene` 3/3D3D12 / OpenGL / Vulkan
- 已验证:`rendering_integration_object_id_scene` 3/3D3D12 / OpenGL / Vulkan
- 下一步:如果继续沿 renderer 主线收口,优先补 `DepthOnly / ShadowCaster` 的真实 cross-backend integration coverage并决定是否把 shadow-map 结果继续接回 forward lighting 消费链如果先控制范围request 流程这一块已经收口
### 阶段 D扩展 AssetDatabase / Library Artifact 能力
目标:
- 在已完成的 shader artifact 基础上,继续扩展 import 产物边界
- backend variant 的编译输入、中间产物或缓存策略进入 `Library/Artifacts`
- 为后续 Unity 风格 `.shader` frontend 预留稳定 importer 输出层
交付标准:
- 资源改动能够稳定触发 shader/material 重新导入
- editor/runtime 读取的是 import 后资产,不是源码临时解析
- shader importer 不再只服务当前 JSON manifest 兼容路径,也能承接下一步 authoring frontend
### 阶段 E测试与回归收口
目标:
- 给 shader importer、material schema、binding plan 增加 unit tests
- 对 forward/unlit/object-id 增加 integration coverage
- 保持 D3D12 / OpenGL / Vulkan 一致回归
最低验证集:
- `shader_tests`
- `material_tests`
- `rendering_unit_tests`
- `rendering_integration_textured_quad_scene`
- `rendering_integration_backpack_lit_scene`
必要时新增:
- `rendering_integration_unlit_scene`
- `rendering_integration_object_id_scene`
当前进展(`2026-04-04`
- 已完成:`rendering_integration_unlit_scene`
- 显式使用 builtin `unlit` shader + `Unlit` pass覆盖 `BuiltinForwardPipeline``ForwardLit / Unlit` pass 选择路径
- 复用 `textured_quad_scene` 构图做最小差异回归,验证 shader/material 新 contract 不改变既有画面输出
- 已验证:`rendering_integration_unlit_scene`
- D3D12通过
- OpenGL通过
- Vulkan通过
- 已完成:`rendering_integration_object_id_scene`
- 新增独立的 object-id integration scene直接验证 object-id 输出采样点,而不是再维护一张新的大尺寸 GT 图片
- 覆盖 `CameraRenderer + BuiltinObjectIdPass` 路径,以及 `Forward -> ObjectId -> Copy/Screenshot` 的跨 pass 回归
- 修正了 `BuiltinObjectIdPass` 在 Vulkan 下的顶点输入步长问题,并让 object-id pass 自己清理/写入 depth避免依赖前一 pass 的 depth 复用状态
- 已验证:`rendering_integration_object_id_scene`
- D3D12通过
- OpenGL通过
- Vulkan通过
- 阶段 E 当前状态:`unlit_scene``object_id_scene` 均已完成并通过三后端验证,本阶段可以收口
## 7. 当前阶段明确不做
下一阶段不应把范围扩散到下面这些方向:
- render graph
- shader graph
- 全平台单源码自动转译一次性做完
- 完整 SRP scripting API
- 大规模后处理框架
这些都依赖 shader/material 正式体系先稳定下来。
## 8. 成功标准
这个阶段完成时,应该满足下面几个判断:
- 作者侧已经可以写 Unity 风格的 `.shader`
- runtime 已不再依赖手写 JSON manifest 才能描述 pass contract
- material 能基于 shader schema 做正式绑定,而不是 builtin 特判兜底
- 至少 `ForwardLit / Unlit / ObjectId` 三类 pass 共用统一 shader/material 执行边界
- 三后端回归测试仍稳定通过
## 9. 一句话总结
下一阶段不是继续给 builtin forward 打补丁,而是把 `Shader``Material` 正式提升为 Unity 风格渲染架构中的稳定中层资产与执行契约。
## 10. 快速收口策略(`2026-04-04`
目标收窄为只处理 `shader / material` 核心主线不继续扩散到完整阴影功能、render graph、shader graph 或 editor 外围能力。
按下面顺序收口:
1. 先完成 Unity-like `.shader` authoring MVP importer
- 允许最小子集:`Shader / Properties / SubShader / Tags / Pass / HLSLPROGRAM / #pragma vertex / #pragma fragment`
- importer 输出继续复用当前 runtime shader contract`properties / passes / resources / backend variants`
- 这一阶段不追求完整 Unity ShaderLab只做 builtin 与主线材质系统需要的最小闭环
2. 再迁移 builtin shader 到新 authoring 入口
- 优先 `ForwardLit / Unlit / ObjectId / DepthOnly / ShadowCaster`
- 要求 importer 产出的 runtime contract 与当前 renderer 消费路径保持一致
3. 然后收紧 material 主路径
- 以 imported shader schema 为主路径完成 property 类型校验、默认值回退、constant layout 与 resource mapping
- builtin alias / canonical-name fallback 只保留兼容兜底,不再作为主执行路径
4. 最后做最小回归集收口
- `shader_tests`
- `material_tests`
- `rendering_unit_tests`
- 必要的 rendering integration smoke
当前进展(`2026-04-04`
- 已完成Step 1 `Unity-like .shader authoring MVP importer`
- `ShaderLoader` 新增 Unity-like `.shader` authoring 识别与解析入口,但保留现有 JSON manifest `.shader` 兼容路径不动
- importer 继续落到现有 runtime shader contract`properties / passes / resources / backend variants`
- `CollectSourceDependencies` 已覆盖新 authoring 路径,`AssetDatabase` 会继续追踪各 backend stage 文件依赖并参与重导入
- 已完成Step 2 `builtin shader 迁到新 authoring 入口`
- `forward-lit / unlit / object-id / depth-only / shadow-caster` 五个 builtin `.shader` 入口已全部切到 Unity-like authoring
- stage 源文件、builtin shader 路径与 renderer 消费 contract 保持不变,迁移只发生在 authoring 入口层
- 补充 `DepthOnly / ShadowCaster` builtin shader loader 覆盖,确保五类 builtin pass 都经过新 authoring 路径验证
- 已完成Step 3 `material 主路径收紧到 imported shader schema`
- `MaterialLoader` 在存在 shader schema 时,`properties / textures` 中的旧 key 会先解析到 shader property semantic再落到 shader 正式属性名
- 旧的 `baseColor / baseColorTexture` 等兼容 key 仍可导入,但只作为兼容输入存在,不再直接污染 material 主执行路径
- 当 material 绑定 shader schema 后,未知 texture binding 现在会被显式拒绝,不再静默忽略
- 已验证:`shader_tests` 中新增 authoring 直载与 artifact/reimport 覆盖
- 已验证:`shader_tests` 31/31 通过builtin `ForwardLit / Unlit / ObjectId / DepthOnly / ShadowCaster` 全部通过加载与 backend variant 覆盖
- 已验证:`material_tests` 53/53 通过schema 驱动的 property/texture 映射与未知 binding 拒绝路径都已覆盖
- 已完成Step 4 `最小回归集收口`
- `rendering_unit_tests` 73/73 通过builtin pass contract 与 renderer 侧消费路径在当前重构后保持稳定
- 本轮最小回归集结果:`shader_tests` 31/31`material_tests` 53/53`rendering_unit_tests` 73/73
- 以当前目标范围看,`shader / material` 核心主线已经可以阶段性收口
- 补充验收(`2026-04-04`
- 补跑 integration smoke 时发现并修复了一处真实回归Unity-like `.shader` authoring 将 HLSL 的 `MainVS / MainPS` 入口错误套到了 GLSL/Vulkan variant上层表现为 Vulkan `BuiltinForwardPipeline` 建 pipeline 失败
- 修复后补跑 `rendering_integration_textured_quad_scene``rendering_integration_unlit_scene``rendering_integration_object_id_scene`,三者在 `D3D12 / OpenGL / Vulkan` 下均通过
- 额外补跑 `rendering_integration_backpack_lit_scene`暴露出一条相邻但不同范围的问题direct `MeshLoader` 导入的 mesh/material/texture 生命周期路径存在异常退出/不干净收尾,已超出本次 `shader / material contract` 收口范围
- 因此本计划按“核心主线已收口,附带一条相邻 residual risk”归档若后续继续补强优先单独开一轮处理 `MeshLoader + imported subresource lifetime`
- 下一步:从当前目标范围出发,本计划可归档;后续如继续推进,请以新计划承接 `backpack_lit_scene` 这条相邻问题
当前阶段明确不做:
- 完整阴影贴图消费链
- render graph
- shader graph
- 完整 Unity ShaderLab 全语法
- 与 shader/material 主线无关的 editor/ui 扩展

View File

@@ -0,0 +1,48 @@
# Subplan 01XCUI Core Tree / State / Invalidation
目标:
- 搭出 XCUI 的 retained-mode 核心骨架。
- 明确 `ElementTree``NodeId``View``ViewModel``dirty flag``rebuild``lifecycle` 的最小闭环。
负责人边界:
- 负责 `engine/include/XCEngine/UI/``engine/src/UI/Core/` 的核心树模型。
- 不负责具体布局算法。
- 不负责 ImGui 适配绘制。
建议目录:
- `engine/include/XCEngine/UI/Core/`
- `engine/src/UI/Core/`
- `tests` 中对应 XCUI core 测试文件
前置依赖:
- 依赖主线完成 `Phase 0` 的基础类型和 UI 生命周期边界清理。
现在就可以先做的内容:
- 设计 `UIElementId` / `UIElement` / `UIContext` / `UIBuildContext`
- 设计 dirty 标记与增量重建规则
- 设计 ViewModel 读写边界和 command 回调入口
- 写最小 tree rebuild 测试
明确不做:
- 不接入 `.xcui` 文件
- 不接入 editor 面板
- 不写具体 widget 大库
交付物:
- XCUI core 基础类与生命周期定义
- tree rebuild / invalidation / state propagation 单元测试
- 一个最小 demo代码构建 UI tree 并触发一次增量更新
验收标准:
- 可以构建一棵稳定的 UI tree
- 局部状态变化时只标脏必要节点
- 重建逻辑与布局/渲染解耦
- 其他 subplan 可以基于该模块定义控件树和状态更新

View File

@@ -0,0 +1,46 @@
# Subplan 03XCUI Style / Theme / Token
目标:
- 建立 XCUI 的样式模型、token 体系与主题覆盖规则。
- 让控件视觉不再散落在代码硬编码常量里。
负责人边界:
- 负责 `Style` / `Theme` / `Token` 数据模型和解析规则。
- 不负责 `.xcui` 导入器。
- 不负责最终 renderer 具体绘制。
建议目录:
- `engine/include/XCEngine/UI/Style/`
- `engine/src/UI/Style/`
- `tests` 中 style/theme 测试
前置依赖:
- 依赖 `Subplan 01` 的节点属性注入点。
现在就可以先做的内容:
- 设计 style 层级:默认样式、类型样式、命名样式、局部覆盖
- 设计 token颜色、圆角、边距、字号、线宽
- 设计主题切换与 token 查询接口
- 写冲突优先级测试
明确不做:
- 不做具体面板视觉重构
- 不做字体资源导入
交付物:
- 统一样式查询入口
- `.xctheme` 对应的数据结构
- 样式优先级与 token 解析测试
验收标准:
- 样式优先级可预测
- 主题替换不需要改控件逻辑
- 其他 subplan 能通过统一 API 获取视觉参数

View File

@@ -0,0 +1,46 @@
# Subplan 06XCUI Markup / Import / Hot Reload
目标:
-`.xcui` / `.xctheme` / `.xcschema` 拉进资源系统。
- 建立导入、编译产物、热重载、诊断输出的第一版链路。
负责人边界:
- 负责资源类型、导入器、artifact、诊断日志。
- 不负责 widget 运行时逻辑本身。
建议目录:
- `engine/include/XCEngine/Resources/UI/`
- `engine/src/Resources/UI/`
- `editor/src` 中与导入面板、诊断输出相关的接入口
前置依赖:
- 需要主计划中的资源类型命名拍板。
-`Subplan 03``Subplan 07` 协调格式字段。
现在就可以先做的内容:
- 定义三类资源描述结构
- 设计导入错误诊断格式
- 设计热重载触发和缓存失效策略
- 先做一个最小 parser可以把简单 `.xcui` 编成中间结构
明确不做:
- 不做完整 markup 语法大全
- 不做 inspector 的最终渲染
交付物:
- UI 资源类型定义
- 导入器与 artifact 结构
- 热重载与错误输出最小闭环
验收标准:
- UI 资源可被 ResourceManager 识别
- 导入失败时有可读诊断
- 改动文件后可触发重新加载

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,62 @@
# Unity式 Tick 系统与 Play Mode 运行时方案阶段进展
日期2026-04-02
## 已完成
### 阶段 A
- 已接入 `RuntimeLoop`,统一承载 `FixedUpdate / Update / LateUpdate`
- 已接入 `PlaySessionController`
- 已实现 `Play / Stop`
- Play 时运行 runtime scene clone
- Stop 时恢复 editor scene snapshot
- `Run` 菜单与 `F5` 已可切换 `Play / Stop`
### 阶段 B 当前收口
- 明确区分“文档级编辑”和“运行态场景对象编辑”
- `New/Open/Save Scene``New/Open/Save Project` 仍只允许在 `Edit` 下执行
- `Play / Paused` 下允许对 runtime scene 进行对象级编辑与 `Undo / Redo`
- runtime scene 的对象改动默认不再污染场景文档 dirty 状态
### 阶段 C 当前收口
- 已补全 `Pause / Resume / Step` 的完整请求与状态切换
- `Run` 菜单现在区分 `Play/Stop``Pause/Resume``Step`
- `Error Pause` 已接入正式 Pause 请求通道
- `Paused` 下维持 runtime world不回退到 editor scene
- `Step` 现在只在 `Paused` 下有效,并保持 `Paused` 状态不变
### 阶段 D 当前收口
- 已在软件顶部增加独立运行栏
- 运行栏已接入 `Play / Pause / Step` 三个图标按钮
- 顶部按钮直接复用现有 PlayMode 请求通道,不额外分叉状态机
- `Play` 按钮在运行中会保持高亮,再次点击即 `Stop`
- `Pause``Play / Paused` 下可用,并沿用现有 `F6`
- `Step` 仍只在 `Paused` 下可用
- 顶部栏已改为参与 dockspace 布局,不再覆盖 Scene / Hierarchy / Inspector 面板标题区
## 本轮验证
- 已重新执行 `cmake -S . -B build`
- 已通过 `cmake --build build --config Debug --target scene_tests`
- 已通过 `cmake --build build --config Debug --target editor_tests -- /m:1 /v:minimal`
- 已通过 `cmake --build build --config Debug --target XCEditor -- /m:1 /v:minimal`
- 已通过聚焦测试:
`ctest --test-dir build -C Debug --output-on-failure -j1 -R "RuntimeLoopTest|PlaySessionControllerTest|EditorActionRoutingTest.*PlayMode|EditorActionRoutingTest.*MainMenuRouterRequestsPlayPauseResumeAndStepEvents"`
## 当前语义
- `editor tick` 负责托管运行时会话
- `engine tick` 负责推进 runtime world
- Play 时 `Hierarchy / Inspector / SceneView / GameView` 面对的是同一份 runtime world
- Play 中对对象的改动默认是临时运行态改动Stop 后回滚
- Play 中禁止的是文档切换与文档保存,不是禁止观察或编辑 runtime clone
## 下一阶段建议
- 明确 `Paused` 下的 `Undo / Redo / Gizmo / Inspector` 更细粒度交互边界
- 将 GameView 输入正式接入 runtime input 通道
- 继续补 `Simulate` 与更完整的 Time 语义

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,140 @@
# XCUI Input / Focus / Shortcut Subplan 完成归档
日期:`2026-04-04`
## 1. 归档结论
`Subplan-04` 在其原始定义边界内已经完成,可以归档。
这里的“完成”指的是:
- 已建立 XCUI 输入事件基础模型
- 已建立焦点、激活路径、指针捕获路径三套状态管理
- 已建立 capture / target / bubble 三阶段输入路由
- 已建立 shortcut scope 与命令匹配机制
- 已建立统一的 `UIInputDispatcher`
- 已补齐最小单元测试并完成通过验证
这里的“完成”不包括:
- Win32 原生消息采集
- ImGui / Editor 侧的输入桥接
- 文本输入控件级别的 IME 细节
这些内容本来就不在 `Subplan-04` 的负责边界里,后续应由 `Subplan-05``Subplan-08``Subplan-09` 等继续接手。
## 2. 本次落地内容
### 2.1 输入事件模型
已扩展 `UIInputEvent`
- `PointerEnter`
- `PointerLeave`
- `pointerId`
- `timestampNanoseconds`
- `repeat`
- `synthetic`
相关文件:
- `engine/include/XCEngine/UI/Types.h`
### 2.2 焦点与路径模型
已补齐:
- `UIElementId`
- `UIInputPath`
- `UIFocusController`
- `UIFocusChange`
相关文件:
- `engine/include/XCEngine/UI/Input/UIInputPath.h`
- `engine/include/XCEngine/UI/Input/UIFocusController.h`
- `engine/src/UI/Input/UIInputPath.cpp`
- `engine/src/UI/Input/UIFocusController.cpp`
### 2.3 Shortcut 系统
已补齐:
- `UIShortcutScope`
- `UIShortcutChord`
- `UIShortcutBinding`
- `UIShortcutRegistry`
- shortcut scope 优先级匹配规则
相关文件:
- `engine/include/XCEngine/UI/Input/UIShortcutRegistry.h`
- `engine/src/UI/Input/UIShortcutRegistry.cpp`
### 2.4 输入路由与统一分发器
已补齐:
- `UIInputRouter`
- `UIInputRoutingPlan`
- `UIInputRoutingStep`
- `UIInputDispatcher`
相关文件:
- `engine/include/XCEngine/UI/Input/UIInputRouter.h`
- `engine/include/XCEngine/UI/Input/UIInputDispatcher.h`
- `engine/src/UI/Input/UIInputRouter.cpp`
- `engine/src/UI/Input/UIInputDispatcher.cpp`
## 3. 测试与验证
新增测试:
- `tests/Input/test_xcui_input_dispatcher.cpp`
已完成验证:
- `cmake --build build --config Debug --target input_tests`
- `ctest -C Debug -R "XCUI.*" --output-on-failure`
验证结果:
- `6 / 6` 通过
覆盖点包括:
- focus path 切换
- capture path 优先级
- keyboard routed path 顺序
- shortcut scope 匹配优先级
- pointer down / pointer up 对 active path 的影响
- shortcut 命中后优先消费、跳过普通 routing
## 4. 对后续 subplan 的可复用输出
当前已经可以被后续直接依赖的稳定入口:
- `XCEngine::UI::UIInputPath`
- `XCEngine::UI::UIFocusController`
- `XCEngine::UI::UIShortcutRegistry`
- `XCEngine::UI::UIInputRouter`
- `XCEngine::UI::UIInputDispatcher`
后续建议对接方式:
- `Subplan-05`:负责把 ImGui/平台输入桥接进这套 dispatcher
- `Subplan-08`:负责把 menu / dock / panel shell 的 shortcut scope 接进 registry
- `Subplan-09`:负责把 viewport shell 的 pointer / focus / capture 接进 routing
## 5. 原 subplan 文件
原始 subplan 文件已从活跃 `xcui-subplans` 目录移出。
当前这份文件就是 `Subplan-04` 的最终归档版本。
其状态应视为:
- 已完成
- 已归档
- 不再作为活跃开发计划继续扩写

View File

@@ -0,0 +1,93 @@
# XCUI Subplan 01Core Tree / State / Invalidation
归档日期:
- `2026-04-04`
状态:
- 已完成
本次实际完成内容:
- 新增 XCUI core 基础契约:`UIElementId``UIDirtyFlags``IUIViewModel``RevisionedViewModelBase`
- 新增 retained-mode build 层:`UIBuildElementDesc``UIBuildList``UIBuildContext`
- 新增 retained-mode tree 层:`UIElementTree``UIElementNode``UIElementTreeRebuildResult`
- 新增统一入口:`UIContext`
- 实现最小闭环tree rebuild、dirty flag 标记、layout dirty 向祖先传播、dirty root 收集
- 新增并验证 UI core 测试tree 创建、unchanged rebuild、local state invalidation、view model invalidation、structure change、未闭合 build scope 失败
本次涉及文件:
- `engine/include/XCEngine/UI/Types.h`
- `engine/include/XCEngine/UI/Core/UIInvalidation.h`
- `engine/include/XCEngine/UI/Core/UIViewModel.h`
- `engine/include/XCEngine/UI/Core/UIBuildContext.h`
- `engine/include/XCEngine/UI/Core/UIElementTree.h`
- `engine/include/XCEngine/UI/Core/UIContext.h`
- `engine/src/UI/Core/UIBuildContext.cpp`
- `engine/src/UI/Core/UIElementTree.cpp`
- `tests/core/UI/CMakeLists.txt`
- `tests/core/UI/test_ui_core.cpp`
验证结果:
- `cmake --build . --config Debug --target core_ui_tests`
- `ctest -C Debug --output-on-failure -R UICoreTest --test-dir .`
- 结果:`6/6` 通过
当前结论:
- `Subplan 01` 的最小 retained-mode core 已经可用
- 后续 `Subplan 03/05/06/07/08/09` 可以基于这套 core 继续推进
原始 subplan 内容归档如下:
# Subplan 01XCUI Core Tree / State / Invalidation
目标:
- 搭出 XCUI 的 retained-mode 核心骨架。
- 明确 `ElementTree``NodeId``View``ViewModel``dirty flag``rebuild``lifecycle` 的最小闭环。
负责人边界:
- 负责 `engine/include/XCEngine/UI/``engine/src/UI/Core/` 的核心树模型。
- 不负责具体布局算法。
- 不负责 ImGui 适配绘制。
建议目录:
- `engine/include/XCEngine/UI/Core/`
- `engine/src/UI/Core/`
- `tests` 中对应 XCUI core 测试文件
前置依赖:
- 依赖主线完成 `Phase 0` 的基础类型和 UI 生命周期边界清理。
现在就可以先做的内容:
- 设计 `UIElementId` / `UIElement` / `UIContext` / `UIBuildContext`
- 设计 dirty 标记与增量重建规则
- 设计 ViewModel 读写边界和 command 回调入口
- 写最小 tree rebuild 测试
明确不做:
- 不接入 `.xcui` 文件
- 不接入 editor 面板
- 不写具体 widget 大库
交付物:
- XCUI core 基础类与生命周期定义
- tree rebuild / invalidation / state propagation 单元测试
- 一个最小 demo代码构建 UI tree 并触发一次增量更新
验收标准:
- 可以构建一棵稳定的 UI tree
- 局部状态变化时只标脏必要节点
- 重建逻辑与布局/渲染解耦
- 其他 subplan 可以基于该模块定义控件树和状态更新

View File

@@ -0,0 +1,50 @@
# XCUI Subplan 02Layout Engine 完成归档
归档日期:
- `2026-04-04`
原始来源:
- [../XCUI完整架构设计与执行计划.md](../XCUI完整架构设计与执行计划.md)
本次完成范围:
- 落地 XCUI 纯算法布局基础类型:
- `UILayoutLength`
- `UILayoutConstraints`
- `UILayoutThickness`
- `UILayoutItem`
- `UIStackLayoutOptions`
- `UIOverlayLayoutOptions`
- 落地 measure / arrange 双阶段布局算法
- 实现 `Horizontal Stack` / `Vertical Stack` / `Overlay` 三类 MVP 容器
- 支持 `px / content / stretch`
- 支持 `padding / spacing / margin / min / max / alignment`
- 建立独立 `ui_tests` 测试目标并通过验证
实际代码落点:
- [engine/include/XCEngine/UI/Types.h](D:/Xuanchi/Main/XCEngine/engine/include/XCEngine/UI/Types.h)
- [engine/include/XCEngine/UI/Layout/LayoutTypes.h](D:/Xuanchi/Main/XCEngine/engine/include/XCEngine/UI/Layout/LayoutTypes.h)
- [engine/include/XCEngine/UI/Layout/LayoutEngine.h](D:/Xuanchi/Main/XCEngine/engine/include/XCEngine/UI/Layout/LayoutEngine.h)
- [tests/Core/Math/CMakeLists.txt](D:/Xuanchi/Main/XCEngine/tests/Core/Math/CMakeLists.txt)
- [tests/Core/Math/test_ui_layout.cpp](D:/Xuanchi/Main/XCEngine/tests/Core/Math/test_ui_layout.cpp)
验证结果:
- `cmake --build . --config Debug --target math_tests -- /m:1`
- `ctest -C Debug --test-dir D:\\Xuanchi\\Main\\XCEngine\\build\\tests\\Core\\Math --output-on-failure -R UI_Layout`
- 结果:`5/5 UI_Layout tests passed`
与原子计划相比,当前仍未覆盖:
- `Scroll` 容器
- 更复杂的主轴分布策略
- 与 XCUI tree/state 的正式对接
- 文本测量与真实控件树集成
建议后续承接:
-`Subplan-01` 提供 tree / node / invalidation 契约后,把当前布局算法接入正式 UI tree
- 后续再补 `Scroll`、更完整容器族、文本测量桥接

View File

@@ -0,0 +1,83 @@
# XCUI Subplan 05: ImGui Transition Backend
归档日期:
- `2026-04-04`
状态:
- 已完成
本次实际完成内容:
- 新增 XCUI 绘制数据契约:`UIColor``UIDrawCommandType``UIDrawCommand``UIDrawList``UIDrawData`
- 新增 `ImGuiTransitionBackend` 过渡后端,支持 `FilledRect``RectOutline``Text``Image``PushClipRect``PopClipRect`
- 新增最小 editor 接入样例 `XCUIDemoPanel`,用于在现有编辑器壳层中演示 XCUI draw data 到 ImGui draw call 的过渡链路
- 将 demo panel 接入 editor workspace并补齐 editor/tests 构建入口
- 新增 Subplan-05 配套测试,覆盖 draw data 聚合与 backend flush 行为
本次涉及文件:
- `editor/CMakeLists.txt`
- `editor/src/Core/EditorWorkspace.h`
- `editor/src/XCUIBackend/ImGuiTransitionBackend.h`
- `editor/src/panels/XCUIDemoPanel.cpp`
- `editor/src/panels/XCUIDemoPanel.h`
- `engine/include/XCEngine/UI/DrawData.h`
- `tests/editor/CMakeLists.txt`
- `tests/editor/test_xcui_draw_data.cpp`
- `tests/editor/test_xcui_imgui_transition_backend.cpp`
验证结果:
- `cmake --build . --config Debug --target editor_tests -- /m:1 /p:CL_MPCount=1`
- `ctest -C Debug -R "XCUIDrawDataTest|XCUIImGuiTransitionBackendTest" --output-on-failure`
- 结果:`4/4` 通过
- `cmake --build . --config Debug --target XCEditor -- /m:1 /p:UseMultiToolTask=false /p:CL_MPCount=1`
- 结果:通过
提交记录:
- `75ded6f` `Add XCUI ImGui transition backend MVP`
当前结论:
- `Subplan-05` 的最小过渡后端已经可用,可以作为 XCUI 在 editor 中落地的第一层渲染适配桥
- XCUI 逻辑层仍然不直接依赖 ImGui APIImGui 仅存在于过渡 backend 和 editor 接入层
- 后续 `Subplan-08``Subplan-09` 可以直接基于这套 draw data 和 transition backend 继续推进
原始 subplan 内容归档如下:
# Subplan 05XCUI ImGui Transition Backend
目标:
- 在过渡阶段,让 ImGui 只承担宿主窗口和 draw submission 容器的职责
- 由 XCUI 自己生成 draw list再交给 ImGui backend 落屏
负责人边界:
- 负责 `editor/src/XCUIBackend/` 或等价新目录
- 负责 XCUI draw primitive 到 ImGui draw call 的映射
- 不负责 XCUI tree、布局、样式的内部规则
建议目录:
- `editor/src/XCUIBackend/`
- `editor/src/UI/` 中与 XCUI backend 直接相关的桥接代码
- `tests/Editor` 中 backend 相关测试
前置依赖:
- 需要 `Subplan-01` 给出稳定 draw data 和 frame submission 契约
- 需要 `Subplan-03` 提供样式查询结果
现在就可以先做的内容:
- 定义 `UIDrawList` / `UIDrawCommand` / `UIDrawText` / `UIDrawImage` / `UIDrawClip`
- 先做矩形、边框、文字、图片四类 primitive
- 设计 frame begin / submit / end 的 adapter 流程
- 写一个最小 demo panel用 XCUI draw list 通过 ImGui 显示
明确不做:
- 不做 RHI native backend
- 不做 docking 逻辑
交付物:
- XCUI 到 ImGui 的过渡 backend
- primitive 转换测试或快照测试
- 最小 editor 接入样例
验收标准:
- XCUI 逻辑层不直接依赖 ImGui API
- ImGui 只出现在 backend 适配层
- 可以渲染基础控件和文本