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

Three.js中修改OBJLoader加载函数,将模型返回给上层而非直接添加场景

解决Three.js异步加载OBJ模型并返回给上层调用的问题

我懂你的痛点——Three.js里的加载器都是异步操作,你原来的写法里,OBJLoader.load的回调函数是在模型加载完成后才会执行,但你的loadObjFile函数早就执行完返回了,根本拿不到加载好的模型对象。咱们可以用Promise来封装整个加载流程,让上层调用能正确获取到返回的模型。

修改后的代码

function loadObjFile(modelConfiguration) {
  // 返回Promise,让上层通过.then或await获取加载结果
  return new Promise((resolve, reject) => {
    const mtlLoader = new THREE.MTLLoader();
    
    mtlLoader.load(
      modelConfiguration.mtl,
      (materials) => {
        materials.preload();
        const objLoader = new THREE.OBJLoader();
        objLoader.setMaterials(materials);
        
        objLoader.load(
          modelConfiguration.obj,
          (object3d) => {
            // 这里可以给模型设置你需要的属性,比如name
            if (modelConfiguration.name) {
              object3d.name = modelConfiguration.name;
            }
            // 加载成功,把模型对象传递给上层
            resolve(object3d);
          },
          undefined, // 可选:进度回调函数,比如显示加载进度
          (error) => {
            // OBJ加载失败,抛出错误
            reject(new Error(`OBJ文件加载失败: ${error.message}`));
          }
        );
      },
      undefined, // 可选:MTL加载进度回调
      (error) => {
        // MTL加载失败,抛出错误
        reject(new Error(`MTL文件加载失败: ${error.message}`));
      }
    );
  });
}

上层调用的方式

方式一:用async/await(推荐,代码更简洁)

async function setupModel() {
  try {
    const modelConfig = {
      mtl: '/path/to/your/model.mtl',
      obj: '/path/to/your/model.obj',
      name: 'MyCustomModel'
    };
    
    // 等待模型加载完成,直接拿到模型对象
    const loadedModel = await loadObjFile(modelConfig);
    
    // 这里由上层决定是否添加到场景,或者做其他处理
    scene.add(loadedModel);
    // 比如调整模型位置、缩放等
    loadedModel.position.set(0, 0, 0);
    loadedModel.scale.set(1, 1, 1);
  } catch (error) {
    console.error('模型加载出错啦:', error);
  }
}

// 调用初始化函数
setupModel();

方式二:用.then链式调用

const modelConfig = {
  mtl: '/path/to/your/model.mtl',
  obj: '/path/to/your/model.obj',
  name: 'MyCustomModel'
};

loadObjFile(modelConfig)
  .then((loadedModel) => {
    // 拿到模型后自行处理
    scene.add(loadedModel);
    loadedModel.rotation.y = Math.PI / 2;
  })
  .catch((error) => {
    console.error('模型加载出错啦:', error);
  });

为什么要这么改?

原来的load方法是异步的,当你调用loadObjFile时,函数会立即执行完毕并返回(此时模型还没加载好),而加载完成的回调是在浏览器拿到文件后才会触发的。用Promise封装后,我们可以在加载成功时通过resolve把模型传递出去,失败时通过reject抛出错误,上层就能通过异步的方式正确获取到结果,完全由上层决定是否把模型添加到场景里。

内容的提问来源于stack exchange,提问作者huj

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 06:49:15