Three js DRACOLoader

preface

Use front-end three In the process of loading 3d models with JS, the model size is often too large, resulting in too long loading time at the front end and reducing the user experience.
What is recorded in this paper is a process of stepping on the DRACOLoader and solving the problem in using gltf pipeline to compress 3d model.

The three library version used is ^ 0.138.2

Solution and introduction

adopt gltf-pipeline The gltf/glb model file can be greatly compressed.

And has the following functions

  • Convert glTF to glb (and reverse)
  • Save the buffer / texture as an embedded or separate file
  • Convert glTF 1.0 model to glTF 2.0 (using KHR_techniques_webgl and KHR_blend (Extended)
  • application Draco Mesh compression

install

npm install -g gltf-pipeline

perhaps

yarn global add gltf-pipeline

Common compression commands

gltf-pipeline -i model.glb -o modelDraco.glb -d

use Draco Compress mesh model GLB file, modeldraco GLB is the compressed output file name

gltf-pipeline -i model.glb -o modelDraco.glb -d -s

Compress and write separate buffers, shaders, and textures.

In three JS file after using Draco to compress the grid

Pit and solution process

Code written after Baidu many times

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;
});

Here I came across a big pit:

Uncaught SyntaxError: Unexpected token '<'

solve:

In the troubleshooting process, it is found that the network request requests the model data

Later, it was found that the request of bolb:xxx was not sent by the application layer of writing
Then read dracoloader JS source code


In the network request, the bolb:xxx request is made by line 250 URL.createObjectURL Created, the request needs to be created

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

And the requested path is set using the setDecoderPath method

Follow up information obtained

  • draco_decoder.js - Emscripten compiled decoder, compatible with any modern browser.
  • draco_decoder.wasm - web assembly decoder, compatible with newer browsers and devices.
  • draco_wasm_wrapper.js - JavaScript wrapper for WASM decoder.

On node_ The draco path corresponding to the three version obtained from the package installed by modules is
node_modules\three\examples\js\libs

Copy the modified folder to the public folder and put it in dracoloader Set the corresponding path when setdecoderpath

The final solution code and its own encapsulation

import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
/**
 * 
 *  path:Store model parent path
 *  modelName:Model name
 *  setCenter:Centered
 *  scale:Zoom ratio setting of the model
 *  position:Location of the model
 *  rotation:Local rotation of 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 and pay attention to the last one/
    dracoLoader.setDecoderConfig({ type: "js" }); //Use Draco with strong compatibility_ 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;
        });
    });
}

call

loadModuleByDRACOLoader('./moduler/', "grow4-processed.glb", false, 1, 0)

epilogue

Because no corresponding solution was found after encountering this pit, this article was written as a record, and it was also used to avoid the pit for developers encountering the same problem.

also 🎇🎇 Big three seeking inner push 🎇🎇

Keywords: Javascript Front-end Three.js

Added by Mactek on Wed, 09 Mar 2022 04:35:47 +0200