Three.js加载GLTF模型过慢问题求助及代码排查
解决Three.js GLB模型加载缓慢的问题
我帮你梳理了代码和问题,有几个关键点很可能是导致加载慢的原因,咱们一步步来排查修复:
1. 修复DRACOLoader的配置(最核心的问题)
你创建了DRACOLoader但没有设置解码器文件的路径,Three.js的DRACOLoader需要加载对应的解码文件(比如draco_decoder.js、draco_wasm_wrapper.js)才能解析DRACO压缩的模型。如果路径没配置,浏览器会从当前页面路径尝试加载,大概率会404失败,导致模型只能以未压缩的原始格式加载(体积会大很多,自然慢)。
修改loadDraco6141012函数:
function loadDraco6141012( src ) { var loader = new THREE.GLTFLoader(); const dracoLoader = new THREE.DRACOLoader(); // 这里要替换成你项目中DRACO解码器文件的实际路径 dracoLoader.setDecoderPath('../gltf/libraries/draco/'); // 优先用wasm解码器,性能更好;如果兼容性有问题可以改用'js' dracoLoader.setDecoderConfig({type: 'wasm'}); loader.setDRACOLoader(dracoLoader); // 后续加载逻辑不变 loader.load( src, function( gltf ) { gltf.scene.traverse( function ( child ) { if ( child.isMesh ) { child.material.envMap = envMap; child.material.envMapIntensity = 0.8; mesh = child; } } ); scene.add( gltf.scene ); }, function ( xhr ) { if ( xhr.lengthComputable ) { percentComplete = xhr.loaded / xhr.total * 100; console.log( "Loading Model - " + Math.round(percentComplete, 2) + "%" ); document.getElementById("lowPoly_progress").innerHTML = "Loading Raw Model " + Math.round(percentComplete, 2) + "%"; document.getElementById("load_lowPoly").value = percentComplete; } } ); }
注意:你需要从Three.js官方示例的examples/jsm/libs/draco目录下,把解码器文件复制到你项目的对应路径中。
2. 修正相机比例与废弃API
你的相机宽高比计算虽然数值上没问题,但写法容易混淆;另外还有一个废弃的API会导致控制台报错,间接影响性能:
// 替换init函数中的相机与渲染器配置 function init() { camera.position.z = 0; camera.position.y = 0; camera.position.x = 2000.00; const canvasWidth = window.innerWidth / 1.15; const canvasHeight = 800; renderer.setPixelRatio( window.devicePixelRatio ); renderer.setSize( canvasWidth, canvasHeight ); renderer.physicallyCorrectLights = true; // 废弃的gammaOutput改用outputEncoding renderer.outputEncoding = THREE.GammaEncoding; renderer.gammaFactor = 2.8; renderer.setClearColor( 0xf2f2f2, 1 ); camera.aspect = canvasWidth / canvasHeight; camera.updateProjectionMatrix(); updateWindow(); // ... 其他逻辑 } // 修正onWindowResize函数 function onWindowResize() { const canvasWidth = window.innerWidth / 1.15; camera.aspect = canvasWidth / windowHeight; camera.updateProjectionMatrix(); renderer.setSize( canvasWidth, windowHeight ); }
3. 优化HDR环境贴图的处理逻辑
你在加载HDR后同步执行了大量纹理转换操作,会阻塞主线程,影响模型加载。可以用Promise封装HDR加载,确保模型在HDR处理完成后再赋值环境贴图:
function createCubeMap( src, res ) { return new Promise((resolve) => { new THREE.RGBELoader().setDataType( THREE.UnsignedByteType ).load( src, function ( texture ) { var cubeGenerator = new THREE.EquirectangularToCubeGenerator( texture, { resolution: res } ); var pmremGenerator = new THREE.PMREMGenerator( cubeGenerator.renderTarget.texture ); var pmremCubeUVPacker = new THREE.PMREMCubeUVPacker( pmremGenerator.cubeLods ); envMap = pmremCubeUVPacker.CubeUVRenderTarget.texture; cubeGenerator.update( renderer ); pmremGenerator.update( renderer ); pmremCubeUVPacker.update( renderer ); // 及时释放无用资源,避免内存泄漏 pmremGenerator.dispose(); pmremCubeUVPacker.dispose(); cubeGenerator.dispose(); texture.dispose(); resolve(envMap); } ); }); } // 修改init为异步函数,先加载HDR再加载模型 async function init() { // ... 相机、渲染器配置 updateWindow(); // 等待HDR处理完成后再加载模型 envMap = await createCubeMap( "../gltf/hdri/machine_shop_02_1k.hdr", 1024 ); loadDraco6141012( "../gltf/assets/PromoModel.glb" ); }
4. 优化进度回调的DOM操作
频繁更新DOM会占用主线程,给进度回调加个节流,只在进度变化明显时更新:
let lastProgress = 0; // 替换loadDraco6141012中的进度回调 function ( xhr ) { if ( xhr.lengthComputable ) { percentComplete = xhr.loaded / xhr.total * 100; const currentProgress = Math.round(percentComplete); // 只有进度变化超过1%时才更新DOM if (currentProgress !== lastProgress) { lastProgress = currentProgress; console.log( "Loading Model - " + currentProgress + "%" ); document.getElementById("lowPoly_progress").innerHTML = "Loading Raw Model " + currentProgress + "%"; document.getElementById("load_lowPoly").value = currentProgress; } } }
5. 服务器端优化建议
- 开启Gzip/Brotli压缩:GLB、HDR这类文件压缩后体积会大幅减小,加载速度显著提升。
- 配置HTTP缓存:让浏览器缓存静态资源,避免重复下载。
先优先修复DRACOLoader的路径问题,这应该是导致加载慢的最主要原因,再逐步验证其他优化点。
内容的提问来源于stack exchange,提问作者Miger




