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
相关产品推荐
相关产品推荐

