Three.js lightweight glb model detailed whole process

This method is not necessarily the fastest, but the personal test is feasible and the effect is better

The unity3d three-dimensional engine was used to develop web projects before, but because of the long loading time of the black screen in the early stage, a new three-dimensional technical solution was used for project development: three.js+glb. Because most of the models in the project of Party A are industrial models, the models are large and the number of faces is large, and the model loading of the three.js scene itself has a certain upper limit, so the lightweight of the model is a relatively important issue.

DRACOLoader, the lightweight loading tool for three.js's own glb format model, became the first object of research.

The code that can be used for DRACOLoader in the demo scene found in three.js:

new GLTFLoader()

.setPath( 'models/gltf/' )

.setDRACOLoader( new DRACOLoader().setDecoderPath( 'js/libs/draco/gltf/' ) )

.load( 'model-separate.glb', function ( gltf ) {

console.log(gltf.scene);

scene.add( gltf.scene );

} );

Taking the existing scene as the research object, it is found that DRACOLoader is only a tool for special loading of the compressed model, and it cannot realize the compression function of the glb model by itself.

The tool actually used for glb compression is gltf-pipeline, so install gltf-pipeline first. GitHub address https://github.com/CesiumGS/gltf-pipeline .

First install nodejs, address download | Node.js. After Nodejs is installed, open Developer PowerShell for VS 2019, and enter npm install -g gltf-pipeline to install gltf-pipeline.

Install vscode, create a glb folder on the desktop, then use vscode to open the glb folder, create a file draco.js as a compressed code script file, open a terminal, create a new terminal, enter npm install gltf-pipeline, and when the installation is successful, the left window will be The node_modules folder appears, as well as two json files. Put the glb model (model.glb) that needs to be compressed into the glb folder just created on the desktop.

First convert glb to gltf:

const gltfPipeline = require("gltf-pipeline");

const fsExtra = require("fs-extra");

const glbToGltf = gltfPipeline.glbToGltf;

const glb = fsExtra.readFileSync("model.glb");

glbToGltf(glb).then(function (results) {

  fsExtra.writeJsonSync("model.gltf", results.gltf);

});

Recompress gltf:

const gltfPipeline = require("gltf-pipeline");

const fsExtra = require("fs-extra");

const processGltf = gltfPipeline.processGltf;

const gltf = fsExtra.readJsonSync("model.gltf");

const options = {

  dracoOptions: {

    compressionLevel: 10,

  },

};

processGltf(gltf, options).then(function (results) {

  fsExtra.writeJsonSync("model-draco.gltf", results.gltf);

});

Then convert the compressed gltf to glb:

const gltfPipeline = require("gltf-pipeline");

const fsExtra = require("fs-extra");

const gltfToGlb = gltfPipeline.gltfToGlb;

const gltf = fsExtra.readJsonSync("model-draco.gltf");

gltfToGlb(gltf).then(function (results) {

  fsExtra.writeFileSync("model-draco.glb", results.glb);

});

However, if you take the above code compression, you will find that the actual compression effect is not very good, and there is no 10 times compression. If you save the gltf texture separately, you will find that the texture map has not been compressed, but the gltf itself. In addition to compression, gltf itself does have 10 times compression, so if your model texture accounts for a heavy proportion of the model size, this compression will actually be very poor.

So it is necessary to compress the gltf texture.

First save gltf as a separate texture:

const gltfPipeline = require("gltf-pipeline");

const fsExtra = require("fs-extra");

const processGltf = gltfPipeline.processGltf;

const gltf = fsExtra.readJsonSync("model.gltf");

const options = {

  separateTextures: true,

};

processGltf(gltf, options).then(function (results) {

  fsExtra.writeJsonSync("model-separate.gltf", results.gltf);

  // Save separate resources

  const separateResources = results.separateResources;

  for (const relativePath in separateResources) {

    if (separateResources.hasOwnProperty(relativePath)) {

      const resource = separateResources[relativePath];

      fsExtra.writeFileSync(relativePath, resource);

    }

  }

});

Nodejs has a jimp module that can process images, open the terminal in the glb project, enter npm install jimp, and install the jimp tool.

Image compression code:

var Jimp = require('jimp');

Jimp.read('image0.png').then(img => {

  const imgWidth = img.bitmap.width;

  const imgHeight = img.bitmap.height;

  const length = 400;

  const isWidthLonger = imgWidth > imgHeight ? true : false;

  const time = (isWidthLonger ? imgWidth : imgHeight) / length;

  const rWidth = imgWidth / time;

  const rHeight = imgHeight / time;

  return img.resize(rWidth, rHeight ).write(`image0.png`);

});

Then the separately saved and processed pictures and gltf are recombined into glb.

Use the CMD command line to package gltf and texture maps to produce glb:

[pgltf-pipeline -i 'gltf model file address' -o 'glb model file save address'], ensure that the texture and gltf model files are in one folder, so that the glb is successfully compressed for the grid and texture.

Final code summary:

const gltfPipeline = require("gltf-pipeline");

const fsExtra = require("fs-extra");

const glbToGltf = gltfPipeline.glbToGltf;

const glb = fsExtra.readFileSync("model.glb");

const processGltf = gltfPipeline.processGltf;

var Jimp = require('jimp');

const options = {

  dracoOptions: {

    compressionLevel: 10,

  },

};

const options1 = {

  separateTextures: true,

};

glbToGltf(glb).then(function (results) {

  processGltf(results.gltf, options).then(function (results) {

    processGltf(results.gltf, options1).then(function (results) {

      fsExtra.writeJsonSync("model-separate.gltf", results.gltf);

      // Save separate resources

      const separateResources = results.separateResources;

      for (const relativePath in separateResources) {

        if (separateResources.hasOwnProperty(relativePath)) {

          const resource = separateResources[relativePath];

          fsExtra.writeFileSync(relativePath, resource);

          Jimp.read(relativePath).then(img => {

            const imgWidth = img.bitmap.width;

            const imgHeight = img.bitmap.height;

            const length = 10;

            const rWidth = imgWidth / length;

            const rHeight = imgHeight / length;

            return img.resize(rWidth, rHeight ).write(relativePath);

          });

        }

      }

    });

  });

});

CMD:gltf-pipeline -i C:\xx\xx\xx\glb\model-separate.gltf -o C:\xx\xx\xx\glb\model-separate.glb

The last 4158KB of glb is compressed to 138KB, and it is loaded and used normally

Guess you like

Origin blog.csdn.net/Bug1997/article/details/126768305