preface

In the process of loading 3D models with front-end three.js, the model size is too large, leading to a long loading time of front-end, which reduces user experience. In this paper, the author is recorded in the use of GLTF-pipeline compression 3d model in the pit DRACOLoader and solve a process.

The three library version used is ^0.138.2

Solution and introduction

GLTF -pipeline can compress GLTF/GLB model files greatly.

And it has the following functions

  • Convert glTF to GLB (and reverse)
  • Save buffers/textures as embedded or separate files
  • Convert glTF 1.0 model to glTF 2.0 (using KHR_techniques_webgl and KHR_blend extensions)
  • Apply Draco mesh compression

The installation

npm install -g gltf-pipeline
Copy the code

or

yarn global add gltf-pipeline
Copy the code

Common Compression commands

gltf-pipeline -i model.glb -o modelDraco.glb -d
Copy the code

Use Draco to compress the grid model. GLB file, modelDraco. GLB is the output file name after compression

gltf-pipeline -i model.glb -o modelDraco.glb -d -s
Copy the code

Compress and write separate buffers, shaders, and textures.

Use Draco to compress the grid in three.js

Pit and solution process

The code written after many baidu searches

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;
});
Copy the code

Here I came across a big hole:

Uncaught SyntaxError: Unexpected token ‘<‘

Solution:

During the troubleshooting process, it was discovered that the network request requested model data

Subsequent discovery bolb: XXX request is not written by the application layer issued by reading dracoloader.js source code

The bolb: XXX request in the network request is created at line 250 url.createObjecturl and is required to create the request

  • draco_decoder.js
  • draco_wasm_wrapper.js
  • draco_decoder.wasm

And the requested path is set using the setDecoderPath method

Follow-up access to information

  • draco_decoder.js— Emscripten-compiled decoder, andCompatible with any modern browser.
  • draco_decoder.wasm– WebAssembly decoder, compatible with newer browsers and devices.
  • draco_wasm_wrapper.js— JavaScript wrapper for the WASM decoder.

The Draco path for obtaining the three version in the node_modules installation package is node_modules\three\examples\js\libs

Copies to change folder to public folder and DRACOLoader. SetDecoderPath when setting the corresponding path

The final solution is to wrap the code with itself

import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
/** ** path: store the parent path of the model * modelName: modelName * setCenter: center or not * scale: scale of the model * position: position of the model * rotation: local rotation of the model */
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/"); // Set the decoding path under public, note the/at the end
    dracoLoader.setDecoderConfig({ type: "js" }); // Use a compatible draco_decoder.js decoder
    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;
        });
    });
}
Copy the code

call

loadModuleByDRACOLoader('./moduler/'."grow4-processed.glb".false.1.0)
Copy the code

conclusion

Since I didn’t find a solution to this problem, I wrote this article as a record to avoid the same problem for other developers.

And 🎇🎇 🎇🎇