import argparse import json import subprocess import sys from pathlib import Path BLENDER = "/Applications/Blender.app/Contents/MacOS/Blender" ap = argparse.ArgumentParser() ap.add_argument("--input", required=True) ap.add_argument("--outdir", required=True) ap.add_argument("--params", default="{}") args = ap.parse_args() p = json.loads(args.params) target = p.get("target", "glb") outdir = Path(args.outdir) out_name = Path(args.input).stem + "." + target out_path = outdir / out_name bpy_script = outdir / "_convert.py" bpy_script.write_text(f""" import bpy, json, sys src = {json.dumps(args.input)} dst = {json.dumps(str(out_path))} params = json.loads({json.dumps(json.dumps(p))}) ext = src.rsplit('.', 1)[-1].lower() bpy.ops.wm.read_factory_settings(use_empty=True) importers = {{ 'glb': lambda: bpy.ops.import_scene.gltf(filepath=src), 'gltf': lambda: bpy.ops.import_scene.gltf(filepath=src), 'obj': lambda: bpy.ops.wm.obj_import(filepath=src), 'fbx': lambda: bpy.ops.import_scene.fbx(filepath=src), 'stl': lambda: bpy.ops.wm.stl_import(filepath=src), 'ply': lambda: bpy.ops.wm.ply_import(filepath=src), 'usd': lambda: bpy.ops.wm.usd_import(filepath=src), 'usdz': lambda: bpy.ops.wm.usd_import(filepath=src), 'usda': lambda: bpy.ops.wm.usd_import(filepath=src), 'dae': lambda: bpy.ops.wm.collada_import(filepath=src), 'abc': lambda: bpy.ops.wm.alembic_import(filepath=src), }} if ext == 'blend': bpy.ops.wm.open_mainfile(filepath=src) else: importers[ext]() scale = params.get('scale', 1.0) if scale != 1.0: for ob in bpy.context.scene.objects: ob.scale = [s * scale for s in ob.scale] if params.get('apply_transforms', True): for ob in bpy.context.scene.objects: ob.select_set(True) if bpy.context.scene.objects: bpy.context.view_layer.objects.active = bpy.context.scene.objects[0] bpy.ops.object.transform_apply(location=False, rotation=True, scale=True) tgt = dst.rsplit('.', 1)[-1].lower() exporters = {{ 'glb': lambda: bpy.ops.export_scene.gltf(filepath=dst, export_format='GLB'), 'fbx': lambda: bpy.ops.export_scene.fbx(filepath=dst), 'obj': lambda: bpy.ops.wm.obj_export(filepath=dst), 'stl': lambda: bpy.ops.wm.stl_export(filepath=dst), 'ply': lambda: bpy.ops.wm.ply_export(filepath=dst), 'usd': lambda: bpy.ops.wm.usd_export(filepath=dst), 'usdz': lambda: bpy.ops.wm.usd_export(filepath=dst), 'blend': lambda: bpy.ops.wm.save_as_mainfile(filepath=dst), }} exporters[tgt]() print('exported', dst) """) cmd = [BLENDER, "-b", "--python", str(bpy_script)] print("+", " ".join(cmd), flush=True) res = subprocess.run(cmd, stdout=sys.stdout, stderr=subprocess.STDOUT) bpy_script.unlink(missing_ok=True) if res.returncode != 0 or not out_path.exists(): sys.exit(res.returncode or 1) (outdir / "result.json").write_text(json.dumps( {"outputs": [{"path": out_name}]})) print("done", flush=True)