导读
以下仅为个人总结,不喜轻喷~~
说明:
通过java程序在linux环境中将fbx、glb、stp、ifc等文件。转换为obj文件或其他文件的转换,思路都一样。
思路:
处理这类文件的框架大多都提供了python的操作方式,然后通过python脚本进行转换。或者像ifc转其他类型文件就可以用IfcConvert的命令去操作。都是通过linux命令行的方式操作。那么我们只需要在java中执行对应的linux命令就行了。
可以先在linux环境中进行转换,脚本或环境没问题之后再通过java执行命令,接着处理对应的业务。
流程:
java接口需要接收要被转换的文件,拿到文件后将文件上传到服务器,用于转换时在服务器中将该文件作为输入文件,也就是在执行linux命令或者python脚本的时候,脚本可以拿到文件
将要执行的python脚本上传到服务器,给执行的命令作为支撑
在java中拼接好需要执行的命令,不同类型的转换所需的命令不同,也就是执行的脚本会有差异;所以针对每种转换都有各自的执行命令
开始执行命令(转换的过程根据个人需求决定是否异步,大文件转换会等待很久)
转换成功以后通过io流读取该文件,然后上传到各自的文件服务器中即可。
注意:
以下转换方式在linux中都可以单独执行操作,可先在linux中通过该脚本进行验证,例如执行python的命令:
blender -b -P /path/fbx2obj.py /path/被转换文件.fbx /path/转换后的文件.obj 0.1
linux环境下的命令请按照自己的环境进行配置
不同类型转换涉及到的开源技术:blender、freecad、ifcopenshell
使用blender
python文档:https://docs.blender.org/api/master/bpy.ops.html
以下是支持导出的函数,具体导出类型可自行查看
前提:
需要安装blender
安装:https://www.blender.org/download/ 下载linux版本即可,这是编译好的,可以直接使用
以下使用的时候我先采用全路径,减少安装所产生的问题:例如下载的blender解压后的文件为 /root/data/blender-3.6.1
使用:
以下的python脚本如何使用呢?
linux中命令行执行:
/root/data/blender-3.6.1/blender -b -P /root/blender-py/fbx2obj.py fbx.fbx fbx2obj.obj 0.1
参数1:/root/data/blender-3.6.1/blender 使用blender
参数2:-b 后台运行
参数3:-P 执行python脚本
参数4:/root/blender-py/fbx2obj.py 执行的python脚本
参数5:fbx.fbx 输入的fbx文件
参数6:fbx2.obj 输出的obj文件,名称及路径可以自定义,会自动生成
参数7:0.1 转换精度0.1即可
docker镜像可以去dockerhub上自行下载
fbx转obj
import bpy
import sys
input_fbx_path = sys.argv[-3]
output_obj_path = sys.argv[-2]
rate = float(sys.argv[-1])
bpy.ops.import_scene.fbx(filepath=input_fbx_path)#导入fbx文件
mesh = bpy.data.meshes["Cube"]
bpy.data.meshes.remove(mesh)
for i in bpy.context.visible_objects:
if i.type == "MESH":
bpy.context.view_layer.objects.active = i
bpy.ops.object.modifier_add(type='DECIMATE')
bpy.context.object.modifiers["Decimate"].ratio = rate
bpy.ops.export_scene.obj(filepath=output_obj_path)
glb转obj或者gltf转obj
import bpy
import sys
input_fbx_path = sys.argv[-3]
output_obj_path = sys.argv[-2]
rate = float(sys.argv[-1])
bpy.ops.import_scene.gltf(filepath=input_fbx_path)#导入glb或gltf文件
mesh = bpy.data.meshes["Cube"]
bpy.data.meshes.remove(mesh)
for i in bpy.context.visible_objects:
if i.type == "MESH":
bpy.context.view_layer.objects.active = i
bpy.ops.object.modifier_add(type='DECIMATE')
bpy.context.object.modifiers["Decimate"].ratio = rate
bpy.ops.export_scene.obj(filepath=output_obj_path)
使用FreeCAD
python文档:https://wiki.freecad.org/Category:Poweruser_Documentation
安装:
推荐使用docker安装
命令:python /root/blender-py/stp2obj.py stp.fbx stp2obj.obj
stp转obj
import sys
sys.path.append("/usr/lib64/freecad")# 此处根据自己实际路径引入
sys.path.append("/usr/lib64/freecad")
import FreeCAD
import Part
import Mesh
input_stp_path = sys.argv[1]
output_obj_path = sys.argv[2]
doc = FreeCAD.newDocument()
shape = Part.read(input_fbx_path)
obj = doc.addObject("Part::Feature", "MyShape")
obj.Shape = shape
# 2.9仅为个人测试时觉得合适的参数。该参数会影响输出的文件大小
triangles = shape.tessellate(2.9)
mesh = Mesh.Mesh(triangles)
mesh.write(output_obj_path)
FreeCAD.closeDocument(doc.Name)
使用IfcOpenShell
IfcConvert模块相关文档:https://blenderbim.org/docs-python/ifcconvert/usage.html
安装:
手动下载linux版本的:
https://blenderbim.org/docs-python/ifcconvert/installation.html
解压后会获得
IfcConvert
文件docker安装:
docker pull aecgeeks/ifcopenshell docker run -it -d --name ifcopenshell -v /data/blender:/data/blender aecgeeks/ifcopenshell
ifc转obj
使用IfcConvert的命令转换:IfcConvert /data/blender/ifc.ifc /data/blender/ifc2obj.obj
java部分代码
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.function.Consumer;
// 传入命令即可
// 执行脚本 这里的返回值只是为了存储执行过程中的命令。代码可根据自己需求修改
public String runScript(String cmd) {
try {
log.info("执行命令开始,cmd:{}", cmd);
Runtime rt = Runtime.getRuntime();
// 执行命令
Process p = rt.exec(cmd, null, null);
// ----------------以下为执行命令后的打印输出信息的处理-------------------
// 获取进程的标准输入流
final InputStream is1 = p.getInputStream();
// 获取进城的错误流
final InputStream is2 = p.getErrorStream();
// 启动两个线程,一个线程负责读标准输出流,另一个负责读标准错误流
ExecutorService executorService = ExecutorBuilder.create().setCorePoolSize(2).setMaxPoolSize(2).build();
Future<StringBuilder> inFuture = executorService.submit(() -> {
StringBuilder sb = new StringBuilder();
BufferedReader br1 = new BufferedReader(new InputStreamReader(is1, Charset.forName("UTF8"))); // 这里要注意shell返回的类型,windows和linux可能不同
try {
String line1 = null;
while ((line1 = br1.readLine()) != null) {
if (line1 != null) {
System.out.println(String.format("标准输出流 -> %s", line1));
sb.append(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))).append("--> INFO -->").append(line1.trim()).append("\n");
}
}
} catch (IOException e) {
sb.append("异常错误:").append(e.getMessage()).append("\n");
} finally {
try {
is1.close();
System.out.println("标准输出流线程关闭");
} catch (IOException e) {
sb.append("异常错误:").append(e.getMessage()).append("\n");
}
}
return sb;
});
Future<StringBuilder> errFuture = executorService.submit(() -> {
StringBuilder sb = new StringBuilder();
BufferedReader br2 = new BufferedReader(new InputStreamReader(is2, Charset.forName("UTF8")));
try {
String line2 = null;
while ((line2 = br2.readLine()) != null) {
if (line2 != null) {
System.out.println(String.format("标准错误流 -> %s", line2));
sb.append(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))).append("--> INFO -->").append(line2.trim()).append("\n");
}
}
} catch (IOException e) {
sb.append(e.getMessage()).append("\n");
} finally {
try {
is2.close();
System.out.println("标准错误流线程关闭");
sb.append("标准错误流线程关闭").append("\n");
} catch (IOException e) {
sb.append(e.getMessage()).append("\n");
}
}
return sb;
});
StringBuilder errStrBuilder = errFuture.get();
StringBuilder sucStrBuilder = inFuture.get();
sucStrBuilder.append("\n").append(errStrBuilder);
// 0 表示线程正常终止
if (p.waitFor() == 0) {
log.info("-----------thread proper termination------------");
log.info("------------运行命令结束!!!!!------------");
} else {
log.info("运行命令异常!!!!!");
}
return sucStrBuilder.toString();
} catch (Exception e) {
convertLog.append(e.getMessage()).append("\n");
e.printStackTrace();
}
return null;
}
end
评论区