纹渊 HarmonyOS 7 工程实战(03):GLTF/GLB 模型库的数据目录设计

📅 2026/7/19 9:15:33 👁️ 阅读次数 📝 编程学习
纹渊 HarmonyOS 7 工程实战(03):GLTF/GLB 模型库的数据目录设计

一、问题与目标

纹渊的 3D 预览需要面对多个载体模型:头盔、动物、杯体或其他商品形态。模型如果只是散落在资源目录里,页面很快会变成一堆硬编码路径;后续新增载体、替换模型或做降级提示时,维护成本会越来越高。

更稳的做法是把模型当成目录数据来管理。每个模型都应该有名称、资源路径、默认缩略图、适用纹样区域和失败提示。页面只消费目录项,不直接关心底层资源怎么组织。这样模型库扩展时,页面状态不会跟着重写。

二、实现思路

模型目录可以先从最小字段开始:id、displayName、resource、previewImage、materialSlot 和 fallbackText。id 用来保存选择状态,resource 指向 GLTF/GLB 资源,materialSlot 标记纹样最终要进入哪个材质节点,fallbackText 用于模型加载失败时的界面提示。

加载流程也要分层:目录读取负责提供候选项,模型加载负责创建 Scene,材质绑定负责把纹样结果放进节点,页面只处理选中态和错误态。这样做的好处是模型数量增加时,业务链路仍然保持稳定。

模型字段处理方式
id保存用户选择,避免显示名变更影响状态恢复
resource指向 GLTF/GLB 资源,统一交给模型加载服务处理
materialSlot标记纹样需要替换的材质节点或贴图槽位
fallbackText加载失败时给出可理解的降级说明

三、关键实现

模型加载服务只暴露一个入口:接收资源路径,返回可绑定材质的场景对象。页面不直接创建底层资源,也不把节点查找逻辑写进组件。

async function loadModel(path: ResourceStr): Promise<Scene> { const scene = await Scene.load(path) const factory = scene.getResourceFactory() if (scene.root !== undefined) { scene.root.position = { x: 0, y: 0, z: 0 } } if (factory !== null) { const camera = await factory.createCamera({ name: 'main-camera' }) scene.root?.addChild(camera) } return scene }

这种写法把 3D 资源的不确定性包在服务层里。模型文件缺失、节点名称变化、材质槽位不匹配,都可以在服务层返回明确错误,页面只需要显示降级状态或切换到二维预览。

目录化还有一个实际好处:不同载体可以共享同一套页面组件。新增一个 GLB 模型时,优先改目录数据和材质槽位,不需要改创作页的交互结构。

四、失败场景与取舍

模型库最容易踩的坑是把资源路径和页面选择写死。短期看能跑,长期看每新增一个载体都要改页面。另一个问题是材质节点没有稳定标识,模型换版后贴图失效,但页面仍然显示“生成成功”。

降级策略要提前准备。模型加载失败时,不应该让页面停在空白 3D 容器;可以保留 Canvas 预览、显示模型资源不可用提示,并允许用户继续导出平面纹样。这样 3D 能力异常不会拖垮整个创作流程。

五、验证步骤

  1. 打开创作入口,确认标题、主要卡片、底部操作区和预览区域显示正常。
  2. 走一遍主流程,观察加载态、成功态和下一步按钮是否同步变化。
  3. 人为制造空输入、重复点击或不可用条件,确认页面给出可理解的提示。
  4. 返回上一页再进入,确认选中态、预览结果和关键状态没有漂移。
  5. 在较窄窗口和较宽窗口各看一遍,确认文字、卡片和按钮没有重叠。

六、总结

GLTF/GLB 模型库的数据目录设计,核心是把资源、材质槽位和失败提示从页面里拿出来。页面只处理选中态,模型服务处理资源细节,后续扩展载体时会更稳。