You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

Three.js加载GLTF模型过慢问题求助及代码排查

解决Three.js GLB模型加载缓慢的问题

我帮你梳理了代码和问题,有几个关键点很可能是导致加载慢的原因,咱们一步步来排查修复:

1. 修复DRACOLoader的配置(最核心的问题)

你创建了DRACOLoader但没有设置解码器文件的路径,Three.js的DRACOLoader需要加载对应的解码文件(比如draco_decoder.jsdraco_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

火山引擎 最新活动