20 KiB
Unity 风格模型导入与 Model 资产架构重构计划
日期:2026-04-10
1. 文档定位
这份计划覆盖 XCEngine 现阶段外部模型资源导入链路的结构性重构,目标不是“再给 MeshLoader 多加几个扩展名”,而是把模型资源正式提升为接近 Unity 的 ModelImporter + ModelAsset 工作流。
本计划默认遵循以下战略判断:
- 当前工程已经具备基于
Assimp的基础静态模型读取能力,.obj/.fbx/.gltf/.glb/.dae/.stl都能进入导入链。 - 当前主资源仍然是
Mesh,这导致导入时会把大量上层语义压扁到静态网格层。 - 如果要走 Unity 风格,后续继续在
Mesh主资产上堆功能会越来越别扭,必须先补一层真正的Model资产。 - 骨骼动画不是本轮主目标,但本轮的数据结构和 artifact 设计必须为它预留正式扩展位。
本轮计划的本质是:
- 把“source model import”和“runtime mesh load”拆开。
- 把“外部模型文件的主资产类型”从
Mesh提升到Model。 - 把
.obj/.fbx/...的导入体验统一到一条ModelImporter主链上。
2. 当前状态判断
基于当前代码结构,可以确认已有能力与缺口如下。
2.1 已有能力
MeshLoader已通过Assimp支持.fbx/.obj/.gltf/.glb/.dae/.stl/.xcmesh。AssetDatabase已将.obj/.fbx/.gltf/.glb/.dae/.stl识别为ModelImporter。- 编辑器
MeshFilter的资源选择 UI 已允许.fbx/.obj/.gltf/.glb。 - 工程已接入
assimp-vc143-mt.dll,说明构建链和基础运行依赖已经建立。 - 当前 artifact 管线已经具备
xcmesh/xcmat/xctex的写入与回读能力。
2.2 当前核心问题
ModelImporter的主资源类型实际上仍然是Mesh,并不是真正的Model。- 导入时递归遍历 Assimp node,但会把 node transform 烘进顶点,原始层级、局部变换、pivot 语义丢失。
Mesh顶点结构当前仍是静态网格视角,只覆盖position/normal/tangent/bitangent/uv0。MeshImportSettings中虽然已经出现ImportSkinning / ImportAnimations / ImportCameras / ImportLights等标志,但没有形成对应的正式数据通路。.meta当前只写 importer 名称和版本,没有形成 Unity 风格的模型导入设置持久化。- 测试主要覆盖
obj路径,针对真实fbxfixture 的链路验证明显不足。 - 拖模型进场景时,现有工作流更接近“给一个
GameObject绑定单个Mesh”,而不是实例化一棵模型层级。
2.3 当前阶段最重要的判断
当前问题不在于“FBX 能不能读进来”,而在于“读进来以后是被当成 Mesh 还是被当成 Model”。
如果继续让外部模型文件直接产出主 Mesh:
OBJ还能勉强成立。FBX会不断丢失层级、pivot、子节点、多部件组织等上层语义。- 后续无论做子资产展开、模型 prefab 化、骨骼动画还是稳定 reimport,都会越来越难。
3. 目标架构决策
3.1 总体决策
长期目标不是:
OBJ -> MeshFBX -> Model
而是统一到:
- 外部模型格式统一进入
ModelImporter ModelImporter的主产物统一是ModelModel内部再引用一个或多个Mesh/Material/Texture
即:
.obj -> 简化 Model.fbx -> 完整 Model.gltf/.glb/... -> 同样走 Model 主链
这样做的好处是:
- 资源系统主线统一。
- 编辑器工作流统一。
- 子资产稳定引用机制统一。
- 骨骼、动画、blend shape、嵌入纹理等后续扩展都有正式落点。
3.2 Mesh 与 Model 的职责边界
Mesh 只回答一件事:
- 这个表面怎么画。
它应该承载:
- 顶点数据
- 索引数据
- section
- bounds
- 材质槽位数量与 section-material 映射
Model 回答另一件事:
- 这个资源整体怎么组织。
它应该承载:
- 节点层级
- 节点局部 TRS
- 节点名字与路径
- 节点绑定的 mesh 引用
- 每个 mesh 节点的材质槽绑定
- 根节点信息
- 导入元数据
- 未来的 skeleton / animation / blend shape 扩展位
3.3 运行时链路的长期形态
长期上应当形成三层:
ModelImporter负责 source file -> artifact graphModelLoader负责读取xcmodelMeshLoader负责读取xcmesh
其中:
MeshLoader不再承担完整 source scene import 的主责任。MeshLoader更适合退化成“运行时 mesh artifact 加载器 + builtin mesh loader”。- 所有 source model 的正式导入都应该通过
ModelImporter的专用实现完成。
4. 本轮范围与明确不做的内容
4.1 本轮必须完成
Model资源类型与xcmodelartifact。- 统一的
ModelImporter主链。 .meta中的 Model Import Settings 持久化。- 保留层级的静态模型导入。
- 场景中实例化模型层级的工作流。
- 子资产与稳定
LocalID规则。 - 编辑器中的模型导入设置 Inspector。
OBJ/FBX静态模型的正式测试闭环。
4.2 本轮暂不做
SkinnedMeshRenderer正式渲染链。- 骨骼矩阵上传与 GPU skinning。
- 动画 clip runtime 播放系统。
- blend shape runtime。
- 完整相机/灯光从
FBX到 scene 的自动生成。 - 模型子资产在 Project 面板中的完整可展开 UI。
4.3 本轮只预留不落地的内容
Skeleton资源类型接口AnimationClip资源类型接口Model中 skeleton/animation 的 artifact 扩展位- skinning/blend shape 所需的稳定 source 标识规则
5. 目标数据结构设计
5.1 新增资源类型
建议在 ResourceType 中正式新增:
Model
同时保留已有:
MeshMaterialTextureAnimationClipSkeleton
即使 AnimationClip/Skeleton 本轮不真正导出,也应在设计上与 Model 并列存在。
5.2 Model 资源结构建议
Model 至少包含以下结构:
ModelNodenameparentIndexfirstChildIndex / childCount或 child index arraylocalPositionlocalRotationlocalScalemeshBindingStartmeshBindingCount
ModelMeshBindingmeshLocalIDmaterialBindingStartmaterialBindingCount
ModelMaterialBindingslotIndexmaterialLocalID
ModelImportMetadata- importer version
- source file signature
- import settings snapshot
5.3 Mesh 资源职责调整
Mesh 继续作为低层渲染资源保留,但职责要收紧:
- 不再把 source model file 当成它的长期主输入。
- 主要负责:
xcmesh- builtin mesh
- source format 直接读取只作为过渡能力,后续应弱化。
5.4 Model artifact 文件布局
建议 artifact 目录布局统一为:
main.xcmodelmesh_0.xcmeshmesh_1.xcmeshmaterial_0.xcmatmaterial_1.xcmattexture_0.xctextexture_1.xctex- 未来可扩展:
skeleton_0.xcskelanim_0.xcanim
5.5 LocalID 稳定规则
这是整个 Unity 风格方案里最关键的一部分。
不能简单使用“导入顺序下标”作为长期稳定标识。应当引入基于源语义的稳定 LocalID 生成策略:
- Node:基于节点路径生成
- Mesh:基于节点路径 + mesh name + source mesh index 生成
- Material:基于 material name + source material index 生成
- Texture:基于 source texture path 或 embedded texture key 生成
- 后续骨骼/动画:基于骨骼名、clip 名、source index 生成
目标是:
- 同一个模型在普通 reimport 后,子资产
LocalID不变。 - 场景/prefab/材质槽引用不因为 artifact 目录变化而失效。
6. 导入链路重构方案
6.1 引入专用 source importer
建议新增专用模块,例如:
AssimpModelImporter
它的职责是:
- 读取
.obj/.fbx/.gltf/.glb/... - 产出统一中间结构
ImportedModel - 再由 artifact writer 写出
xcmodel/xcmesh/xcmat/xctex
不建议继续把这部分主逻辑堆在 MeshLoader 内部。
6.2 导入中间结构
建议先建立 importer 内部中间结构:
ImportedModelImportedNodeImportedMeshImportedMaterialImportedTexture
这样可以把:
- Assimp scene 读取
- 引擎内部资源表示
- artifact 写出
三者解耦。
6.3 节点与变换处理原则
这是与当前实现最大的差异之一。
当前做法是把 node 变换乘到顶点上,再把所有几何收进同一个 Mesh。本轮要改成:
- Mesh 顶点保持在 mesh local space
- Node local transform 单独存进
Model - Scene 实例化时再把 node local transform 还原到
GameObject
只有这样才能保留:
- 层级
- pivot
- 本地 TRS
- 后续动画骨骼的基础结构
6.4 轴系与缩放的处理原则
建议明确以下规则:
- 轴系转换属于导入标准化步骤,但不能以“摧毁原始层级”为代价。
- 全局 import scale 应优先体现在 root 侧或 mesh 侧的单一标准化策略中,不要 mesh 与 node 两边重复施加。
- 一旦规则确定,要在
ModelImportSettings中固定,并进入metaHash。
本轮必须把“坐标转换在哪里做、缩放在哪里做”写成正式约束,而不是散落在 loader 里。
6.5 OBJ 的导入策略
OBJ 仍然统一走 ModelImporter,但导入结果通常是一个简化模型:
- 一个 root node
- 一个或少量 mesh node
- 少量 material bindings
即:
OBJ不是继续作为架构特例保留在Mesh主链外面- 它只是“语义很简单的 model source”
6.6 FBX 的导入策略
FBX 则要保留完整静态结构:
- node hierarchy
- local transform
- mesh attachments
- material slots
- embedded/external textures
- 后续可扩展 skeleton/animation metadata
即使本轮不做动画,也不应该再把 FBX 烘成单个主 Mesh。
7. AssetDatabase 与 ArtifactDatabase 改造计划
7.1 主资产类型调整
当前 ModelImporter 的主资产仍是 Mesh。本轮要改成:
ModelImporter主资产类型为ModelmainLocalID指向Model主资产Mesh/Material/Texture成为其子资产
7.2 EnsureArtifact 语义调整
对 Assets/Models/robot.fbx 执行 EnsureArtifact(..., ResourceType::Model) 时:
- 返回主
xcmodel - 内部子资产可通过
AssetRef(assetGuid, localID, resourceType)访问
若后续有需要,MeshFilter 等组件可直接引用某个 Mesh 子资产,而不是引用主 Model。
7.3 依赖追踪调整
当前依赖追踪对 obj -> mtl -> texture 已有基础覆盖,但本轮要升级成通用模型依赖追踪:
- source model file
- 外部纹理
- embedded texture 的派生 key
- 导入设置 meta
- future:外部 animation source / skeleton source
目标是:
- 改 texture 会触发模型 reimport
- 改 importer settings 会触发模型 reimport
- 子资产 artifact 会稳定重建
7.4 资源查询接口调整
建议新增或调整:
TryGetAssetRef(path, ResourceType::Model, ...)TryGetSubAssetRef(path, subAssetKey or localID, ResourceType::Mesh, ...)TryGetPrimaryAssetPath(guid, ...)对Model继续保持主资产语义
同时要保证:
- 主
Model与子Mesh的引用路径语义清晰 - 编辑器与场景序列化知道自己引用的是主资产还是子资产
8. .meta 与导入设置计划
8.1 当前问题
当前 .meta 只有:
guidfolderAssetimporterimporterVersion
这不足以支撑 Unity 风格模型工作流。
8.2 新增 ModelImportSettings
建议正式引入或升级为:
ModelImportSettings
至少包括:
globalScaleaxisConversionflipUVsflipWindingOrdergenerateNormalsgenerateTangentsimportMaterialsextractEmbeddedTexturespreserveHierarchymergeStaticMeshes- 预留:
importSkinningimportAnimationsimportCamerasimportLights
8.3 .meta 持久化规则
应当把上述设置正式写入 .meta,并参与 metaHash。
目标是:
- 切换 importer setting 后 artifact key 会变化
Reimport有明确语义- Inspector 改完设置能稳定反映到导入结果
8.4 版本策略
建议:
ModelImporter单独维护 importer version- 当
xcmodelschema 或子资产布局变化时,显式提升版本号 - 不再使用“整个 AssetDatabase 共用一个笼统版本号”来覆盖全部导入器变化
9. 编辑器工作流计划
9.1 Project 面板语义
.obj/.fbx/.gltf/.glb/... 在 Project 面板中应统一显示为:
Model
而不是继续让用户默认把这些资源理解成“单个 mesh 文件”。
9.2 Model Importer Inspector
选中模型资源时,Inspector 需要出现真正的导入设置面板:
- Import Settings
- Apply
- Revert
- Reimport
首批显示的设置至少包括:
- Scale
- Axis Conversion
- Preserve Hierarchy
- Import Materials
- Generate Normals
- Generate Tangents
- Flip UVs
9.3 场景拖拽行为
把模型资源拖进场景时,不应只创建一个空物体加一个 MeshFilter。
推荐行为:
- 读取
Model - 生成对应
GameObject树 - 按节点局部变换恢复 TRS
- 对带 mesh 的节点挂
MeshFilter + MeshRenderer - 材质槽按
Model内的绑定还原
这才接近 Unity 的“拖入模型得到层级实例”。
9.4 子资产访问
本轮不强制要求 Project 面板完整展开子资产树,但至少应保证:
MeshFilter能引用模型产出的某个Mesh子资产- 场景序列化后引用稳定
- 后续补 Project 子资产展开 UI 时不需要推倒重来
10. 场景实例化与运行时路径
10.1 不建议增加 ModelComponent
为了贴近 Unity,建议不要把“整个模型实例”抽成一个新的 ModelComponent 挂在单个对象上。
更合理的做法是:
Model是资源- “实例化模型”是一个 utility / service
- 实例化结果是
GameObject层级
10.2 建议新增实例化工具层
可以新增例如:
ModelInstantiationUtilityInstantiateModelAsset(...)
职责:
- 根据
Model创建场景层级 - 为每个节点恢复局部 TRS
- 绑定子
Mesh - 绑定默认材质或导入材质
10.3 与现有渲染链的兼容策略
现有渲染链以 MeshFilter + MeshRenderer 为中心,这一层本轮不应推翻。
本轮应当:
- 保持 runtime 渲染主链稳定
- 通过新的
Model -> GameObject hierarchy实例化路径,把Model翻译回现有组件体系
这样风险最小,且后续加 SkinnedMeshRenderer 时也有自然落点。
11. 测试与验证计划
11.1 Fixture 规划
必须新增真实模型 fixture,不再只停留在字符串层面的 CanLoad("test.fbx")。
建议至少准备:
single_mesh_static.objsingle_mesh_static.fbxmulti_node_static.fbxmulti_material_static.fbxembedded_texture_static.fbxexternal_texture_static.fbx
11.2 Unit Test
建议新增或扩展:
ModelLoader基础加载测试ModelImportSettings持久化测试ModelArtifact写入/回读测试LocalID稳定性测试AssetDatabase主资产/子资产引用测试
11.3 Integration Test
建议新增:
FBX -> xcmodel -> scene instantiate集成测试- reimport 后
AssetRef稳定性测试 - 多节点模型实例化后层级与局部变换恢复测试
- 多材质槽绑定测试
11.4 Editor Test
建议补:
- Project 面板模型类型识别
- Model Importer Inspector 设置编辑
- Apply/Reimport 行为
- 拖模型到场景生成层级
11.5 验收原则
本轮不能以“能读进一个 FBX 文件”作为完成标准。
必须同时满足:
- artifact 正确
- hierarchy 正确
- reimport 稳定
- editor 工作流成立
12. 分阶段执行计划
Phase 1:Model 资源与 artifact 基础设施落地
目标:
- 新增
ResourceType::Model - 新增
Model类与ModelLoader - 新增
xcmodelartifact 格式
任务:
- 设计
ModelNode / ModelMeshBinding / ModelMaterialBinding - 在
ArtifactFormats中定义ModelArtifactHeader - 实现
WriteModelArtifactFile / LoadModelArtifact - 让
ResourceManager注册ModelLoader
验收标准:
xcmodel能写出与读回Model可被ResourceManager正式加载
Phase 2:source import 主链从 Mesh 迁移到 Model
目标:
- 建立
AssimpModelImporter - 将
.obj/.fbx/...的正式导入主链切换到Model
任务:
- 建立
ImportedModel中间结构 - 从 Assimp scene 提取节点层级、局部 TRS、mesh、material、texture
- 停止在导入主链中把 node transform 烘平到单个主 mesh
- 输出
main.xcmodel + sub assets
验收标准:
OBJ被导入成简化ModelFBX被导入成保留 hierarchy 的Model
Phase 3:AssetDatabase 子资产与稳定 LocalID
目标:
- 完成主资产/子资产语义
- 建立稳定
LocalID规则
任务:
- 修改
ModelImporter的主资源类型 - 实现模型子资产
AssetRef - 让
EnsureArtifact、TryGetAssetRef、序列化链路理解Model主资产与子Mesh - 建立 reimport 稳定性测试
验收标准:
- reimport 后子资产引用不漂移
- 场景中的 mesh 引用可稳定恢复
Phase 4:.meta 与 Model Import Settings 正式化
目标:
- 让模型导入参数进入正式工作流
任务:
- 定义
ModelImportSettings - 把 settings 写入
.meta - 调整
metaHash - 保证 settings 变化触发 reimport
验收标准:
- 改 scale/axis/material 等设置会稳定影响导入结果
- artifact key 与导入设置一致变化
Phase 5:编辑器 Inspector 与场景实例化工作流
目标:
- 建立 Unity 风格的模型资源使用体验
任务:
- Project 面板统一把模型文件识别为
Model - 新增 Model Importer Inspector
- 实现
Apply/Reimport - 实现拖模型到场景生成
GameObject层级
验收标准:
- 从 editor 可完整配置模型导入
- 拖入场景后层级与局部变换正确
Phase 6:清理过渡路径与补齐文档测试
目标:
- 收紧旧路径,避免双轨架构长期并存
任务:
- 评估并逐步弱化“source file 直接由
MeshLoader作为主入口”的旧路径 - 清理命名、文档、注释、测试目录结构
- 输出阶段总结
验收标准:
- 主链路清晰,旧路径只保留必要兼容
- 文档与测试同步完成
13. 关键风险与应对
13.1 最大风险:LocalID 不稳定
风险:
- reimport 后子资产重排
- 场景与 prefab 引用失效
应对:
- 在 Phase 1 之前先写清
LocalID规则 - 在 Phase 3 前就建立稳定性测试
13.2 第二风险:轴系与缩放规则前后不一致
风险:
- 同一模型在 direct load、artifact load、scene instantiate 三条路径下结果不一致
应对:
- 明确标准化规则只允许一个真值来源
- 写入 importer settings 并进入测试
13.3 第三风险:编辑器体验与底层数据不同步
风险:
- Inspector 改了设置但 reimport 行为不稳定
- Project 面板显示的是
Model,内部实际仍按Mesh走
应对:
- 先完成 Resource/AssetDatabase 语义,再接 editor UI
- 不允许 editor 先行伪装完成
13.4 第四风险:过渡期双轨逻辑长期共存
风险:
MeshLoadersource import 与ModelImportersource import 两套路径并行,长期维护成本失控
应对:
- 在 Phase 6 明确收紧旧路径
- 把 source import 主入口统一到
ModelImporter
14. 本轮完成标志
当以下条件同时成立时,本轮才算真正完成:
.obj/.fbx/.gltf/.glb/...的主资产统一为ModelModelartifact 已正式落地并进入ResourceManagerOBJ能导入成简化ModelFBX能导入成保留 hierarchy 的静态Model- 模型导入设置已写入
.meta并进入 reimport 逻辑 - editor 中已具备 Model Importer Inspector
- 拖模型到场景时会生成
GameObject层级,而非单个烘平 mesh - 子资产
LocalID在普通 reimport 下稳定 - 测试已覆盖真实
FBXfixture 的关键路径
15. 一句话结论
这一轮不是“给 FBX 补支持”,而是把 XCEngine 的外部模型资源体系从“以 Mesh 为主资产的静态导入器”升级成“以 Model 为主资产、以子资产和稳定 reimport 为基础、可持续扩展到骨骼动画的 Unity 风格模型工作流”。