voronstl/create_glb.py
2026-03-04 17:47:07 -08:00

71 lines
No EOL
1.8 KiB
Python

#!/usr/bin/env python3
# create_glb.py — Blender headless STL -> GLB
#
# Example:
# blender-bin-5.0.0 --background --python create_glb.py -- input.stl [output.glb]
import bpy
import sys
import os
from mathutils import Vector
def die(msg, rc=2):
print(f"ERROR: {msg}")
raise SystemExit(rc)
# args after "--"
argv = sys.argv
argv = argv[argv.index("--") + 1:] if "--" in argv else []
if len(argv) == 1:
inp = argv[0]
base, _ = os.path.splitext(inp)
outp = base + ".glb"
elif len(argv) >= 2:
inp, outp = argv[0], argv[1]
else:
die("USAGE: blender --background --python create_glb.py -- input.stl [output.glb]")
if not os.path.exists(inp):
die(f"Input not found: {inp}")
# Empty scene
bpy.ops.wm.read_factory_settings(use_empty=True)
# Import STL (Blender 4/5 operator)
res = bpy.ops.wm.stl_import(filepath=inp)
if 'FINISHED' not in res:
die(f"STL import failed for: {inp}")
# Gather imported mesh objects
objs = [o for o in bpy.context.scene.objects if o.type == 'MESH']
if not objs:
die("No mesh objects after import (unexpected)")
# Compute combined bounding box center in world space
min_v = Vector(( 1e30, 1e30, 1e30))
max_v = Vector((-1e30, -1e30, -1e30))
for o in objs:
# object bound_box is in local coords; transform to world
for corner in o.bound_box:
v = o.matrix_world @ Vector(corner)
min_v.x = min(min_v.x, v.x); min_v.y = min(min_v.y, v.y); min_v.z = min(min_v.z, v.z)
max_v.x = max(max_v.x, v.x); max_v.y = max(max_v.y, v.y); max_v.z = max(max_v.z, v.z)
center = (min_v + max_v) * 0.5
# Translate all meshes so center is at origin
for o in objs:
o.location -= center
# Export GLB
res = bpy.ops.export_scene.gltf(
filepath=outp,
export_format='GLB',
export_apply=True,
)
if 'FINISHED' not in res:
die(f"GLB export failed: {outp}")
print(f"Wrote: {outp}")