"""Rigidly orient a generated character before baking/rigging, preserving UVs.""" import argparse import json import math from pathlib import Path import sys import bpy from mathutils import Matrix,Vector p=argparse.ArgumentParser(description=__doc__) p.add_argument('source',type=Path);p.add_argument('output',type=Path) p.add_argument('--blender-yaw',type=float,required=True) a=p.parse_args(sys.argv[sys.argv.index('--')+1:]) bpy.ops.wm.read_factory_settings(use_empty=True) bpy.ops.import_scene.gltf(filepath=str(a.source.resolve())) if any(o.type=='ARMATURE' for o in bpy.data.objects):raise ValueError('Orient the static high source before rigging') rotation=Matrix.Rotation(math.radians(a.blender_yaw),4,'Z') roots=[o for o in bpy.context.scene.objects if o.parent is None] for o in roots:o.matrix_world=rotation@o.matrix_world bpy.context.view_layer.update() points=[o.matrix_world@v.co for o in bpy.context.scene.objects if o.type=='MESH' for v in o.data.vertices] mn=Vector([min(p[c] for p in points) for c in range(3)]);mx=Vector([max(p[c] for p in points) for c in range(3)]) offset=Matrix.Translation(-Vector(((mn.x+mx.x)/2,(mn.y+mx.y)/2,mn.z))) for o in roots:o.matrix_world=offset@o.matrix_world a.output.parent.mkdir(parents=True,exist_ok=True) bpy.ops.export_scene.gltf(filepath=str(a.output.resolve()),export_format='GLB') record=dict(source=str(a.source),output=str(a.output),blender_yaw_degrees=a.blender_yaw,orientation_note='Verify final forward in Unity views: FBX handedness conversion must be included.',height=mx.z-mn.z,mesh_unchanged_except_rigid_transform=True) a.output.with_suffix('.orientation.json').write_text(json.dumps(record,indent=2),encoding='utf-8') print(json.dumps(record))