three.js 轻量化glb模型 详细全过程

该方法不一定是最快捷方面的,但亲测可行,效果较好

之前采用unity3d三维引擎进行web项目的开发,但因为存在较长的前期加载黑屏加载时间,故采用新的三维技术方案进行项目开发:three.js+glb。因为甲方项目中的模型多数为工业模型,所以模型大,面数多,three.js场景本身的模型加载就有一定的上限,所以模型的轻量化是一个较为重要的问题。

DRACOLoader,three.js本身的glb格式模型轻量化加载工具便成为了第一个研究使用对象。

能从three.js找到的demo场景里对DRACOLoader使用的代码:

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

} );

就以现有的场景作为研究对象,发现DRACOLoader只是一个对进行压缩后的模型进行特殊加载的工具,本身并不能实现对glb模型的压缩功能。

实际用来做glb压缩的工具为gltf-pipeline,故先进行gltf-pipeline的安装操作。GitHub地址https://github.com/CesiumGS/gltf-pipeline。

先安装nodejs,地址下载 | Node.js。Nodejs安装好后,打开Developer PowerShell for VS 2019,输入npm install -g gltf-pipeline安装gltf-pipeline。

安装vscode,在桌面创建一个glb文件夹,然后使用vscode打开glb文件夹,创建文件draco.js作为压缩代码脚本文件,打开终端,新建终端,输入npm install gltf-pipeline,当安装成功后左边窗口会出现node_modules文件夹,以及两个json文件。将需要压缩的glb模型(model.glb)放到刚才创建在桌面的glb文件夹中。

先将glb转成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);

});

再压缩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);

});

再将压缩过后的gltf转换成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);

});

然而采取以上代码压缩会发现,实际压缩效果并没有太好,不存在10倍压缩的情况,将gltf纹理单独保存出来就会发现,纹理贴图是没有做过压缩处理的,只是将本身的gltf做了压缩,本身gltf确实存在10倍压缩,所以如果你的模型贴图占了该模型大小较重的比例,这个压缩实际效果很差。

所以就需要对gltf的贴图进行压缩。

先将gltf做纹理的单独保存:

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有个jimp模块可以对图片进行处理,在glb工程中打开终端,输入npm install jimp,安装jimp工具。

图片压缩代码:

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

});

然后把单独保存出来并处理过的图片和gltf,重新再合成glb。

使用CMD命令行进行gltf以及纹理贴图的打包,生产glb:

[pgltf-pipeline -i ‘gltf模型文件地址’ -o ‘glb模型文件保存地址’],保证纹理和gltf模型文件在一个文件夹下,如此便成功将glb进行网格和纹理的压缩。

最后代码总结:

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

最后4158KB的glb压缩到138KB,并且正常加载使用

你可能感兴趣的:(Three.js,npm,js)