Files
AIGame/Tools/model_tools/bl_orient_character.py
udxandClaude Opus 5.5 89e0fa246f Add formal enemies, remaining formal partners and synthesized UI SFX
- UI SFX v3: procedurally synthesized one-shots (Tools/synth_ui_sfx.py) wired to
  buttons, rewards, errors and red dots via UiSfx, gated by the SFX setting.
- Five formal enemies (Hornlet, Dashlet, Shellhorn, HornCaptain, GreatHorn):
  Hunyuan 50k -> 2000-tri XPbr, DGXA TokenRig, Idle/Walk/Attack, nested per type
  in PrototypeArena; PrototypeBattle.Enemy gains presentation-only Moving/Strikes.
- Formal partners for all ten pets in the arena and portraits, including new
  VineSprite, ThunderLeopard and TideWhale.
- Pipeline fixes: reject local TokenRig fallback, drop loose mesh islands,
  configurable Unity run_script timeout, companion static stage.
- Also includes concurrent work from another tool in this working tree
  (FlameLion, enemy combat FX, challenge mode, home explorer, server updates).
- Resources registered in Doc/ResDesc_*.md; verified on isolated :18081.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 12:23:55 +08:00

30 lines
1.7 KiB
Python

"""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))