You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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提取原模型的几何与材质数据,生成全新的独立模型:

  1. 初始化SceneBuilder扩展:
async initSceneBuilder() {
    const sceneBuilderExt = await this.viewer.loadExtension('Autodesk.SceneBuilder');
    this.sceneBuilder = sceneBuilderExt;
    return sceneBuilderExt;
}
  1. 提取原模型片段并创建克隆体:
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;
}
  1. 在成功回调中调用:
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 02:26:01