ThreeJS中如何复用导入对象的几何体以节省内存?
解决ThreeJS几何体复用与异步加载的问题
嘿,我一眼就看出你代码里的问题啦——OBJ加载是异步操作,这直接导致你的复用逻辑没按预期跑起来,咱们一步步拆解:
你的代码为啥不生效?
- 当你执行
obj.add(new THREE.Mesh(tmpGeo, tmpMat))时,objLoader.load的回调还没触发,tmpGeo还是你一开始创建的空BufferGeometry; - 等回调触发后,你给
tmpGeo重新赋值了加载好的几何体,但这个tmpGeo是局部变量,和已经添加到场景里的Mesh的几何体、还有geometries[ID]里存的空几何体都没有引用关系,自然不会更新。
正确的复用方案:异步流程+缓存
完全可以只加载一次几何体,之后全程复用同一个引用,核心是等异步加载完成后再使用几何体,同时把加载好的几何体存入缓存池。
第一步:封装加载逻辑为Promise(更清晰处理异步)
先把OBJ加载写成返回Promise的函数,方便后续复用和处理流程:
// 假设geometries是全局或模块级的缓存对象 const geometries = {}; function loadAndCacheGeometry(ID) { return new Promise((resolve, reject) => { const objLoader = new THREE.OBJLoader(); objLoader.load( `/models/${ID}.obj`, (loadedMesh) => { const targetGeo = loadedMesh.children[0].geometry; // 存入缓存,后续直接取用 geometries[ID] = targetGeo; resolve(targetGeo); }, undefined, // 进度回调可选 (error) => reject(error) // 错误处理 ); }); }
第二步:复用逻辑的正确写法
// 先检查缓存里有没有已加载好的几何体 const cachedGeo = geometries[ID]; if (cachedGeo) { // 直接复用,不用再加载 obj.add(new THREE.Mesh(cachedGeo, tmpMat)); } else { // 缓存没有,发起加载,完成后再创建Mesh loadAndCacheGeometry(ID) .then((geo) => { obj.add(new THREE.Mesh(geo, tmpMat)); // 之后其他地方需要用这个几何体,直接取geometries[ID]就行 }) .catch((err) => { console.error(`加载ID为${ID}的几何体失败:`, err); }); }
可选:如果已经提前添加了空几何体的Mesh
要是你因为某些原因必须先把Mesh加到场景里,之后再替换几何体,可以这么做:
// 先创建带空几何体的Mesh并添加 const tempMesh = new THREE.Mesh(new THREE.BufferGeometry(), tmpMat); obj.add(tempMesh); // 加载完成后替换几何体,同时释放空几何体的内存 loadAndCacheGeometry(ID) .then((geo) => { tempMesh.geometry.dispose(); // 释放旧几何体的内存,避免泄漏 tempMesh.geometry = geo; });
这样就能保证整个应用里,同一个ID的几何体只会被加载一次,所有用到它的Mesh都复用同一个几何体引用,完全不会有冗余内存占用~
内容的提问来源于stack exchange,提问作者user5280885
相关产品推荐
相关产品推荐

