侧边栏壁纸
博主头像
红颜青妙博主等级

好好学习,天天向上

  • 累计撰写 6 篇文章
  • 累计创建 4 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

linux环境下fbx、stp、glb、ifc转obj

红颜青妙
2024-06-26 / 0 评论 / 0 点赞 / 121 阅读 / 10556 字

导读

以下仅为个人总结,不喜轻喷~~

说明:

通过java程序在linux环境中将fbx、glb、stp、ifc等文件。转换为obj文件或其他文件的转换,思路都一样。

思路:

处理这类文件的框架大多都提供了python的操作方式,然后通过python脚本进行转换。或者像ifc转其他类型文件就可以用IfcConvert的命令去操作。都是通过linux命令行的方式操作。那么我们只需要在java中执行对应的linux命令就行了。

可以先在linux环境中进行转换,脚本或环境没问题之后再通过java执行命令,接着处理对应的业务。

流程:

  1. java接口需要接收要被转换的文件,拿到文件后将文件上传到服务器,用于转换时在服务器中将该文件作为输入文件,也就是在执行linux命令或者python脚本的时候,脚本可以拿到文件

  2. 将要执行的python脚本上传到服务器,给执行的命令作为支撑

  3. 在java中拼接好需要执行的命令,不同类型的转换所需的命令不同,也就是执行的脚本会有差异;所以针对每种转换都有各自的执行命令

  4. 开始执行命令(转换的过程根据个人需求决定是否异步,大文件转换会等待很久)

  5. 转换成功以后通过io流读取该文件,然后上传到各自的文件服务器中即可。

注意:

  1. 以下转换方式在linux中都可以单独执行操作,可先在linux中通过该脚本进行验证,例如执行python的命令:blender -b -P /path/fbx2obj.py /path/被转换文件.fbx /path/转换后的文件.obj 0.1

  2. 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

0

评论区