Three.js中Car类方法返回Mesh为undefined的问题求助
问题分析:异步加载的执行顺序坑
这是个典型的异步操作问题!THREE.BinaryLoader.load()是异步方法——它会在后台默默加载模型文件,不会暂停后续代码的执行。所以当你在load()外面打印mesh时,回调函数里创建Mesh的逻辑还根本没跑呢,自然输出undefined;而回调内部打印正常,是因为只有当模型文件加载完成后,这段代码才会被触发执行。
下面给你三种实用的解决方案,你可以根据自己的代码场景选择:
方案1:把后续逻辑直接塞进回调里(最简单)
既然只有回调里能拿到完整的mesh,那直接把需要用mesh的代码写到回调里,或者抽成一个专门的方法在回调里调用:
this.loadCarToScene = function (carsVector, carName) { var carLoader = new THREE.BinaryLoader(); const carData = carsVector[Object.keys(carsVector)[0]]; // 先把重复的对象提出来,代码更简洁 carLoader.load(carData.url, function(geometry) { geometry.sortFacesByMaterialIndex(); console.log("url--->" + carData.url); var m = []; for (var i in carData.mmap) { m[i] = carData.mmap[i]; } const mesh = new THREE.Mesh(geometry, m); mesh.rotation.set(...carData.init_rotation); // 用set方法简化代码 mesh.scale.setScalar(carData.scale); mesh.position.set(...carData.position); scene.add(mesh); // 在这里写所有需要用到mesh的逻辑,或者调用专门的处理方法 this.handleLoadedCar(mesh); }.bind(this)); // 别忘了绑定this,不然拿不到类里的其他方法 }; // 专门处理加载完成后的mesh this.handleLoadedCar = function(mesh) { console.log("终于拿到可用的mesh啦:", mesh); // 比如给mesh加动画、绑定点击事件、调整材质等等 };
方案2:用Promise包装(最灵活,推荐)
如果你的代码里有多处需要等待这个mesh加载完成,把加载过程包装成Promise是更好的选择,这样就能用async/await来优雅处理异步:
this.loadCarToScene = async function (carsVector, carName) { return new Promise((resolve, reject) => { var carLoader = new THREE.BinaryLoader(); const carData = carsVector[Object.keys(carsVector)[0]]; carLoader.load( carData.url, // 加载成功的回调 function(geometry) { geometry.sortFacesByMaterialIndex(); var m = []; for (var i in carData.mmap) { m[i] = carData.mmap[i]; } const mesh = new THREE.Mesh(geometry, m); mesh.rotation.set(...carData.init_rotation); mesh.scale.setScalar(carData.scale); mesh.position.set(...carData.position); scene.add(mesh); resolve(mesh); // 把加载好的mesh传递出去 }, // 加载进度的回调(可选) function(xhr) { console.log(`加载进度: ${(xhr.loaded / xhr.total * 100)}%`); }, // 加载失败的回调 function(error) { console.error("模型加载失败:", error); reject(error); // 把错误抛出去 } ); }); }; // 使用的时候这么写: async function initMyCar() { try { const carMesh = await yourCarInstance.loadCarToScene(carsVector, carName); console.log("加载完成的mesh:", carMesh); // 这里就可以放心使用carMesh做任何操作了 } catch (err) { console.error("初始化汽车失败:", err); } }
方案3:把mesh存为类的实例属性
如果你的Car类需要在多个方法里用到这个mesh,可以把它作为类的属性存储,同时加个加载完成的标记,避免后续操作时mesh还没加载好:
// 先在类的构造函数里初始化属性 constructor() { this.carMesh = null; this.isCarLoaded = false; } this.loadCarToScene = function (carsVector, carName) { var carLoader = new THREE.BinaryLoader(); const carData = carsVector[Object.keys(carsVector)[0]]; carLoader.load(carData.url, function(geometry) { geometry.sortFacesByMaterialIndex(); var m = []; for (var i in carData.mmap) { m[i] = carData.mmap[i]; } this.carMesh = new THREE.Mesh(geometry, m); this.carMesh.rotation.set(...carData.init_rotation); this.carMesh.scale.setScalar(carData.scale); this.carMesh.position.set(...carData.position); scene.add(this.carMesh); this.isCarLoaded = true; // 标记加载完成 console.log("mesh加载完成:", this.carMesh); }.bind(this)); // 绑定this,确保能访问到类的属性 }; // 后续其他方法里使用mesh时,先检查状态 this.moveCar = function() { if (this.isCarLoaded && this.carMesh) { this.carMesh.position.x += 0.1; // 比如让汽车往前移动 } else { console.log("别急,模型还在加载呢!"); } };
内容的提问来源于stack exchange,提问作者Ioana B
相关产品推荐
相关产品推荐

