squad-proto/tools/blender/inspect_source_model.py

47 lines
2.1 KiB
Python
Raw Normal View History

"""Print a compact inventory of a Blender-compatible source model."""
import sys
from pathlib import Path
import bpy
from mathutils import Vector
def main() -> None:
marker = sys.argv.index("--")
source = Path(sys.argv[marker + 1]).resolve()
bpy.ops.wm.read_factory_settings(use_empty=True)
suffix = source.suffix.lower()
if suffix in {".glb", ".gltf"}:
bpy.ops.import_scene.gltf(filepath=str(source))
elif suffix == ".fbx":
bpy.ops.import_scene.fbx(filepath=str(source))
elif suffix == ".obj":
bpy.ops.wm.obj_import(filepath=str(source))
else:
raise SystemExit(f"unsupported source format: {suffix}")
for obj in sorted(bpy.context.scene.objects, key=lambda value: value.name):
if obj.type == "MESH":
corners = [obj.matrix_world @ Vector(corner) for corner in obj.bound_box]
lo = tuple(round(min(point[index] for point in corners), 4) for index in range(3))
hi = tuple(round(max(point[index] for point in corners), 4) for index in range(3))
parent = obj.parent.name if obj.parent else "-"
print(f"MESH {obj.name} verts={len(obj.data.vertices)} mats={len(obj.data.materials)} parent={parent} hide={obj.hide_render} bbox={lo}..{hi}")
elif obj.type == "ARMATURE":
bones = ",".join(bone.name for bone in obj.data.bones)
print(f"ARMATURE {obj.name} bones={len(obj.data.bones)} [{bones}]")
for bone in obj.data.bones:
if bone.name in {"root","DEF-hips","DEF-spine.002","DEF-spine.003","DEF-head",
"DEF-hand.L","DEF-hand.R","DEF-upper_arm.L","DEF-upper_arm.R"}:
head=tuple(round(value,4) for value in bone.head_local)
tail=tuple(round(value,4) for value in bone.tail_local)
print(f"BONE {bone.name} {head}->{tail}")
for action in sorted(bpy.data.actions, key=lambda value: value.name):
start, end = action.frame_range
print(f"ACTION {action.name} frames={start:.0f}..{end:.0f}")
if __name__ == "__main__":
main()