Files
XCEngine/docs/plan/Unity风格模型导入与Model资产架构重构计划_2026-04-10.md

20 KiB
Raw Permalink Blame History

Unity 风格模型导入与 Model 资产架构重构计划

日期2026-04-10

1. 文档定位

这份计划覆盖 XCEngine 现阶段外部模型资源导入链路的结构性重构,目标不是“再给 MeshLoader 多加几个扩展名”,而是把模型资源正式提升为接近 Unity 的 ModelImporter + ModelAsset 工作流。

本计划默认遵循以下战略判断:

  1. 当前工程已经具备基于 Assimp 的基础静态模型读取能力,.obj/.fbx/.gltf/.glb/.dae/.stl 都能进入导入链。
  2. 当前主资源仍然是 Mesh,这导致导入时会把大量上层语义压扁到静态网格层。
  3. 如果要走 Unity 风格,后续继续在 Mesh 主资产上堆功能会越来越别扭,必须先补一层真正的 Model 资产。
  4. 骨骼动画不是本轮主目标,但本轮的数据结构和 artifact 设计必须为它预留正式扩展位。

本轮计划的本质是:

  1. 把“source model import”和“runtime mesh load”拆开。
  2. 把“外部模型文件的主资产类型”从 Mesh 提升到 Model
  3. .obj/.fbx/... 的导入体验统一到一条 ModelImporter 主链上。

2. 当前状态判断

基于当前代码结构,可以确认已有能力与缺口如下。

2.1 已有能力

  1. MeshLoader 已通过 Assimp 支持 .fbx/.obj/.gltf/.glb/.dae/.stl/.xcmesh
  2. AssetDatabase 已将 .obj/.fbx/.gltf/.glb/.dae/.stl 识别为 ModelImporter
  3. 编辑器 MeshFilter 的资源选择 UI 已允许 .fbx/.obj/.gltf/.glb
  4. 工程已接入 assimp-vc143-mt.dll,说明构建链和基础运行依赖已经建立。
  5. 当前 artifact 管线已经具备 xcmesh/xcmat/xctex 的写入与回读能力。

2.2 当前核心问题

  1. ModelImporter 的主资源类型实际上仍然是 Mesh,并不是真正的 Model
  2. 导入时递归遍历 Assimp node但会把 node transform 烘进顶点原始层级、局部变换、pivot 语义丢失。
  3. Mesh 顶点结构当前仍是静态网格视角,只覆盖 position/normal/tangent/bitangent/uv0
  4. MeshImportSettings 中虽然已经出现 ImportSkinning / ImportAnimations / ImportCameras / ImportLights 等标志,但没有形成对应的正式数据通路。
  5. .meta 当前只写 importer 名称和版本,没有形成 Unity 风格的模型导入设置持久化。
  6. 测试主要覆盖 obj 路径,针对真实 fbx fixture 的链路验证明显不足。
  7. 拖模型进场景时,现有工作流更接近“给一个 GameObject 绑定单个 Mesh”,而不是实例化一棵模型层级。

2.3 当前阶段最重要的判断

当前问题不在于“FBX 能不能读进来”,而在于“读进来以后是被当成 Mesh 还是被当成 Model”。

如果继续让外部模型文件直接产出主 Mesh

  1. OBJ 还能勉强成立。
  2. FBX 会不断丢失层级、pivot、子节点、多部件组织等上层语义。
  3. 后续无论做子资产展开、模型 prefab 化、骨骼动画还是稳定 reimport都会越来越难。

3. 目标架构决策

3.1 总体决策

长期目标不是:

  1. OBJ -> Mesh
  2. FBX -> Model

而是统一到:

  1. 外部模型格式统一进入 ModelImporter
  2. ModelImporter 的主产物统一是 Model
  3. Model 内部再引用一个或多个 Mesh/Material/Texture

即:

  1. .obj -> 简化 Model
  2. .fbx -> 完整 Model
  3. .gltf/.glb/... -> 同样走 Model 主链

这样做的好处是:

  1. 资源系统主线统一。
  2. 编辑器工作流统一。
  3. 子资产稳定引用机制统一。
  4. 骨骼、动画、blend shape、嵌入纹理等后续扩展都有正式落点。

3.2 MeshModel 的职责边界

Mesh 只回答一件事:

  1. 这个表面怎么画。

它应该承载:

  1. 顶点数据
  2. 索引数据
  3. section
  4. bounds
  5. 材质槽位数量与 section-material 映射

Model 回答另一件事:

  1. 这个资源整体怎么组织。

它应该承载:

  1. 节点层级
  2. 节点局部 TRS
  3. 节点名字与路径
  4. 节点绑定的 mesh 引用
  5. 每个 mesh 节点的材质槽绑定
  6. 根节点信息
  7. 导入元数据
  8. 未来的 skeleton / animation / blend shape 扩展位

3.3 运行时链路的长期形态

长期上应当形成三层:

  1. ModelImporter 负责 source file -> artifact graph
  2. ModelLoader 负责读取 xcmodel
  3. MeshLoader 负责读取 xcmesh

其中:

  1. MeshLoader 不再承担完整 source scene import 的主责任。
  2. MeshLoader 更适合退化成“运行时 mesh artifact 加载器 + builtin mesh loader”。
  3. 所有 source model 的正式导入都应该通过 ModelImporter 的专用实现完成。

4. 本轮范围与明确不做的内容

4.1 本轮必须完成

  1. Model 资源类型与 xcmodel artifact。
  2. 统一的 ModelImporter 主链。
  3. .meta 中的 Model Import Settings 持久化。
  4. 保留层级的静态模型导入。
  5. 场景中实例化模型层级的工作流。
  6. 子资产与稳定 LocalID 规则。
  7. 编辑器中的模型导入设置 Inspector。
  8. OBJ/FBX 静态模型的正式测试闭环。

4.2 本轮暂不做

  1. SkinnedMeshRenderer 正式渲染链。
  2. 骨骼矩阵上传与 GPU skinning。
  3. 动画 clip runtime 播放系统。
  4. blend shape runtime。
  5. 完整相机/灯光从 FBX 到 scene 的自动生成。
  6. 模型子资产在 Project 面板中的完整可展开 UI。

4.3 本轮只预留不落地的内容

  1. Skeleton 资源类型接口
  2. AnimationClip 资源类型接口
  3. Model 中 skeleton/animation 的 artifact 扩展位
  4. skinning/blend shape 所需的稳定 source 标识规则

5. 目标数据结构设计

5.1 新增资源类型

建议在 ResourceType 中正式新增:

  1. Model

同时保留已有:

  1. Mesh
  2. Material
  3. Texture
  4. AnimationClip
  5. Skeleton

即使 AnimationClip/Skeleton 本轮不真正导出,也应在设计上与 Model 并列存在。

5.2 Model 资源结构建议

Model 至少包含以下结构:

  1. ModelNode
    • name
    • parentIndex
    • firstChildIndex / childCount 或 child index array
    • localPosition
    • localRotation
    • localScale
    • meshBindingStart
    • meshBindingCount
  2. ModelMeshBinding
    • meshLocalID
    • materialBindingStart
    • materialBindingCount
  3. ModelMaterialBinding
    • slotIndex
    • materialLocalID
  4. ModelImportMetadata
    • importer version
    • source file signature
    • import settings snapshot

5.3 Mesh 资源职责调整

Mesh 继续作为低层渲染资源保留,但职责要收紧:

  1. 不再把 source model file 当成它的长期主输入。
  2. 主要负责:
    • xcmesh
    • builtin mesh
  3. source format 直接读取只作为过渡能力,后续应弱化。

5.4 Model artifact 文件布局

建议 artifact 目录布局统一为:

  1. main.xcmodel
  2. mesh_0.xcmesh
  3. mesh_1.xcmesh
  4. material_0.xcmat
  5. material_1.xcmat
  6. texture_0.xctex
  7. texture_1.xctex
  8. 未来可扩展:
    • skeleton_0.xcskel
    • anim_0.xcanim

5.5 LocalID 稳定规则

这是整个 Unity 风格方案里最关键的一部分。

不能简单使用“导入顺序下标”作为长期稳定标识。应当引入基于源语义的稳定 LocalID 生成策略:

  1. Node基于节点路径生成
  2. Mesh基于节点路径 + mesh name + source mesh index 生成
  3. Material基于 material name + source material index 生成
  4. Texture基于 source texture path 或 embedded texture key 生成
  5. 后续骨骼/动画基于骨骼名、clip 名、source index 生成

目标是:

  1. 同一个模型在普通 reimport 后,子资产 LocalID 不变。
  2. 场景/prefab/材质槽引用不因为 artifact 目录变化而失效。

6. 导入链路重构方案

6.1 引入专用 source importer

建议新增专用模块,例如:

  1. AssimpModelImporter

它的职责是:

  1. 读取 .obj/.fbx/.gltf/.glb/...
  2. 产出统一中间结构 ImportedModel
  3. 再由 artifact writer 写出 xcmodel/xcmesh/xcmat/xctex

不建议继续把这部分主逻辑堆在 MeshLoader 内部。

6.2 导入中间结构

建议先建立 importer 内部中间结构:

  1. ImportedModel
  2. ImportedNode
  3. ImportedMesh
  4. ImportedMaterial
  5. ImportedTexture

这样可以把:

  1. Assimp scene 读取
  2. 引擎内部资源表示
  3. artifact 写出

三者解耦。

6.3 节点与变换处理原则

这是与当前实现最大的差异之一。

当前做法是把 node 变换乘到顶点上,再把所有几何收进同一个 Mesh。本轮要改成:

  1. Mesh 顶点保持在 mesh local space
  2. Node local transform 单独存进 Model
  3. Scene 实例化时再把 node local transform 还原到 GameObject

只有这样才能保留:

  1. 层级
  2. pivot
  3. 本地 TRS
  4. 后续动画骨骼的基础结构

6.4 轴系与缩放的处理原则

建议明确以下规则:

  1. 轴系转换属于导入标准化步骤,但不能以“摧毁原始层级”为代价。
  2. 全局 import scale 应优先体现在 root 侧或 mesh 侧的单一标准化策略中,不要 mesh 与 node 两边重复施加。
  3. 一旦规则确定,要在 ModelImportSettings 中固定,并进入 metaHash

本轮必须把“坐标转换在哪里做、缩放在哪里做”写成正式约束,而不是散落在 loader 里。

6.5 OBJ 的导入策略

OBJ 仍然统一走 ModelImporter,但导入结果通常是一个简化模型:

  1. 一个 root node
  2. 一个或少量 mesh node
  3. 少量 material bindings

即:

  1. OBJ 不是继续作为架构特例保留在 Mesh 主链外面
  2. 它只是“语义很简单的 model source”

6.6 FBX 的导入策略

FBX 则要保留完整静态结构:

  1. node hierarchy
  2. local transform
  3. mesh attachments
  4. material slots
  5. embedded/external textures
  6. 后续可扩展 skeleton/animation metadata

即使本轮不做动画,也不应该再把 FBX 烘成单个主 Mesh


7. AssetDatabase 与 ArtifactDatabase 改造计划

7.1 主资产类型调整

当前 ModelImporter 的主资产仍是 Mesh。本轮要改成:

  1. ModelImporter 主资产类型为 Model
  2. mainLocalID 指向 Model 主资产
  3. Mesh/Material/Texture 成为其子资产

7.2 EnsureArtifact 语义调整

Assets/Models/robot.fbx 执行 EnsureArtifact(..., ResourceType::Model) 时:

  1. 返回主 xcmodel
  2. 内部子资产可通过 AssetRef(assetGuid, localID, resourceType) 访问

若后续有需要,MeshFilter 等组件可直接引用某个 Mesh 子资产,而不是引用主 Model

7.3 依赖追踪调整

当前依赖追踪对 obj -> mtl -> texture 已有基础覆盖,但本轮要升级成通用模型依赖追踪:

  1. source model file
  2. 外部纹理
  3. embedded texture 的派生 key
  4. 导入设置 meta
  5. future外部 animation source / skeleton source

目标是:

  1. 改 texture 会触发模型 reimport
  2. 改 importer settings 会触发模型 reimport
  3. 子资产 artifact 会稳定重建

7.4 资源查询接口调整

建议新增或调整:

  1. TryGetAssetRef(path, ResourceType::Model, ...)
  2. TryGetSubAssetRef(path, subAssetKey or localID, ResourceType::Mesh, ...)
  3. TryGetPrimaryAssetPath(guid, ...)Model 继续保持主资产语义

同时要保证:

  1. Model 与子 Mesh 的引用路径语义清晰
  2. 编辑器与场景序列化知道自己引用的是主资产还是子资产

8. .meta 与导入设置计划

8.1 当前问题

当前 .meta 只有:

  1. guid
  2. folderAsset
  3. importer
  4. importerVersion

这不足以支撑 Unity 风格模型工作流。

8.2 新增 ModelImportSettings

建议正式引入或升级为:

  1. ModelImportSettings

至少包括:

  1. globalScale
  2. axisConversion
  3. flipUVs
  4. flipWindingOrder
  5. generateNormals
  6. generateTangents
  7. importMaterials
  8. extractEmbeddedTextures
  9. preserveHierarchy
  10. mergeStaticMeshes
  11. 预留:
    • importSkinning
    • importAnimations
    • importCameras
    • importLights

8.3 .meta 持久化规则

应当把上述设置正式写入 .meta,并参与 metaHash

目标是:

  1. 切换 importer setting 后 artifact key 会变化
  2. Reimport 有明确语义
  3. Inspector 改完设置能稳定反映到导入结果

8.4 版本策略

建议:

  1. ModelImporter 单独维护 importer version
  2. xcmodel schema 或子资产布局变化时,显式提升版本号
  3. 不再使用“整个 AssetDatabase 共用一个笼统版本号”来覆盖全部导入器变化

9. 编辑器工作流计划

9.1 Project 面板语义

.obj/.fbx/.gltf/.glb/... 在 Project 面板中应统一显示为:

  1. Model

而不是继续让用户默认把这些资源理解成“单个 mesh 文件”。

9.2 Model Importer Inspector

选中模型资源时Inspector 需要出现真正的导入设置面板:

  1. Import Settings
  2. Apply
  3. Revert
  4. Reimport

首批显示的设置至少包括:

  1. Scale
  2. Axis Conversion
  3. Preserve Hierarchy
  4. Import Materials
  5. Generate Normals
  6. Generate Tangents
  7. Flip UVs

9.3 场景拖拽行为

把模型资源拖进场景时,不应只创建一个空物体加一个 MeshFilter

推荐行为:

  1. 读取 Model
  2. 生成对应 GameObject
  3. 按节点局部变换恢复 TRS
  4. 对带 mesh 的节点挂 MeshFilter + MeshRenderer
  5. 材质槽按 Model 内的绑定还原

这才接近 Unity 的“拖入模型得到层级实例”。

9.4 子资产访问

本轮不强制要求 Project 面板完整展开子资产树,但至少应保证:

  1. MeshFilter 能引用模型产出的某个 Mesh 子资产
  2. 场景序列化后引用稳定
  3. 后续补 Project 子资产展开 UI 时不需要推倒重来

10. 场景实例化与运行时路径

10.1 不建议增加 ModelComponent

为了贴近 Unity建议不要把“整个模型实例”抽成一个新的 ModelComponent 挂在单个对象上。

更合理的做法是:

  1. Model 是资源
  2. “实例化模型”是一个 utility / service
  3. 实例化结果是 GameObject 层级

10.2 建议新增实例化工具层

可以新增例如:

  1. ModelInstantiationUtility
  2. InstantiateModelAsset(...)

职责:

  1. 根据 Model 创建场景层级
  2. 为每个节点恢复局部 TRS
  3. 绑定子 Mesh
  4. 绑定默认材质或导入材质

10.3 与现有渲染链的兼容策略

现有渲染链以 MeshFilter + MeshRenderer 为中心,这一层本轮不应推翻。

本轮应当:

  1. 保持 runtime 渲染主链稳定
  2. 通过新的 Model -> GameObject hierarchy 实例化路径,把 Model 翻译回现有组件体系

这样风险最小,且后续加 SkinnedMeshRenderer 时也有自然落点。


11. 测试与验证计划

11.1 Fixture 规划

必须新增真实模型 fixture不再只停留在字符串层面的 CanLoad("test.fbx")

建议至少准备:

  1. single_mesh_static.obj
  2. single_mesh_static.fbx
  3. multi_node_static.fbx
  4. multi_material_static.fbx
  5. embedded_texture_static.fbx
  6. external_texture_static.fbx

11.2 Unit Test

建议新增或扩展:

  1. ModelLoader 基础加载测试
  2. ModelImportSettings 持久化测试
  3. ModelArtifact 写入/回读测试
  4. LocalID 稳定性测试
  5. AssetDatabase 主资产/子资产引用测试

11.3 Integration Test

建议新增:

  1. FBX -> xcmodel -> scene instantiate 集成测试
  2. reimport 后 AssetRef 稳定性测试
  3. 多节点模型实例化后层级与局部变换恢复测试
  4. 多材质槽绑定测试

11.4 Editor Test

建议补:

  1. Project 面板模型类型识别
  2. Model Importer Inspector 设置编辑
  3. Apply/Reimport 行为
  4. 拖模型到场景生成层级

11.5 验收原则

本轮不能以“能读进一个 FBX 文件”作为完成标准。

必须同时满足:

  1. artifact 正确
  2. hierarchy 正确
  3. reimport 稳定
  4. editor 工作流成立

12. 分阶段执行计划

Phase 1Model 资源与 artifact 基础设施落地

目标:

  1. 新增 ResourceType::Model
  2. 新增 Model 类与 ModelLoader
  3. 新增 xcmodel artifact 格式

任务:

  1. 设计 ModelNode / ModelMeshBinding / ModelMaterialBinding
  2. ArtifactFormats 中定义 ModelArtifactHeader
  3. 实现 WriteModelArtifactFile / LoadModelArtifact
  4. ResourceManager 注册 ModelLoader

验收标准:

  1. xcmodel 能写出与读回
  2. Model 可被 ResourceManager 正式加载

Phase 2source import 主链从 Mesh 迁移到 Model

目标:

  1. 建立 AssimpModelImporter
  2. .obj/.fbx/... 的正式导入主链切换到 Model

任务:

  1. 建立 ImportedModel 中间结构
  2. 从 Assimp scene 提取节点层级、局部 TRS、mesh、material、texture
  3. 停止在导入主链中把 node transform 烘平到单个主 mesh
  4. 输出 main.xcmodel + sub assets

验收标准:

  1. OBJ 被导入成简化 Model
  2. FBX 被导入成保留 hierarchy 的 Model

Phase 3AssetDatabase 子资产与稳定 LocalID

目标:

  1. 完成主资产/子资产语义
  2. 建立稳定 LocalID 规则

任务:

  1. 修改 ModelImporter 的主资源类型
  2. 实现模型子资产 AssetRef
  3. EnsureArtifactTryGetAssetRef、序列化链路理解 Model 主资产与子 Mesh
  4. 建立 reimport 稳定性测试

验收标准:

  1. reimport 后子资产引用不漂移
  2. 场景中的 mesh 引用可稳定恢复

Phase 4.meta 与 Model Import Settings 正式化

目标:

  1. 让模型导入参数进入正式工作流

任务:

  1. 定义 ModelImportSettings
  2. 把 settings 写入 .meta
  3. 调整 metaHash
  4. 保证 settings 变化触发 reimport

验收标准:

  1. 改 scale/axis/material 等设置会稳定影响导入结果
  2. artifact key 与导入设置一致变化

Phase 5编辑器 Inspector 与场景实例化工作流

目标:

  1. 建立 Unity 风格的模型资源使用体验

任务:

  1. Project 面板统一把模型文件识别为 Model
  2. 新增 Model Importer Inspector
  3. 实现 Apply/Reimport
  4. 实现拖模型到场景生成 GameObject 层级

验收标准:

  1. 从 editor 可完整配置模型导入
  2. 拖入场景后层级与局部变换正确

Phase 6清理过渡路径与补齐文档测试

目标:

  1. 收紧旧路径,避免双轨架构长期并存

任务:

  1. 评估并逐步弱化“source file 直接由 MeshLoader 作为主入口”的旧路径
  2. 清理命名、文档、注释、测试目录结构
  3. 输出阶段总结

验收标准:

  1. 主链路清晰,旧路径只保留必要兼容
  2. 文档与测试同步完成

13. 关键风险与应对

13.1 最大风险:LocalID 不稳定

风险:

  1. reimport 后子资产重排
  2. 场景与 prefab 引用失效

应对:

  1. 在 Phase 1 之前先写清 LocalID 规则
  2. 在 Phase 3 前就建立稳定性测试

13.2 第二风险:轴系与缩放规则前后不一致

风险:

  1. 同一模型在 direct load、artifact load、scene instantiate 三条路径下结果不一致

应对:

  1. 明确标准化规则只允许一个真值来源
  2. 写入 importer settings 并进入测试

13.3 第三风险:编辑器体验与底层数据不同步

风险:

  1. Inspector 改了设置但 reimport 行为不稳定
  2. Project 面板显示的是 Model,内部实际仍按 Mesh

应对:

  1. 先完成 Resource/AssetDatabase 语义,再接 editor UI
  2. 不允许 editor 先行伪装完成

13.4 第四风险:过渡期双轨逻辑长期共存

风险:

  1. MeshLoader source import 与 ModelImporter source import 两套路径并行,长期维护成本失控

应对:

  1. 在 Phase 6 明确收紧旧路径
  2. 把 source import 主入口统一到 ModelImporter

14. 本轮完成标志

当以下条件同时成立时,本轮才算真正完成:

  1. .obj/.fbx/.gltf/.glb/... 的主资产统一为 Model
  2. Model artifact 已正式落地并进入 ResourceManager
  3. OBJ 能导入成简化 Model
  4. FBX 能导入成保留 hierarchy 的静态 Model
  5. 模型导入设置已写入 .meta 并进入 reimport 逻辑
  6. editor 中已具备 Model Importer Inspector
  7. 拖模型到场景时会生成 GameObject 层级,而非单个烘平 mesh
  8. 子资产 LocalID 在普通 reimport 下稳定
  9. 测试已覆盖真实 FBX fixture 的关键路径

15. 一句话结论

这一轮不是“给 FBX 补支持”,而是把 XCEngine 的外部模型资源体系从“以 Mesh 为主资产的静态导入器”升级成“以 Model 为主资产、以子资产和稳定 reimport 为基础、可持续扩展到骨骼动画的 Unity 风格模型工作流”。