stl转glb glb缩放

目录

glb缩放

trimesh转换


glb缩放

缩放并把中心点移动到原点

python 复制代码
import os

import trimesh

import glob


def move_to_zero(mesh):

    mesh.apply_translation(-mesh.centroid)
    print(f"模型中心点: {mesh.centroid}")

def scale_to_target_mm(input_path, output_path, target_mm):
    mesh = trimesh.load(input_path)

    # 获取当前最大边长(米)
    bounds = mesh.bounds
    current_size = bounds[1] - bounds[0]
    current_max_m = max(current_size)

    # 目标尺寸(米)
    target_m = target_mm #/ 1000

    # 计算缩放因子
    scale_factor = target_m / current_max_m

    print(f"当前最大边长: {current_max_m:.3f} 米 ({current_max_m:.1f} mm)")
    print(f"目标边长: {target_mm} mm")
    print(f"缩放因子: {scale_factor}")

    # 应用缩放
    mesh.apply_scale(scale_factor)

    move_to_zero(mesh)
    
    mesh.export(output_path, file_type='glb')

    # 验证
    new_bounds = mesh.bounds
    new_size = new_bounds[1] - new_bounds[0]
    print(f"缩放后最大边长: {max(new_size) :.1f} mm")

    return scale_factor

if __name__ == "__main__":

    input_dir=r'E:\project\3d_label\three-bvh-csg-main\examples\kakou_m'
    output_dir=r'E:\project\3d_label\three-bvh-csg-main\examples\kakou_s'
    os.makedirs(output_dir, exist_ok=True)
    glb_files = glob.glob(os.path.join(input_dir, "*.glb"))
    glb_files.extend(glob.glob(os.path.join(input_dir, "*.GLB")))

    print(f"找到 {len(glb_files)} 个 GLB 文件")

    for i, input_path in enumerate(glb_files, 1):
        filename = os.path.basename(input_path)
        output_path = os.path.join(output_dir, filename)

        scale_to_target_mm(input_path=input_path, output_path=output_path, target_mm=8)

trimesh转换

python 复制代码
import trimesh
import numpy as np
import os


def analyze_and_convert_stl_to_glb(input_path, output_path=None, scale_factor=1.0, apply_scale=True):
    if not os.path.exists(input_path):
        print(f"错误:文件不存在 - {input_path}")
        return None

    print(f"读取 STL 文件: {os.path.basename(input_path)}")
    print("=" * 60)

    try:
        mesh = trimesh.load_mesh(input_path, process=False)  # process=False 保留原始数据
        print("✓ 文件加载成功")
    except Exception as e:
        print(f"✗ 加载失败: {e}")
        return None

    # ========== 打印模型参数 ==========
    print("\n【模型基本参数】")
    print("-" * 40)

    # 顶点和面信息
    vertices_count = len(mesh.vertices)
    faces_count = len(mesh.faces)
    print(f"顶点数: {vertices_count:,}")
    print(f"三角形面数: {faces_count:,}")

    # 包围盒尺寸
    bounds = mesh.bounds
    min_bound = bounds[0]
    max_bound = bounds[1]
    size = max_bound - min_bound

    print(f"\n【包围盒尺寸】")
    print(f"  宽度 (X轴): {size[0]:.4f} 米  ({size[0] * 1000:.2f} mm)")
    print(f"  高度 (Y轴): {size[1]:.4f} 米  ({size[1] * 1000:.2f} mm)")
    print(f"  深度 (Z轴): {size[2]:.4f} 米  ({size[2] * 1000:.2f} mm)")
    print(f"  最长边: {max(size):.4f} 米  ({max(size) * 1000:.2f} mm)")

    # 包围盒范围
    print(f"\n【包围盒范围】")
    print(f"  X: [{min_bound[0]:.4f}, {max_bound[0]:.4f}] 米")
    print(f"  Y: [{min_bound[1]:.4f}, {max_bound[1]:.4f}] 米")
    print(f"  Z: [{min_bound[2]:.4f}, {max_bound[2]:.4f}] 米")

    # 中心点
    center = mesh.centroid
    print(f"\n【质心/中心点】")
    print(f"  ({center[0]:.4f}, {center[1]:.4f}, {center[2]:.4f}) 米")

    # 体积和表面积
    try:
        volume = mesh.volume
        area = mesh.area
        print(f"\n【几何属性】")
        print(f"  体积: {volume:.6f} 立方米  ({volume * 1e6:.2f} 立方厘米)")
        print(f"  表面积: {area:.6f} 平方米  ({area * 1e4:.2f} 平方厘米)")
    except:
        print(f"\n【几何属性】")
        print(f"  体积: 无法计算(网格可能不封闭)")
        print(f"  表面积: 无法计算")

    # 判断是否为流形
    is_watertight = mesh.is_watertight
    print(f"\n【网格质量】")
    print(f"  是否为水密/流形: {'是 ✓' if is_watertight else '否 ✗'}")

    if not is_watertight:
        # 检查边界边数
        try:
            edges = mesh.edges_unique
            boundary_edges = sum(1 for e in edges if len(mesh.edge_adjacencies[e[0], e[1]] if hasattr(mesh, 'edge_adjacencies') else 0) < 2)
            print(f"  边界边数: {boundary_edges}")
        except:
            pass

    # ========== 缩放处理 ==========
    if apply_scale and scale_factor != 1.0:
        print(f"\n【缩放处理】")
        print(f"  缩放因子: {scale_factor}")
        mesh.apply_scale(scale_factor)

        # 打印缩放后的尺寸
        new_bounds = mesh.bounds
        new_size = new_bounds[1] - new_bounds[0]
        print(f"  缩放后尺寸: {new_size[0]:.4f} × {new_size[1]:.4f} × {new_size[2]:.4f} 米")
        print(f"  缩放后最大边长: {max(new_size) * 1000:.2f} mm")

    # ========== 导出 GLB ==========
    if output_path is None:
        base_name = os.path.splitext(input_path)[0]
        output_path = base_name + ".glb"

    try:
        mesh.export(output_path, file_type='glb')
        print(f"\n【导出完成】")
        print(f"  输出文件: {output_path}")
        print(f"  文件大小: {os.path.getsize(output_path) / 1024:.2f} KB")
        print("=" * 60)
        return mesh
    except Exception as e:
        print(f"\n✗ 导出失败: {e}")
        return None


def batch_convert_stl_to_glb(input_dir, output_dir=None, scale_factor=1.0):

    import glob

    # 查找所有 STL 文件
    stl_files = glob.glob(os.path.join(input_dir, "*.stl"))
    stl_files.extend(glob.glob(os.path.join(input_dir, "*.STL")))

    if not stl_files:
        print(f"错误:在目录 {input_dir} 中没有找到 STL 文件")
        return

    print(f"\n找到 {len(stl_files)} 个 STL 文件")
    print("=" * 60)

    # 创建输出目录
    if output_dir and not os.path.exists(output_dir):
        os.makedirs(output_dir)

    success_count = 0
    fail_count = 0

    for i, input_file in enumerate(stl_files, 1):
        print(f"\n[{i}/{len(stl_files)}] 处理: {os.path.basename(input_file)}")

        if output_dir:
            output_file = os.path.join(output_dir, os.path.splitext(os.path.basename(input_file))[0] + ".glb")
        else:
            output_file = os.path.splitext(input_file)[0] + ".glb"

        try:
            mesh = trimesh.load_mesh(input_file, process=False)

            if scale_factor != 1.0:
                mesh.apply_scale(scale_factor)

            mesh.export(output_file, file_type='glb')

            # 打印尺寸
            size = mesh.bounds[1] - mesh.bounds[0]
            print(f"  ✓ 成功 | 尺寸: {max(size) * 1000:.1f}mm | 输出: {os.path.basename(output_file)}")
            success_count += 1

        except Exception as e:
            print(f"  ✗ 失败: {e}")
            fail_count += 1

    print("\n" + "=" * 60)
    print(f"批量转换完成!")
    print(f"成功: {success_count} 个")
    print(f"失败: {fail_count} 个")
    print("=" * 60)


# ========== 使用示例 ==========
if __name__ == "__main__":
    # 单个文件转换
    INPUT_STL = r"E:\soft\qiuxing2.stl"  # 修改为你的 STL 文件路径

    # 方式2:缩放后转换(例如:米转毫米,缩放 0.001)
    analyze_and_convert_stl_to_glb(INPUT_STL, scale_factor=0.001)

    # 方式3:指定输出路径并缩放
    # OUTPUT_GLB = r"C:\path\to\output\model.glb"
    # analyze_and_convert_stl_to_glb(INPUT_STL, OUTPUT_GLB, scale_factor=0.001)

    # 批量转换目录中的所有 STL
    # batch_convert_stl_to_glb(
    #     input_dir=r"C:\path\to\stl_files",
    #     output_dir=r"C:\path\to\glb_output",
    #     scale_factor=0.001  # 米转毫米
    # )

    # 如果只是查看模型参数不导出
    if os.path.exists(INPUT_STL):
        analyze_and_convert_stl_to_glb(INPUT_STL, scale_factor=1.0)
    else:
        print(f"请修改 INPUT_STL 变量为你的 STL 文件路径")
        print("\n使用方法:")
        print("  1. 修改 INPUT_STL = '你的模型.stl'")
        print("  2. 运行脚本")
        print("\n可选参数:")
        print("  - scale_factor=0.001  : 米转毫米")
        print("  - scale_factor=25.4   : 英寸转毫米")
相关推荐
日取其半万世不竭1 小时前
Rust《腐蚀》 服务器低成本怎么开?配置、端口和存档避坑
服务器·开发语言·rust
消失的旧时光-19431 小时前
Kotlin 协程设计思想(十):Kotlin 协程到底解决了什么问题?
开发语言·kotlin·生命周期·rxjava·协程·结构化并发
go不是csgo2 小时前
从0到1理解Go熔断器:sony/gobreaker 源码剖析 + 仿TikTok Feed 项目实战
开发语言·后端·golang
阿狸猿2 小时前
论企业应用系统的分层架构风格
java·开发语言·架构
JAVA9652 小时前
JAVA面试-并发篇 07-CAS底层原理是什么有什么缺陷如何解决
java·开发语言·面试
San813_LDD2 小时前
[QT]Qt对象树笔记:父子关系与内存管理
开发语言·qt
gaohe26AIliuzeyu2 小时前
Java接口
java·开发语言
码云骑士2 小时前
【3.1Java基础】Java运算符常见错误排查:10个高频编译运行错误一网打尽
java·开发语言
小程故事多_802 小时前
RAGFlow 分块策略全景与 Book 策略深度解析
java·开发语言·rag