如何访问three.js中必须声明在函数内部的OBJ模型对象
问题根因
这不是变量作用域导致的访问失败,本质是异步资源加载的时序问题:
页面初始化后animate渲染循环就会逐帧执行,但MTL、OBJ资源的网络加载需要耗时,加载完成前你在外部声明的house变量值始终为undefined,此时直接读取house.position属性就会抛出类型错误,和你预声明变量的写法没有关系。
可直接落地的解决方法
方法1:动画循环内增加空值判断(零成本适配现有代码)
不需要重构现有加载逻辑,只需要在操作house对象前先判断它是否已经完成加载赋值,等模型加载完成后再执行位移逻辑即可。
修改后的animate函数代码如下:
function animate(){ // 模型加载完成、house被赋值后才执行位移 if(house){ house.position.x += 0.01; // 步长建议调小,否则模型移动速度过快直接飞出视野 } renderer.render(scene,camera); sLightHelper.update(); }
这个写法改动最小,完全适配你当前的代码结构,是单模型场景下最常用的处理方式。
方法2:封装加载Promise,等模型就绪后再启动渲染循环(结构更清晰)
如果不想在渲染循环里加判断,可以把MTL+OBJ的串联加载逻辑封装为Promise,等模型加载完成、house变量完成赋值后,再启动渲染循环,从流程上避免访问到未初始化的对象。
核心实现代码:
// 封装模型加载方法 function loadHouse() { return new Promise((resolve, reject) => { const mtlLoader = new MTLLoader(); mtlLoader.load( '../source/MaryStanfordLifeboatHouse02.mtl', (materials)=>{ materials.preload(); const objLoader = new OBJLoader() objLoader.setMaterials(materials) objLoader.load( '../source/MaryStanfordLifeboatHouse02.obj', (object)=>{ scene.add(object); object.rotation.x = 1/2 * Math.PI; object.rotation.y = Math.PI; resolve(object); }, undefined, (err)=>reject(err) ) }, undefined, (err)=>reject(err) ) }) } let house = null; // 等模型加载完成后再启动渲染循环 loadHouse().then(model => { house = model; renderer.setAnimationLoop(animate); }) function animate(){ // 启动循环时house必然已完成赋值,不需要额外判断 house.position.x += 0.01; renderer.render(scene,camera); sLightHelper.update(); }
注意事项
- 不要把所有动画、交互逻辑全部堆在OBJ加载的回调函数内部,后续如果新增多模型加载、GUI控制等逻辑,代码可维护性会极差
- 位移步长不要设置为1,Three.js默认单位为1米,每帧移动1米会导致模型瞬间移出视野,建议根据实际效果在0.01~0.1区间调整
- 现有代码中材质加载失败的日志存在拼写错误,
Material Eror可修正为Material Error,不影响运行但方便后续排查加载问题
内容的提问来源于stack exchange,提问作者Noone
相关产品推荐
相关产品推荐

