客户发来了一个400M的3d模型文件,obj+mtl+png格式的,如下图:
要求用h5展示出来,效果类似于博物馆文物的3D展示。
据我有限的所知,目前的3d js库有Three.js 和 Babylon.js。之前听说过Three.js,就打算用它实现,但看文档一下就懵了。因为我用的是vue开发,偶然搜到vue-3d-model这个组件,几行代码就能实现3d展示,核心代码如下:
-
- :backgroundAlpha="0"
- @on-load="onLoad"
- src="static/models/obj/male02/male02.obj"
- mtl="static/models/obj/male02/male02.mtl"
- >
在本地这个项目跑起来已经比较慢,因为要加载400M文件,慢很正常。于是开始想办法优化。试了用Blender、Polygon Cruncher做减面,效果不理想。期间走了很多弯路,装了很多软件不再赘述。下面直接给出优化步骤。
三、优化步骤
1.压缩PNG
这一步非常关键,且容易忽略,但这一步压缩比例最高:原图是8192*8192的60M大的PNG,先把分辨率降为400*400,再用tinypng网站或软件降低质量进一步压缩。图片锐减为100KB。
注意:这一步要多看效果(可使用win10自带的3D查看器),在清晰度和文件大小间反复衡量、取舍。尤其注意带文字的部分是否能看清。
2.合并为gltf
使用obj2gltf.js 将obj\mtl+png 合并为gltf。obj2gltf.js的安装比较繁琐,且中间要解决几个错误(主要是缺少fs-* 等js库),网上有教程,自行百度。转换命令如下:
node bin\obj2gltf.js -i TM00001.obj -o tm.gltf
推荐使用Blender软件,转换比较方便:导入obj,然后导出gltf嵌入式即可。这时候tm.gltf文件有14M大小,打开会看到内容是json格式,内嵌了base64格式的图片。
另外:Blender也可以导出分离的gltf。这是分成gltf文件、bin文件、若干贴图。
3.转换glb
gltf在用于3d展示时,图片部分要做base64解码,也需要消耗资源。因此可以使用glb格式,这种格式用二进制形式存储json和图像,进一步压缩文件大小,且在展示时能省略图像的base64解码 。
可以使用gltf-pipeline转换:
gltf-pipeline -i tm.gltf -o tm.glb
如果没有gltf-pipeline ,需要事先安装:
npm install -g gltf-pipeline --registry=https://registry.npmmirror.com
也可以用Blender软件转换,且可以直接从obj转换为glb:导入obj,导出glTF二进制(.glb)即可。但是切记不要选择压缩。
转换为glb后大小为10M,大小变化不大。
4.Draco压缩glb
10M大小的文件,加载时间也很长。 有没有进一步压缩的空间?有,使用压缩算法。Blender软件在导出glb文件时,可以选择压缩(红色箭头),如下图:
此时采用的Draco算法进行压缩。压缩后文件可以降为2M,但这时vue-3d-model已不支持,需要修改一下组件,加入Draco的支持。但最终效果并不理想,10s左右才能加载完,比未压缩的glb文件性能相当,原因是Draco算法解码存在瓶颈。且有明显的失真,能看到模型出现了空白的缝隙。
5.EXT_meshopt_compression压缩glb
使用EXT_meshopt_compression算法也可以压缩glb,需要事先安装gltfpack
npm install -g gltfpack --registry=https://registry.npmmirror.com
压缩命令:
gltfpack -i tm.glb -o tm-me.glb -cc
此时文件缩小为不足3M,虽然比Draco算法压缩后的文件略大,但是由于解码快,2s内就能加载完。这时vue-3d-model也不支持,需要简单改造,示意代码如下:
- import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
- import { MeshoptDecoder } from 'three/examples/jsm/libs/meshopt_decoder.module.js'
-
- const loader = new GLTFLoader();
- loader.setMeshoptDecoder(MeshoptDecoder);
需要注意的是:three.js版本要升级,大于r122(0.122?我用的是0.143.0)。
四、总结
我对obj+mtl+png格式的3d模型文件压缩步骤如下:
1.压缩png:降低分辨率;再使用tinypng降低质量。
2.使用Blender软件转换glb文件。(不要压缩)
3.使用gltfpack采用-cc选项压缩
五、改进思路
1.使用Blender修改器--精简,去减面。注意:会失真。
2.使用oss+cdn存储glb文件。这是很有必要的,因为模型文件相对于js、css很大,不存在oss上,应用服务器带宽很容易被打爆。
3.感觉分离的gltf文件,也有优势,因为可以多个文件同时加载。但不确定能否压缩。没有尝试。
4.因为gltf文件中最大的部分还是图片,看到有的实现:将图片分为缩略的小图和高清大图,默认加载缩略图,减少用户等待时间。待大图加载完毕后,再替换成大图。这种应该可以通过简单修改GLTFLoader就可以实现。
5.使用OSGB格式:猜测类似于地图瓦片,逐级加载。初始时只需要加载小图,放大后可以加载大图(也是一部分)。这种方式对要求精细细节的人员比较友好,且能解决一次性加载所有资源的性能瓶颈。