# MetaCore 模型工作流 P0 实施计划 生成时间:2026-04-11 状态:执行稿 范围:Task 06 / 01 / 03 / 02 / 04 / 05 ## 目的 这份文档把 [metacore-model-workflow-p0-task-cards.md](D:/MetaCore/docs/designs/metacore-model-workflow-p0-task-cards.md) 再往下压一层,直接落到: - 要改哪些状态 - 要加哪些接口 - 哪些面板负责什么 - 每一步怎么验收 目标是让后续实现阶段尽量少临场改设计。 ## 推荐实施顺序 建议严格按下面顺序推进: 1. Task 06:资源选择状态统一 2. Task 01:Project 面板最小版 3. Task 03:模型资源 Inspector 最小版 4. Task 02:模型 / Prefab 拖拽到 Scene / Hierarchy 5. Task 04:对象材质槽编辑 6. Task 05:材质资源 Inspector 最小版 原因: - 没有独立资源选择状态,Project 面板和 Inspector 没法稳 - 没有 Project 面板,后面的资源拖拽和资源 Inspector 都无从谈起 - 没有模型资源 Inspector,资源选中就没有价值 - 材质槽编辑和材质资源编辑必须等资源选择主链稳定后再上 --- ## Step 1:资源选择状态统一 ### 目标 让编辑器同时理解两套不同的选择: - 场景对象选择 - 资源选择 并明确 Inspector 当前展示哪一种。 ### 当前问题 目前编辑器核心状态明显偏向对象选择: - `Hierarchy` - `Scene View` - `Inspector` 基本都围绕 `GameObject` 选中展开。 但一旦引入 `Project` 面板,编辑器必须明确: - 选中资源时,Inspector 显示资源 - 选中对象时,Inspector 显示对象 ### 建议改动 #### A. 在 `MetaCoreEditorContext` 中新增资源选择状态 建议新增最小状态: - `std::optional SelectedAssetGuid` - `std::filesystem::path SelectedAssetPath` - `std::string SelectedAssetType` 也可以封成: ```cpp struct MetaCoreSelectedAssetState { MetaCoreAssetGuid AssetGuid{}; std::filesystem::path RelativePath{}; std::string AssetType{}; bool Valid = false; }; ``` #### B. 新增最小 API 建议在 [MetaCoreEditorContext.h](/D:/MetaCore/Source/MetaCoreEditor/Public/MetaCoreEditor/MetaCoreEditorContext.h) 增加: - `void ClearSelectedAsset();` - `void SelectAsset(const MetaCoreAssetRecord& record);` - `bool HasSelectedAsset() const;` - `const MetaCoreSelectedAssetState& GetSelectedAsset() const;` #### C. 明确 Inspector 模式 建议增加一个轻量枚举: ```cpp enum class MetaCoreInspectorTargetKind { None = 0, SceneObject, Asset }; ``` 由 `EditorContext` 决定当前 Inspector 看谁。 #### D. 事件广播 当前已有 `MetaCoreEditorEventBus`,建议增加: - 复用 `SelectionChanged` - 或新增 `AssetSelectionChanged` 如果不想扩事件类型,`SelectionChanged` 也能先扛住,但消息体里最好补一位,区分对象/资源选择。 ### 落点 - [MetaCoreEditorContext.h](/D:/MetaCore/Source/MetaCoreEditor/Public/MetaCoreEditor/MetaCoreEditorContext.h) - [MetaCoreEditorContext.cpp](/D:/MetaCore/Source/MetaCoreEditor/Private/MetaCoreEditorContext.cpp) - [MetaCoreEditorServices.h](/D:/MetaCore/Source/MetaCoreEditor/Public/MetaCoreEditor/MetaCoreEditorServices.h) ### 完成标准 - 选中对象时 Inspector 仍按对象逻辑显示 - 选中资源时 Inspector 切到资源模式 - 二者切换时状态不互相污染 --- ## Step 2:Project 面板最小版 ### 目标 做出最小可用的资源工作台。 ### 推荐 UI 结构 #### 左栏:目录树 首批固定展示: - `Assets` - `Scenes` - `Runtime` `Library` 不作为主工作目录。 #### 右栏:资源列表 当前目录下显示: - 文件夹 - 资源项 建议首批字段: - 名称 - 类型 - 来源类型(可选) ### 交互设计 #### 单击目录 - 更新当前浏览目录 #### 单击资源 - 写入 `EditorContext` 的资源选择状态 - Inspector 联动 #### 双击资源 首批建议: - 场景:加载 Scene - Prefab:先不做独立打开,可先选中并允许实例化 - 模型/材质/纹理:先只选中,不双开 ### 最小动作 建议面板工具栏有: - `Refresh` - `New Folder` 资源项右键菜单首批支持: - `Reimport` - `Copy Relative Path` ### 数据来源 依赖: - `GetDirectoriesUnder(relativeDirectory)` - `GetAssetsUnder(relativeDirectory)` ### 落点 - [MetaCoreBuiltinEditorModule.cpp](/D:/MetaCore/Source/MetaCoreEditor/Private/MetaCoreBuiltinEditorModule.cpp) - 若当前已有 Project 面板骨架,则优先在既有面板内扩展,不新开第二套实现 ### 完成标准 - 用户可以浏览项目目录 - 用户可以选中资源 - 用户可以执行刷新 - 用户可以对单资源执行重导入 --- ## Step 3:模型资源 Inspector 最小版 ### 目标 让选中模型资源这件事有足够信息密度。 ### 建议 Inspector 结构 #### 基础信息区 - 名称 - 相对路径 - `ImporterId` - `SourceFormat` - `SourceHash` #### 统计区 - `Mesh Count` - `Material Count` - `Texture Count` - `Node Count` #### 摘要区 - Mesh 列表 - 名称 - PrimitiveCount - Material 列表 - 名称 - Texture 列表 - 相对路径 ### 数据读取方式 建议流程: 1. 从 `SelectedAssetGuid` 找 `MetaCoreAssetRecord` 2. 读 `PackagePath` 3. 反序列化 `MetaCoreModelAssetDocument` 4. 在 Inspector 渲染 ### 最小动作 - `Reimport` - `Copy Relative Path` ### 落点 - [MetaCoreBuiltinEditorModule.cpp](/D:/MetaCore/Source/MetaCoreEditor/Private/MetaCoreBuiltinEditorModule.cpp) - [MetaCoreAssetTypes.h](/D:/MetaCore/Source/MetaCoreFoundation/Public/MetaCoreFoundation/MetaCoreAssetTypes.h) ### 完成标准 - 选中模型资源时能显示完整最小摘要 - `glTF / glb / generic model` 都能显示 --- ## Step 4:模型 / Prefab 拖拽到 Scene / Hierarchy ### 目标 把现有实例化服务接到编辑器交互里。 ### 拖拽载荷建议 建议定义一个最小内部拖拽 payload: ```cpp struct MetaCoreAssetDragPayload { MetaCoreAssetGuid AssetGuid{}; std::string AssetType{}; std::filesystem::path RelativePath{}; }; ``` 首批只要支持: - `model` - `prefab` - `material` ### Scene 接收规则 #### 模型 - 调 `InstantiateModelAsset(...)` #### Prefab - 调 `InstantiatePrefab(...)` ### Hierarchy 接收规则 #### 模型 - drop 到某对象时,将该对象作为 `forcedParentId` #### Prefab - 同理 ### 首批先不做 - 3D 光标落点 - 基于鼠标位置自动设置世界坐标 - 材质拖到 Scene 视口 ### 落点 - `Project` 面板的资源项开始拖拽 - `Scene View` 面板接收 - `Hierarchy` 面板节点接收 推测落点主要仍是: - [MetaCoreBuiltinEditorModule.cpp](/D:/MetaCore/Source/MetaCoreEditor/Private/MetaCoreBuiltinEditorModule.cpp) ### 完成标准 - 模型可拖到 Scene - 模型可拖到 Hierarchy 节点 - Prefab 可拖到 Scene / Hierarchy - drop 后自动选中新建根对象 --- ## Step 5:对象 Inspector 中的材质槽编辑 ### 目标 让模型实例不只是“摆进去”,而是真的能改材质引用。 ### 当前基础 [MetaCoreComponents.h](/D:/MetaCore/Source/MetaCoreScene/Public/MetaCoreScene/MetaCoreComponents.h) 中已经有: - `MeshAssetGuid` - `MaterialAssetGuids` 这说明对象级引用结构已经具备。 ### 首批实现建议 #### A. 在 `MeshRenderer` Inspector 中列出材质槽 至少显示: - 槽位索引 - 当前材质名 #### B. 用下拉框替换材质 候选来源: - 资产数据库中 `Type == "material"` 的资源 #### C. 支持从 `Project` 面板拖入 拖一个材质资源到对应槽位时: - 更新 `MaterialAssetGuids[slot]` ### 最小约束 - 如果对象当前没有足够槽位,首批可只支持已有槽位替换 - 不在 P0 里做 submesh 级复杂编辑器 ### 落点 - [MetaCoreBuiltinCoreServicesModule.cpp](/D:/MetaCore/Source/MetaCoreEditor/Private/MetaCoreBuiltinCoreServicesModule.cpp) ### 完成标准 - 用户能替换对象材质槽 - 修改后重新选择对象仍能看到结果 - Scene 保存重开后引用仍保留 --- ## Step 6:材质资源 Inspector 最小版 ### 目标 让 `MetaCoreMaterialAssetDocument` 变成真正能编辑的资源。 ### 建议显示字段 - 名称 - ShaderModel - BaseColor - BaseColorTexture - NormalTexture - Metallic - Roughness - MetallicRoughnessTexture - EmissiveColor - EmissiveTexture - AlphaMode - AlphaCutoff - DoubleSided ### 建议编辑方式 #### 标量 / 开关 - `DragFloat` - `Checkbox` - `Combo` #### 资源引用 - 下拉选择 - 后续支持从 Project 面板拖入 ### 保存策略 首批建议直接: 1. 读材质资源包 2. 反序列化 `MetaCoreMaterialAssetDocument` 3. 修改字段 4. 写回 package ### 运行时联动 P0 阶段至少要求: - 编辑后重新渲染当前对象时能读到更新值 如果实时联动太复杂,也应保证: - 再次选中对象 / 刷新场景时能反映资源修改 ### 落点 - [MetaCoreBuiltinEditorModule.cpp](/D:/MetaCore/Source/MetaCoreEditor/Private/MetaCoreBuiltinEditorModule.cpp) - [MetaCoreBuiltinCoreServicesModule.cpp](/D:/MetaCore/Source/MetaCoreEditor/Private/MetaCoreBuiltinCoreServicesModule.cpp) ### 完成标准 - 选中材质资源能显示参数 - 能修改并写回资源 - 引用该材质的对象能反映修改结果 --- ## 建议接口补充 为了减少 EditorModule 直接拼太多读写逻辑,建议补一层轻量资源编辑服务,至少先支持模型和材质: ```cpp class MetaCoreIAssetEditingService : public MetaCoreIEditorService { public: [[nodiscard]] virtual std::optional LoadModelAsset(const MetaCoreAssetGuid& assetGuid) const = 0; [[nodiscard]] virtual std::optional LoadMaterialAsset(const MetaCoreAssetGuid& assetGuid) const = 0; [[nodiscard]] virtual bool SaveMaterialAsset(const MetaCoreAssetGuid& assetGuid, const MetaCoreMaterialAssetDocument& document) = 0; }; ``` 这不是 P0 必须,但非常建议。 否则: - `Project` 面板 - 资源 Inspector - 材质编辑器 都会在 UI 层重复拼 package 读写逻辑。 --- ## 每步验收命令建议 每完成一个步骤后,至少做下面验证: ```powershell cmake --build --preset build-debug ctest --preset test-debug ``` 同时建议补对应 smoke test: - 资源选择状态切换 - Project 面板基础交互 - 模型资源 Inspector 读取 - 拖拽实例化 - 材质槽替换 - 材质资源写回 --- ## 风险点 ### 1. 资源选择状态与对象选择状态互相覆盖 这是最容易出现的 UI 脏状态问题。 应优先解。 ### 2. Inspector 读写逻辑散落 如果不抽轻量资源编辑服务,后面会重复实现 package 读写。 ### 3. 对象材质参数和材质资源参数边界混乱 当前 `MeshRenderer` 仍带着一部分材质字段。 P0 阶段先容忍,但实现时必须有意识: - 资源 Inspector 编辑的是资源 - 对象 Inspector 编辑的是引用 ### 4. 拖拽协议分散 建议早一点统一 asset drag payload,避免: - Project 一套 - Hierarchy 一套 - Scene 一套 后面难收。 --- ## 最终建议 P0 实施时最重要的不是功能总数,而是: **每一步都要让“资源 -> Inspector -> Scene/Hierarchy”这条链更顺,而不是再加新的孤立能力。** 这条链一旦立住,MetaCore 的观感会马上从“会导模型的工具”变成“开始像编辑器的引擎”。