- 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>
30 lines
1.7 KiB
Python
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))
|