项目上需要展示3D矿图效果,当时前端框架选用了three.js进行渲染引擎,成功的满足了需求进行效果展示,但在后期一直有性能问题的困扰,前端同学做了一些优化,包括分布加载、采用nginx请求头缓存配置、浏览器缓存等机制。 在实践中,我们发现glb格式要比obj格式的文件小一些,此外,obj在加载的过程也容易丢失样式、纹理等文件,由于obj模型文件通常为一组格式mlt(纹理、样式)、png(贴图),因此在做前端浏览器缓存时,也存在问题,后来和前端同学商量后,我们决定将obj转成glb进行尝试。
obj文件专注于存储3D模型的几何数据(顶点、纹理坐标、法线等),通过纯文本描述模型结构,是一组可读的文本语句,eg:v表示顶点定义模型;ojb会依赖外部文件,材质信息需客外MTL文件存储,不支持动画功能,支持贴图文件,png/jpeg
GLB 是GLTF标准的二进制版本,全称为“GL传输格式二进制文件”,将3D模型、纹理、材质、动画甚至场景光源打包为单一二进制文件。是一体化封装文件,所有资源饭知JSON元数据、纹理等都可以整合一体,其设计目标就是快速加载与高效解析,适配WEB和移动端
对比维度 | OBJ | GLB |
|---|---|---|
文件大小 | 文本格式冗余,所以文件相对大 | 二进制压缩,相对小 |
功能支持 | 无动画/场景支持 | 支持动画、光照、相机视角 |
文件可读性 | 文本格式易上手 | 二进制文件难理解难编辑 |
兼容性 | 广泛支持(3D打印/建模软件) | 主流引擎/WebGL原生支持 |
材质管理 | 需额外的MLT、PNG | 内嵌纹理与材制裁 |
经上对比,综述,GLB支持WEB集成,体积更小,减少带宽消耗,如果追求轻量、动画支持可首选GLB格式
选用Node插件进行转换,首先可以用npm install obj2gltf安装插件,然后通过命令进行转换
# 安装node插件
npm install obj2gltf# 格式转换命令
obj2gltf -i 源文件.obj -o 目标文件.glb示例如下所示:
# 示例如下
obj2gltf -i D:\data\mainMap\主要系统巷道\主要大巷.3dmobj\主要大巷_offset.obj -o D:\data\mainMap\主要系统巷道\主要大巷.3dmobj\主要大巷.glb 这个搞定了,剩的工作就简单了,如何动达转换呢,我们可以通过Java程序监听指定目录的新增、修改操作,然后对其变化的文件执行脚本调用,进行转换,思路有了,来码代码,先容我再啰嗦两句,把步骤描述如下所示:
1 、obj2gltf是通过npm install obj2gltf安装的插件,用于模型格式转换操作 2、包下的node_module是将npm install 时产生的所有npm依赖都copy进去了。否则缺少依赖; 3、application.yml 中需要配置脚本文件的绝对路径,需引用obj2gltf下的bin下的obj2gltf.js 4、java 引入Pom依赖 5、JAVA调用IO包中的Process类执行命令脚本
代码结果如下所示:

obj2gltf -i D:\data\mainMap\主要系统巷道\主要大巷.3dmobj\主要大巷_offset.obj -o D:\data\mainMap\主要系统巷道\主要大巷.3dmobj\主要大巷.glb
写了一个转换工具类,参数如下所示:
<dependency>
<groupId>de.javagl</groupId>
<artifactId>jgltf-model</artifactId>
<version>2.0.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/de.javagl/obj -->
<dependency>
<groupId>de.javagl</groupId>
<artifactId>obj</artifactId>
<version>0.3.0</version>
</dependency>package com.zhanglu.test.handle.util;
import com.zhanglu.test..handle.obj2gltf.ConvertObjToGltf;
import com.zhanglu.test..handle.obj2gltf.obj.BufferStrategy;
import com.zhanglu.test..handle.obj2gltf.obj.GltfWriteType;
import com.zhanglu.test..handle.obj2gltf.obj.IndicesComponentType;
import lombok.extern.slf4j.Slf4j;
import java.io.BufferedReader;
import java.io.InputStreamReader;
@Slf4j
@SuppressWarnings("all")
public class NodeJsExcutorUtil {
public static void convertObjToGlb(String objPath,String glbPath,String scriptPath) {
BufferedReader reader = null;
try {
// 构建命令(根据安装方式调整)
String[] command = {
"node", //本地windows启动不加这个命令,不然会报错
scriptPath, // 局部安装使用 npx
"-i", objPath.trim(),
"-o", glbPath.trim()
};
ProcessBuilder builder = new ProcessBuilder(command);
System.out.println(builder.command());
builder.redirectErrorStream(true); // 将错误输出和标准输出合并,便于读取
Process process = builder.start();
reader = new BufferedReader(new InputStreamReader(process.getInputStream(),"utf-8"));
String line;
while ((line = reader.readLine()) != null) {
log.info(line);
}
process.waitFor(); // 等待进程结束
log.info("【glb文件】转换成功");
} catch (Exception err) {
err.printStackTrace();
log.error("【glb文件】转换失败:{}",err.getMessage());
}finally {
try {
if (reader != null) {
reader.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
//本地如果是windows环境用以下脚本
String scriptPath = "D:\\web\\node_modules\\.bin\\obj2gltf.cmd";
//如果是Linux脚本用以下脚本
// String scriptPath = "scriptPath: /data/webapp/calamity/handle/obj2gltf/bin/obj2gltf.js";
String objPath="D:\\data\\mainMap\\主要系统巷道\\主要大巷.3dmobj\\主要大巷.obj";
String glbPath="D:\\data\\mainMap\\主要系统巷道\\主要大巷.3dmobj";
String glbFilePath="D:\\data\\mainMap\\主要系统巷道\\主要大巷.3dmobj\\主要大巷_1.glb";
NodeJsExcutorUtil.convertObjToGlb(objPath,glbFilePath,scriptPath);
}
}Linux环境脚本路径node安装obj2gltf包下的:obj2gltf/bin/obj2gltf.js;
命令:node /脚本实际路径/obj2gltf.js -i objFile.obj -o glbFile.glb
Windows 环境脚本路径node安装obj3gltf包下:node_modules\\.bin\\obj2gltf.cmd
命令: /脚本实际路径/obj2gltf.cmd -i objFile.obj -o glbFile.glb