68 lines
2.0 KiB
GDScript
68 lines
2.0 KiB
GDScript
|
|
# 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)
|