male(v15): Tripo mesh + Meshy rig, UAL retarget test beds
- male/: raw + z-facing + quat-named bodies, Meshy rigged GLB/FBX, stock walk/run clips, male-ual-clips.glb (16 UAL1 clips baked via ariki-game mixamo_retarget.py --map ual) - anim_male.tscn: Meshy stock clips; anim_male_ual.tscn: UAL clips (scales position keys x100 — Meshy skeleton is cm, clips are m) - view_tripo.tscn: env-var GLB turntable/anim shots + interactive orbit - rotate_glb.gd: headless face-+Z/height fixup (Meshy pose estimation rejects Tripo's +X-facing normalized output) - Meshy spine chain is reverse-named: Spine02 = lowest vertebra Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
# Headless GLB fixup: rotate a model to face +Z and scale to a target height,
|
||||
# baking the transform into vertices via the root node transform on export.
|
||||
# Env: ROT_IN (glb path), ROT_OUT (glb path), ROT_YAW_DEG, ROT_HEIGHT_M
|
||||
extends SceneTree
|
||||
|
||||
func _init() -> void:
|
||||
var in_path := OS.get_environment("ROT_IN")
|
||||
var out_path := OS.get_environment("ROT_OUT")
|
||||
var yaw_deg := float(OS.get_environment("ROT_YAW_DEG"))
|
||||
var target_h := float(OS.get_environment("ROT_HEIGHT_M"))
|
||||
|
||||
var doc := GLTFDocument.new()
|
||||
var state := GLTFState.new()
|
||||
if doc.append_from_file(in_path, state) != OK:
|
||||
push_error("load failed: " + in_path)
|
||||
quit(1)
|
||||
return
|
||||
var scene := doc.generate_scene(state)
|
||||
|
||||
# measure current height from merged mesh AABB
|
||||
var merged := AABB()
|
||||
var first := true
|
||||
var stack: Array = [scene]
|
||||
while not stack.is_empty():
|
||||
var n: Node = stack.pop_back()
|
||||
if n is MeshInstance3D:
|
||||
var box: AABB = (n as MeshInstance3D).get_aabb()
|
||||
if first:
|
||||
merged = box
|
||||
first = false
|
||||
else:
|
||||
merged = merged.merge(box)
|
||||
for c in n.get_children():
|
||||
stack.push_back(c)
|
||||
var h := merged.size.y
|
||||
var s := target_h / h if h > 0.001 else 1.0
|
||||
print("height=", h, " scale=", s)
|
||||
|
||||
var wrapper := Node3D.new()
|
||||
wrapper.name = "Root"
|
||||
wrapper.rotate_y(deg_to_rad(yaw_deg))
|
||||
wrapper.scale = Vector3(s, s, s)
|
||||
# move model so feet sit at y=0 after scaling
|
||||
scene.position.y = -merged.position.y
|
||||
var parent := scene.get_parent()
|
||||
if parent != null:
|
||||
parent.remove_child(scene)
|
||||
wrapper.add_child(scene)
|
||||
_own_recursive(scene, wrapper)
|
||||
|
||||
var out_doc := GLTFDocument.new()
|
||||
var out_state := GLTFState.new()
|
||||
if out_doc.append_from_scene(wrapper, out_state) != OK:
|
||||
push_error("export append failed")
|
||||
quit(1)
|
||||
return
|
||||
if out_doc.write_to_filesystem(out_state, out_path) != OK:
|
||||
push_error("write failed: " + out_path)
|
||||
quit(1)
|
||||
return
|
||||
print("WROTE ", out_path)
|
||||
quit(0)
|
||||
|
||||
func _own_recursive(n: Node, owner: Node) -> void:
|
||||
n.owner = owner
|
||||
for c in n.get_children():
|
||||
_own_recursive(c, owner)
|
||||
Reference in New Issue
Block a user