共计 1860 个字符,预计需要花费 5 分钟才能阅读完成。
技术背景
Draco 是 Google 开发的开源 3D 几何压缩库,通过以下方式显著优化 3D-Tiles 性能:

- 顶点属性压缩:坐标 / 法线 /UV 等数据可缩减 50-95%
- 拓扑优化:使用边缘破坏器算法重构网格连接关系
- 量化编码:将浮点数转换为低比特整数存储
在 3D-Tiles 中应用时,典型.b3dm 文件的几何部分经 Draco 压缩后,网络传输体积可减少 70% 以上。
痛点分析
实际开发中主要遇到三类问题:
- 解码性能瓶颈 :
- 复杂模型在主线程解码导致界面冻结
-
WASM 内存分配不当引发频繁 GC
-
内存泄漏陷阱 :
- 未释放解码中间产物
-
多实例共享解码器时的引用残留
-
纹理异常 :
- UV 坐标量化误差导致贴图错位
- 压缩后的顶点属性与材质不匹配
解决方案
集成 Draco 解码器
-
安装依赖项:
npm install @loaders.gl/draco three@0.152.0 @types/three -
初始化解码器(关键配置项):
import {DRACOLoader} from 'three/examples/jsm/loaders/DRACOLoader'; const dracoLoader = new DRACOLoader(); dracoLoader.setDecoderPath('https://www.gstatic.com/draco/versioned/decoders/1.5.6/'); dracoLoader.setWorkerLimit(4); // 根据 CPU 核心数调整
完整加载代码示例
async function loadCompressedTile(url: string) {const loader = new Tiles3DLoader();
// 关键解码配置
loader.setDRACOLoader(dracoLoader);
loader.setOptions({
'3d-tiles': {
loadGLTF: false, // 必须关闭默认 GLTF 加载
decoderType: 'draco',
},
});
try {const tile = await loader.load(url);
// 内存优化:释放解码缓冲区
tile.traverse((obj) => {if (obj.geometry?.attributes) {obj.geometry.dispose();
}
});
return tile;
} catch (err) {console.error('解码失败:', err);
// 失败时强制释放资源
dracoLoader.dispose();
throw err;
}
}
内存优化策略
- WASM 内存管理 :
- 预分配解码缓冲区:
dracoLoader.preallocWebGLBuffers(size) -
定期调用:
dracoLoader.releaseDecoderModule() -
对象池模式 :
const decoderPool = new Map<number, DRACOLoader>(); function getDecoder() {const key = performance.now(); const decoder = new DRACOLoader(); decoderPool.set(key, decoder); return {key, decoder}; }
性能对比
测试环境:Chrome 115 / i7-12700H / 32GB RAM
| 模型 | 原始大小 | 压缩后 | 解码时间 | 内存峰值 |
|---|---|---|---|---|
| 建筑群(500MB) | 498MB | 132MB | 1.8s | 1.2GB |
| 树木(80MB) | 82MB | 24MB | 0.4s | 280MB |
避坑指南
- 版本兼容性 :
- Draco 1.5.x 无法解码 2.0+ 编码的模型
-
解决方案:统一使用
@loaders.gl/draco@3.2.0 -
WebWorker 注意事项 :
// worker.js 必须包含相同版本的 draco 库 self.importScripts('draco_decoder.js'); -
纹理坐标处理 :
- 在压缩时保留 UV 精度:
encoder.SetAttributeQuantization(texCoordAttribute, 14); // 推荐 14-16bit
进阶建议
动态压缩级别选择策略:
function getCompressionLevel(vertexCount: number) {if (vertexCount > 1e6) return 7; // 高压缩比
if (vertexCount > 5e5) return 5;
return 3; // 低复杂度模型保持较高精度
}
完整示例可在 CodeSandbox 查看。实际项目中建议结合 requestIdleCallback 分帧解码,避免主线程阻塞。
正文完
发表至: 未分类
近两天内
