component-studio / scripts /verify_animation.py
mantrakp's picture
Integrate isolated Astra refinement, learned rigging and native Kimodo animation
381de33 verified
Raw History Blame Contribute Delete
2.61 kB
"""Reimport the delivery GLB and verify skinning plus actual animated deformation."""
import argparse
import json
from pathlib import Path
import sys
import bpy
import numpy as np
p = argparse.ArgumentParser()
p.add_argument("--input", required=True)
p.add_argument("--output", required=True)
a = p.parse_args(sys.argv[sys.argv.index("--") + 1 :])
bpy.ops.object.select_all(action="SELECT")
bpy.ops.object.delete(use_global=False)
bpy.context.scene.render.fps = 30
bpy.ops.import_scene.gltf(filepath=str(Path(a.input).resolve()))
meshes = [
obj
for obj in bpy.context.scene.objects
if obj.type == "MESH" and any(m.type == "ARMATURE" for m in obj.modifiers)
]
assert len(meshes) == 8, "Expected all eight skinned components"
rigs = [obj for obj in bpy.context.scene.objects if obj.type == "ARMATURE"]
assert len(rigs) == 1, "Expected one rig"
assert rigs[0].animation_data and rigs[0].animation_data.action, "Missing embedded animation"
assert len(rigs[0].data.bones) == 21
for obj in meshes:
assert all(v.groups for v in obj.data.vertices), f"Unweighted vertices in {obj.name}"
assert all(abs(sum(g.weight for g in v.groups) - 1) < 0.002 for v in obj.data.vertices)
assert any(m.type == "ARMATURE" for m in obj.modifiers)
assert obj.data.uv_layers, f"Missing UVs in {obj.name}"
assert obj.data.materials, f"Missing materials in {obj.name}"
positions = []
frames = list(range(1, 181))
for frame in frames:
bpy.context.scene.frame_set(frame)
depsgraph = bpy.context.evaluated_depsgraph_get()
coords = []
for obj in meshes:
evaluated = obj.evaluated_get(depsgraph)
mesh = evaluated.to_mesh()
coords.extend(tuple(evaluated.matrix_world @ v.co) for v in mesh.vertices)
evaluated.to_mesh_clear()
coords = np.array(coords)
assert np.isfinite(coords).all()
assert np.max(np.ptp(coords, axis=0)) < 1.6, "Implausible skin stretching"
positions.append(coords)
movement = np.max(np.linalg.norm(np.stack(positions) - positions[0], axis=-1), axis=0)
assert movement.max() > 0.1, "The skin does not move with the animation"
report = {
"verified": True,
"frames_checked": frames,
"mesh_objects": len(meshes),
"bones": 21,
"vertices": len(movement),
"moving_vertices": int((movement > 0.005).sum()),
"max_vertex_displacement": float(movement.max()),
"weights_normalized": True,
"uvs_and_materials_present": True,
"finite_deformed_positions": True,
"animation_name": rigs[0].animation_data.action.name,
}
Path(a.output).write_text(json.dumps(report, indent=2))
print(json.dumps(report))