纹渊 HarmonyOS 7 工程实战(04):3D 材质贴图:纹样如何进入模型节点

纹渊 HarmonyOS 7 工程实战(04):3D 材质贴图:纹样如何进入模型节点

一、问题与目标

3D 预览真正有价值的地方,不是把模型摆出来,而是让用户生成的纹样进入模型材质。否则 3D 容器只是一个静态展示区,和创作流程没有形成闭环。

纹样进入 3D 模型通常会经过几步:生成或绘制得到图片,图片进入可访问的沙箱路径,模型加载完成后找到目标材质节点,再把贴图绑定到节点上。任意一步失败,页面都要能说明原因,而不是只留下一个灰色预览区。

二、实现思路

实现上要先明确材质槽位。不同模型的可贴图区不一样,杯体可能对应 bodyMaterial,头盔可能对应 shellMaterial,动物模型可能只有部分节点适合替换。把槽位写进模型目录,比在页面里按模型名称判断更稳。

异步顺序也要收敛。图片结果和模型场景谁先回来都可能发生,因此状态层需要同时记录 textureReady 和 modelReady。只有两者都满足时才执行绑定;否则页面显示等待、降级或重试入口。

贴图链路处理方式
纹样结果来自 AI 生图或 Canvas 绘制,先统一成图片载荷
沙箱路径把临时结果转成运行时可访问的资源
材质槽位根据模型目录找到目标节点,不在页面里硬编码
预览刷新绑定成功后刷新 3D 视图,失败时回到二维预览

三、关键实现

贴图绑定不适合直接散落在点击事件里。下面片段保留模型加载入口,实际项目中可以在服务层继续补上材质槽位查找和错误返回。

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 区域可以显示默认材质;如果图片已经生成但模型加载失败,页面可以保留平面预览和导出能力。这样用户不会因为 3D 单点失败而失去整个创作结果。

四、失败场景与取舍

材质贴图最容易出现“看起来成功、实际没生效”的问题。比如节点名称变化后仍然返回成功,或者贴图尺寸不合适导致模型表面模糊。服务层应该返回绑定结果和目标槽位,必要时记录失败原因。

另一个取舍是不要把 3D 预览当成唯一结果。对创作类应用来说,AI 图和 Canvas 图本身也是成果。3D 预览用于增强确认感,但失败时必须能降级,不应该阻断保存、导出和分享。

五、验证步骤

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

六、总结

3D 材质贴图的关键是把图片结果、模型资源和材质槽位串成可恢复的异步链路。节点绑定成功就刷新预览,失败则保留二维结果和明确提示。