Three.js GLB 首屏慢:Draco 压缩实战(10.6MB→596KB)+ 解码器配置

0 阅读2分钟

环境:Three.js r160+ / Windows / Zipoly 桌面端 v2.1.0(Draco 引擎)。问题:H5 展示首屏 8s+,Network 定位到 46MB 的 GLB。处理流程记录如下,命令和代码都是可直接抄的。

screenshot-compress-start.webp

步骤一:确认瓶颈

DevTools → Network → 按大小排序。GLB 排第一且 >5MB,坐实。顺便看下有没有 4K 贴图和未压缩 HDR 混进来——它们经常是共犯,别只盯着模型文件。

步骤二:压缩(Draco Level 7)

命令行方案是 gltf-pipeline:

gltf-pipeline -i model.glb -o model_out.glb --draco.compressionLevel 7

我用的是 Zipoly 桌面端(美术同事用不了命令行):模型优化页 → 引擎选 Draco → 强度 7 → 开始优化。结果:

输入  ShanDiChe.glb  10.6 MB
输出  ShanDiChe_optimized.glb  596 KB  (-94.5%)
顶点 278,516 / 三角面 190,916 / 材质 20
官方提示: Web 端加载预计提速约 76%

screenshot-compare.webp 注意:已压过的模型再跑 Meshopt 几乎无效(实测 846KB→815KB),别浪费时间。反过来,Meshopt 的场景图优化(合并网格实例降 Draw Call、保留命名节点)适合做完首压后的结构微调,两个引擎是配合关系不是替代关系。

步骤三:Three.js 配解码器(必做)

不配 decoder 直接黑屏,报错还不直观。完整代码:

import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js';

const draco = new DRACOLoader();
draco.setDecoderPath('https://www.gstatic.com/draco/versioned/decoders/1.5.6/');

const loader = new GLTFLoader();
loader.setDRACOLoader(draco);

loader.load('model_optimized.glb', (gltf) => {
  scene.add(gltf.scene);
});

decoder 也可以 npm 装 three/examples/jsm/libs/draco/ 后走本地路径,避免外链依赖。内网项目必须本地化,别指望用户环境能访问 gstatic。

步骤四:进度反馈

loader.load(url, onLoad, (e) => {
  if (e.total) bar.style.width = `${(e.loaded / e.total) * 100}%`;
});

有进度条的三秒,比白屏的三秒体验好一档。这是交互设计常识,但十个项目九个忘。

步骤五:懒加载兜底

首屏只放主视角模型,其余 IntersectionObserver 触发再加载。模型压到 1MB 内还嫌慢的场景,就该上这招了——压缩解决「单个体积」,懒加载解决「总量」。

结果与坑

  • 首屏 8s → 2s 内(46MB 源模型先在 Blender 里粗减面再压的)
  • 坑 1:Draco 压完忘配解码器,黑屏查了半小时
  • 坑 2:带骨骼动画的模型压缩收益波动大,先试压再批量
  • 坑 3:老旧 WebView(无 WebGL2)环境先拿真机验证解码兼容

模型已经很低面数还嫌大?那是内容决定的,改做懒加载吧,别跟压缩较劲。有具体报错或参数疑问的,评论区丢出来一起看。