Skip to content

viewer.model — ModelManager

设计意图

viewer.model 是模型生命周期域:一个 .fmbv 模型从装入场景(load)、被查询浏览,到被替换或卸载(unload)的全部状态都收敛在这里。加载是流式的——load() 在结构树骨架就绪时就 resolve,此刻即可取景、选中、遍历结构树,几何分块在后台渐进到达。ModelSource 支持 URL / URL 对象 / Uint8Array / Blob / 自定义 Range fetcher 五种形态(见模型数据 (.fmbv))。

域内的统一句柄是结构树节点 NodeId:元数据查询(getNodeInfo / iterateNodes / findNodesByName / getNodeProperties)与外观操作(颜色 / 可见性 / 高亮)都以它为入参。外观操作的关键抽象是覆盖层——染色与显隐不修改原始材质,只在其上叠加可撤销的覆盖,对应的 unset* / reset* 总能恢复模型原貌。这让「按检验结果染色」「隔离显示」这类业务标注可以放心叠加、一键退出。

何时用它:凡是「关于模型本体」的事——加载进度、BOM 结构、零件显隐与染色、业务属性——都从 viewer.model 入手;「往哪看」归 viewer.camera,「用户选了什么」归 viewer.selection

典型用法

按 BOM 节点隔离显示(只留目标子树,隐藏其余叶子):

ts
const targets = viewer.model.findNodesByName("BRAKE_ASSY");
viewer.model.isolateNodes(targets); // 装配自动展开为子树,其余叶子隐藏
viewer.camera.fitView({ nodeIds: targets });

按检验结果给零件染色,复查后一键恢复:

ts
viewer.model.setNodesColor(failedIds, { r: 0.9, g: 0.2, b: 0.2 });
viewer.model.setNodesColor(warnIds, { r: 0.95, g: 0.75, b: 0.1 });
// ……复查完毕,恢复原始材质色
viewer.model.resetNodesColor();

选中零件时读它的业务属性(按需拉取,自动缓存):

ts
viewer.on("selection-changed", async (e) => {
  const item = e.current[0];
  if (!item) return;
  const props = await viewer.model.getNodeProperties(item.nodeId);
  console.table(props.map((p) => ({ group: p.group, key: p.key, value: p.value })));
});

注意事项

  • load() 的 resolve 时机是骨架就绪,不是几何全部到达——resolve 后立即取景 / 遍历结构树没问题,但几何仍在后台流式加载;全量到齐以 model-loaded 事件为准。
  • 再次 load() 自动卸旧:旧模型触发 model-disposed,未完成的旧加载以 Cancelled reject;不需要先手动 unload()
  • 错误模式分两类:写操作(setNodesColor / setNodesVisibility 等)在未加载时抛 ViewerError(ModelNotLoaded);查询类(getNodeInfo / getBoundingBox 等)未加载返回 null / 空数组,不抛错。
  • 透明度 API 预留至 v2:setNodesOpacity 等当前调用必抛错,getNodeOpacity 恒返回 1。
  • 隔离显示用 isolateNodes(ids):恰好显示 ids(装配节点自动展开为整个子树),其余叶子隐藏;保留集内先前隐藏的叶子复显;空数组静默 no-op。可见性实际变化时(hide / show / isolate / reset)触发 visibility-changed 事件(payload 带当前隐藏叶子总数 hiddenCount)。相机编排(isolate 保存位姿并 fit、Show all 复显并还原)由 viewer-ui 的 isolateZoom helper 负责,引擎侧不动相机。

完整签名与延伸