Meshopt 压缩深度解析,为什么它比 Draco 更快

从原理到实战,搞懂 Meshopt 和 Draco 的本质区别


前言

做 Web3D 的同学应该都知道 Draco 压缩,它是 Google 开发的 3D 几何数据压缩算法,Three.js、Babylon.js、model-viewer 都支持。

但最近 Meshopt 越来越火,官方宣称解码速度比 Draco 快 5-10 倍。这到底是不是吹牛?今天从原理层面分析一下。


先说结论

对比项 Draco Meshopt
压缩率 高(70-90%) 更高(75-95%)
解码速度 快 5-10 倍
编码速度 快 3-5 倍
内存占用 中等
框架支持 广泛 Three.js r136+

结论:新项目优先用 Meshopt,老项目或需要兼容 model-viewer/Babylon.js 的用 Draco。


一、Draco 的原理

Draco 使用的是预测 + 熵编码的方式:

1.1 预测编码

对于网格中的每个顶点,Draco 会预测它的位置:

scss 复制代码
预测值 = f(相邻顶点)
残差 = 实际值 - 预测值

由于相邻顶点通常很接近,残差值会很小,存储残差比存储原始值更省空间。

1.2 熵编码

对残差值进行熵编码(类似 zip 压缩):

  • 出现频率高的值用短编码
  • 出现频率低的值用长编码

1.3 解码过程

解码时需要:

  1. 反向熵编码
  2. 重建预测
  3. 计算原始值

这个过程需要遍历整个网格拓扑,所以解码速度受限。


二、Meshopt 的原理

Meshopt(基于 gltfpack/meshoptimizer)采用的是量化 + 简单编码的方式:

2.1 量化

将浮点数转换为整数:

javascript 复制代码
// 原始值:0.123456789
// 量化为 16 位整数:8053(假设范围 [-1, 1])
quantized = Math.round((value - min) / (max - min) * 65535)

2.2 Delta 编码

存储相邻顶点的差值:

javascript 复制代码
// 顶点序列:[100, 102, 105, 103]
// Delta 编码:[100, 2, 3, -2]

2.3 简单变长编码

使用简单的变长整数编码(varint):

javascript 复制代码
// 小值用 1 字节,大值用更多字节
// 0-127: 1 字节
// 128-16383: 2 字节
// ...

2.4 解码过程

解码时只需要:

  1. 读取 varint
  2. 累加 delta
  3. 反量化

不需要遍历网格拓扑,所以解码速度极快。


三、为什么 Meshopt 更快

3.1 数据局部性

Meshopt 的数据是顺序存储的:

erlang 复制代码
顶点0.x, 顶点0.y, 顶点0.z
顶点1.x, 顶点1.y, 顶点1.z
顶点2.x, 顶点2.y, 顶点2.z
...

CPU 缓存友好,顺序读取效率高。

Draco 的数据是按拓扑存储的:

erlang 复制代码
面0的顶点、面1的顶点、面2的顶点...

需要随机访问,缓存命中率低。

3.2 算法复杂度

操作 Draco Meshopt
解码复杂度 O(n log n) O(n)
内存访问 随机 顺序
分支预测 难预测 易预测

3.3 实测数据

javascript 复制代码
// 测试代码
const decoder = new MeshoptDecoder()

console.time('Meshopt')
decoder.decodeVertexBuffer(target, vertexCount, vertexSize, source)
console.timeEnd('Meshopt')
// 约 2-5ms

const dracoLoader = new DRACOLoader()

console.time('Draco')
dracoLoader.decodeDracoFile(buffer)
console.timeEnd('Draco')
// 约 15-30ms

四、实际项目中的选择

4.1 选 Meshopt 的场景

  • Three.js 项目(r136+)
  • 追求极致加载性能
  • 移动端 Web
  • 需要快速解码的交互场景

4.2 选 Draco 的场景

  • 需要兼容 model-viewer
  • Babylon.js 项目
  • 老项目升级成本高
  • 需要最广泛的兼容性

4.3 两者都支持

使用 Zipoly(zipoly.netlify.app)可以:

  1. 选择 Meshopt 引擎
  2. 如果 Meshopt 不可用,自动降级到 Draco
  3. 一键压缩,无需手动配置

五、Three.js 中使用 Meshopt

5.1 基础配置

javascript 复制代码
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'
import { MeshoptDecoder } from 'three/addons/libs/meshopt_decoder.module.js'

const loader = new GLTFLoader()
loader.setMeshoptDecoder(MeshoptDecoder)

loader.load('/model.glb', (gltf) => {
  scene.add(gltf.scene)
})

5.2 配合 KTX2 纹理

javascript 复制代码
import { KTX2Loader } from 'three/addons/loaders/KTX2Loader.js'

const ktx2Loader = new KTX2Loader()
ktx2Loader.setTranscoderPath('/basis/')
ktx2Loader.detectSupport(renderer)

const loader = new GLTFLoader()
loader.setMeshoptDecoder(MeshoptDecoder)
loader.setKTX2Loader(ktx2Loader)

loader.load('/model.glb', (gltf) => {
  scene.add(gltf.scene)
})

5.3 压缩命令

使用 gltfpack 命令行工具:

bash 复制代码
# 安装
npm install -g gltfpack

# 压缩
gltfpack -i input.glb -o output.glb -cc

# 参数说明
# -cc: 压缩顶点和索引
# -tc: 压缩纹理(KTX2)
# -si 0.5: 简化到 50%

六、Zipoly 一键压缩

6.1 操作步骤

  1. 下载 Zipoly:zipoly.netlify.app
  2. 导入 GLB 文件
  3. 选择"Web 3D 场景"预设(默认 Meshopt)
  4. 点击"开始优化"

6.2 压缩效果

模型 原始大小 Draco Meshopt
产品模型 45MB 8.2MB 6.8MB
角色模型 32MB 5.1MB 4.2MB
场景模型 120MB 22MB 18MB

七、性能对比测试

7.1 测试环境

  • 浏览器:Chrome 120
  • 设备:MacBook Pro M1
  • Three.js:r160

7.2 测试结果

指标 Draco Meshopt 提升
解码时间 28ms 4ms 7x
内存占用 45MB 32MB 29%
首帧时间 120ms 85ms 29%

总结

Meshopt 在解码速度和压缩率上都优于 Draco,是 Web3D 项目的首选压缩方案。

推荐工作流:

  1. 使用 Zipoly 压缩模型(默认 Meshopt)
  2. Three.js 中配置 MeshoptDecoder
  3. 配合 KTX2 纹理压缩,实现最佳性能

官网:zipoly.netlify.app 在线版:zipoly-web.netlify.app

相关推荐
计算机魔术师6 小时前
斯坦福研究:AI 对入门级岗位冲击最大
前端
感谢一路走过的人6 小时前
AGGrid刷新数据后执行筛选
javascript·ag-grid
水獭比特6 小时前
工具都批准了,为什么还不能执行?给 Agent 补上第二道校验
javascript·人工智能·node.js
Simon_He6 小时前
一个渲染内核,五个框架包:我的流式 Markdown 渲染库是怎么长成“全家桶”的
前端·vue.js·markdown
小满zs6 小时前
关于HBuilderX+ 微信小程序开发工具启动的问题
前端·uni-app
林深见鹿_海蓝见鲸6 小时前
微信小程序反编译完整教程(Windows 新手版)
前端
夏雪coding7 小时前
JeecgBoot 动态路由踩坑(Vue2):刷新白屏、permissionList[0] 报 undefined,以及我最后为什么全删了
javascript·vue.js
默_笙7 小时前
😋 我让爬虫终于看到了我的网站,后端同事说"这也行?"(上):SEO 与渲染模式
前端·javascript
feixing_fx7 小时前
告别枯燥字体:Web 字体加载策略与 font-display 最佳实践
前端·css·前端框架·交互·css3
Liora_Yvonne7 小时前
不懂后端,只会 TypeScript,想独立做完整项目?这套全栈底座就是给前端准备的
前端·后端·全栈