前言
使用前端three.js加载3d模型过程中,往往会出现模型大小过大导致前端加载时间过长,降低用户体验。
 本文所记录的是笔者在使用gltf-pipeline压缩3d模型中踩坑DRACOLoader与解决的一个过程。
所采用的three库版本为 ^0.138.2
解决方案与介绍
通过gltf-pipeline可以大幅度压缩gltf/glb模型文件。
并且有如下的作用
- 将 glTF 转换为 glb(和反向)
 - 将缓冲区/纹理保存为嵌入或单独的文件
 - 将 glTF 1.0 模型转换为 glTF 2.0(使用KHR_techniques_webgl和KHR_blend扩展)
 - 应用Draco网格压缩
 
安装
npm install -g gltf-pipeline
或者
yarn global add gltf-pipeline
常用压缩命令
gltf-pipeline -i model.glb -o modelDraco.glb -d
使用 Draco 压缩网格 model.glb 文件,modelDraco.glb为压缩后输出文件名

gltf-pipeline -i model.glb -o modelDraco.glb -d -s
压缩并编写单独的缓冲区、着色器和纹理。

在three.js中使用Draco压缩网格后的文件
坑与解决过程
在多次百度之后写出的代码
let dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath("path"); 
dracoLoader.preload();
const loader = new GLTFLoader().setPath("path");
loader.setDRACOLoader(dracoLoader);
loader.load("modelName", (gltf) => {
    scene.addObject(gltf.scene);
    gltf = null;
});
在这里我遇到了一个大坑:
Uncaught SyntaxError: Unexpected token '<'
 
解决:
在问题过程排查中,发现网络请求是请求了模型数据的

后续发现bolb:xxx的请求不是写的应用层所发出的
 之后通过阅读DRACOLoader.js的源码得
 
 
 
网络请求中bolb:xxx请求是由第250行URL.createObjectURL所创建的,创建该请求需要
- draco_decoder.js
 - draco_wasm_wrapper.js
 - draco_decoder.wasm
 
并且请求的路径是使用setDecoderPath方法所设定
后续查阅资料得到
- 
draco_decoder.js— Emscripten 编译的解码器,与任何现代浏览器兼容。 - 
draco_decoder.wasm— WebAssembly 解码器,与较新的浏览器和设备兼容。 - 
draco_wasm_wrapper.js— WASM 解码器的 JavaScript 包装器。 
在node_modules安装的包中获取three版本对应的draco路径为
 node_modules\three\examples\js\libs

将改文件夹复制到public文件夹下并在DRACOLoader.setDecoderPath时候设置该对应路径即可
最后的解决代码与自己的封装
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
/**
 * 
 *  path:存放模型父路径
 *  modelName:模型名
 *  setCenter:是否居中
 *  scale:模型的缩放比设定
 *  position:模型的位置
 *  rotation:模型的局部旋转
 */
function loadModuleByDRACOLoader(
    path,
    modelName,
    setCenter,
    scale,
    position,
    rotation
) {
    let scaleVec3, positionVec3;
    if (typeof scale == "number") {
        scaleVec3 = new THREE.Vector3(scale, scale, scale);
    } else {
        scaleVec3 = new THREE.Vector3(scale.x, scale.y, scale.z);
    }
    if (typeof position == "number") {
        positionVec3 = new THREE.Vector3(position, position, position);
    } else {
        positionVec3 = new THREE.Vector3(position.x, position.y, position.z);
    }
    let dracoLoader = new DRACOLoader();
    dracoLoader.setDecoderPath("./moduler/draco/"); // 设置public下的解码路径,注意最后面的/
    dracoLoader.setDecoderConfig({ type: "js" }); //使用兼容性强的draco_decoder.js解码器
    dracoLoader.preload();
    const loader = new GLTFLoader().setPath(path);
    loader.setDRACOLoader(dracoLoader);
    return new Promise((res, rj) => {
        loader.load(modelName, (gltf) => {
            if (setCenter) {
                gltf.scene.traverse(function(child) {
                    if (setCenter && child.isMesh) {
                        child.geometry.center();
                    }
                });
            }
            gltf.scene.scale.copy(scaleVec3);
            gltf.scene.position.copy(positionVec3);
            if (rotation) {
                gltf.scene.rotation.copy(rotation);
            }
            scene.add(gltf.scene);
            res(gltf.scene);
            gltf = null;
        });
    });
}
调用
loadModuleByDRACOLoader('./moduler/', "grow4-processed.glb", false, 1, 0)
结语
因为遇到这个坑之后没有找到对应的解决方法,所以写了该文章作为记录也给遇到相同问题的开发者避坑。
还有🎇🎇大三求内推🎇🎇