Autodesk Viewer中克隆GLB模型:位置关联、ID重复问题求助
问题分析与解决方案
为什么model.clone()无法满足需求
Autodesk Viewer中的Model.clone()并非用于创建完全独立的模型实例,它本质是浅拷贝,会与原模型共享几何数据、材质、变换矩阵等核心资源——这就是调整克隆模型位置时原模型同步变化、手动修改ID也无法彻底分离两者的原因。你自定义的递归克隆函数也无法处理Viewer模型内部复杂的渲染管线引用与状态管理,反而可能引发未知错误。
可行方案
方案1:重复加载GLB并指定位置
最简单的方式是多次调用viewer.loadModel()加载同一GLB文件,每次通过loadOptions指定不同的放置变换矩阵,直接创建完全独立的模型实例:
onSuccessCallback(model) { this.model = model; // 创建第一个克隆体 this.loadClonedModel({ x: 10, y: 0, z: 0 }); // 创建第二个克隆体 this.loadClonedModel({ x: -10, y: 3, z: 0 }); } loadClonedModel(position) { const modelUrl = './GLTF/fireExtinguisher.glb'; const loadOptions = { keepCurrentModels: true, applyRefPoint: true, placementTransform: new THREE.Matrix4().makeTranslation(position.x, position.y, position.z) }; this.viewer.loadModel(modelUrl, loadOptions); }
方案2:用SceneBuilder扩展创建独立实例
若想避免重复加载文件以提升性能,可通过SceneBuilder提取原模型的几何与材质数据,生成全新的独立模型:
- 初始化SceneBuilder扩展:
async initSceneBuilder() { const sceneBuilderExt = await this.viewer.loadExtension('Autodesk.SceneBuilder'); this.sceneBuilder = sceneBuilderExt; return sceneBuilderExt; }
- 提取原模型片段并创建克隆体:
async createClonedModel(originalModel, position) { const sceneBuilder = await this.initSceneBuilder(); const group = new THREE.Group(); // 遍历原模型所有片段 const fragIds = originalModel.getFragmentList().fragments.keys(); for (const fragId of fragIds) { const fragProxy = this.viewer.impl.getFragmentProxy(originalModel, fragId); await fragProxy.getAnimTransform(); // 获取片段当前变换矩阵 // 克隆几何与材质(确保完全独立) const originalMesh = fragProxy.getMesh(); const clonedGeometry = originalMesh.geometry.clone(); const clonedMaterial = originalMesh.material.clone(); // 创建新网格并应用原始片段的变换 const newMesh = new THREE.Mesh(clonedGeometry, clonedMaterial); newMesh.matrix.copy(fragProxy.matrixWorld); newMesh.matrixAutoUpdate = false; group.add(newMesh); } // 设置克隆体位置 group.position.set(position.x, position.y, position.z); // 将组添加为新模型 const clonedModel = await sceneBuilder.addNewModel({ modelName: 'ClonedFireExtinguisher', rootNode: group }); this.viewer.impl.invalidate(true); return clonedModel; }
- 在成功回调中调用:
onSuccessCallback(model) { this.model = model; this.createClonedModel(model, { x: 10, y: 0, z: 0 }); this.createClonedModel(model, { x: -10, y: 3, z: 0 }); }
注意事项
- 方案1实现简单,但多次加载同一文件会增加网络请求(可通过浏览器缓存缓解)。
- 方案2性能更优,但需处理片段遍历、资源克隆等细节,确保所有数据完全独立。
- 使用SceneBuilder时,需确保Viewer版本支持该扩展,并正确处理异步初始化流程。
内容的提问来源于stack exchange,提问作者Predrag Jokovic
相关产品推荐
相关产品推荐

