总结three.js加载gltf格式文件开发过程中遇到的坑
项目介绍
此项目主要是做一个三维运维机房,笔者刚接触three一个月,属于初学者。项目起始,加载模型用的FBX格式,直接引用的3D格式文件,后期发现在性能较差的笔记本上加载模型时,耗时太长(50M大小 3~5min),体验极差。后面通过查阅资料,发现three官方是推荐gltf/glb格式文件的,后面就开始研究如何载入gltf格式文件。开发过程中遇到很多问题,最后经过不懈努力终于得到解决。此次three开发经历值得记录一下。本文适合初学者阅读,对于你比较熟悉three的同学可做交流,欢迎提出宝贵意见。
下面对开发过程入的坑做一总结:
- 如何使用blender导出gltf格式文件;
- GLTFLoader如何载入gltf格式文件;
- gltf格式文件如何压缩;
如何使用blender导出gltf格式文件
如何使用blender导出GLTF—参考:https://blog.csdn.net/ithanmang/article/details/82147686
提示最新版blender(version2.9.0)已经内置gltf格式导出,无需手动下载安装插件包了。
VUE项目中 GLTFLoader如何载入gltf格式文件
import * as THREE from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
const loader = new GLTFLoader(), path = 'three/model/jifang.gltf' ;
loader.load(
path ,
( gltf ) => {
// called when the resource is loaded
scene.add( gltf.scene );
},
( xhr ) => {
// called while loading is progressing
console.log( `${( xhr.loaded / xhr.total * 100 )}% loaded` );
},
( error ) => {
// called when loading has errors
console.error( 'An error happened', error );
},
);
注意:gltf文件——必须、必须、必须放在根目录public文件夹下(vue-li2构建项目对应static静态资源文件夹下面),路径为: ‘public/three/model/jifang.gltf’。gltf文件放入其他目录下 比如‘src/assets’,会导致模型load失败,至于原因后面学到会及时更新。
gltf格式文件如何压缩
项目进行到上面阶段时,模型已经能够载进dom了。但是一般的三维模型文件体积较大,动辄几十上百M,模型载入时间过长(几十秒甚至几分钟),严重影响体验。这时候就需要压缩模型文件了,一般方法有两种:减少模型细节 物理压缩体积(减少了纹理细节 不推荐)、通过gltf-pipeline插件压缩gltf文件(推荐)。
如何gltf-pipeline压缩GLTF—参考:https://blog.csdn.net/rexfow/article/details/107378041
注意:需要先cmd控制台全局安装gltf-pipeline:npm install -g gltf-pipeline
,再cd进入gltf文件目录下执行:gltf-pipeline -i jifang.gltf -o jifangDraco.gltf -d
,指定导出名为 XXDraco.gltf的文件。指令结束后 就可以在‘public/three/model/’目录下(根据自己的项目路径)看到XXDraco.gltf文件了。
此刻,你以为XXDraco.gltf文件就可以直接通过GLTFLoader方法载入使用了?错!
的确,想当然的以为既然压缩后同样是gltf格式文件,直接GLTFLoader载入为啥还会报错呢。通过参考官方demo找到了答案。
学习官方demo_loader_gltf_extensions—参考:http://www.yanhuangxueyuan.com/threejs/examples/?q=loader#webgl_loader_gltf_extensions
import * as THREE from 'three'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader'
const loader = new GLTFLoader(), path = 'three/model/jifangDraco.gltf' ;
var dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath( 'three/js/libs/draco/gltf/' );
loader.setDRACOLoader( dracoLoader );
loader.load(
path ,
( gltf ) => {
// called when the resource is loaded
scene.add( gltf.scene );
},
( xhr ) => {
// called while loading is progressing
console.log( `${( xhr.loaded / xhr.total * 100 )}% loaded` );
},
( error ) => {
// called when loading has errors
console.error( 'An error happened', error );
},
);
执行代码会发下以下错误:DRACOLoader实例对象下setDecoderPath方法未定义。
此刻 是不是有点奇怪,明明和官方demo写法一致为什么会报错,查阅了很多文档终于在一篇文章中找到了答案(参考文章:https://blog.csdn.net/yue1241630499/article/details/105322176),代码做以下改动:
import * as THREE from 'three'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader'
const loader = new GLTFLoader(), path = 'three/model/jifangDraco.gltf' ;
DRACOLoader.setDecoderPath( 'three/js/libs/draco/gltf/' );//设置解压库文件路径
var dracoLoader = new DRACOLoader();
modelLoader.setDRACOLoader( dracoLoader );
loader.load(
path ,
( gltf ) => {
// called when the resource is loaded
scene.add( gltf.scene );
},
( xhr ) => {
// called while loading is progressing
console.log( `${( xhr.loaded / xhr.total * 100 )}% loaded` );
},
( error ) => {
// called when loading has errors
console.error( 'An error happened', error );
},
);
发现区别了嘛?太奇怪了,暂时还未发现这么写的原因,有知晓者欢迎评论区指点迷津。
对于DRACOLoader.setDecoderPath( 'three/js/libs/draco/gltf/' )
设置解压库文件路径的补充
是不是对这个方法的路径参数很懵?我也很懵。。。项目中没有这些文件怎么办。。。那就无奈引入吧,先实现效果再说。去官网工具资源下载官方Three.js-master包,里面有three.js所需各种插件,解压缩后将Three.js-master\R102版本\three.js-master\three.js-r102\examples\
路径下js文件夹存入public/three
路径下面即可。