MIRPAMO/bpy/verify_glb.py
jing a148b4a543 MIRPAMO v0: local Mixamo — autorig + retarget via headless Blender
- autorig: landmark detection from vertex cloud (markers JSON override),
  mixamorig 22-bone skeleton fit, bone-heat weights + nearest-bone rescue
- retarget: world-space quaternion delta transfer, hip-height scale
  compensation, fuzzy/explicit bone mapping (CMU map bundled)
- smoke: procedural test humanoid + synthetic BVH -> rig -> retarget -> verify
- deploy: push to gitea, pull + smoke on m3ultra and m1ultra

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 01:26:13 +10:00

75 lines
2.3 KiB
Python

"""Verify a MIRPAMO output GLB: armature present, meshes skinned,
animations present with real motion. Prints a JSON report; exit 1 on failure.
Usage: blender -b --python bpy/verify_glb.py -- --in out/final.glb \
[--expect-anim] [--min-frames 10]
"""
import argparse
import json
import os
import sys
import bpy
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from common import (clean_scene, count_fcurves, die, find_armature,
find_meshes, import_any, stage_args)
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--in", dest="inp", required=True)
ap.add_argument("--expect-anim", action="store_true")
ap.add_argument("--min-frames", type=int, default=10)
args = ap.parse_args(stage_args())
clean_scene()
objs = import_any(args.inp)
arm = find_armature(objs)
meshes = find_meshes(objs)
report = {
"file": args.inp,
"armature": arm.name if arm else None,
"bones": len(arm.data.bones) if arm else 0,
"meshes": [m.name for m in meshes],
"skinned": [],
"actions": {},
}
if not arm:
print(json.dumps(report, indent=2))
die("no armature in output")
if not meshes:
print(json.dumps(report, indent=2))
die("no meshes in output")
for m in meshes:
has_arm_mod = any(mod.type == "ARMATURE" for mod in m.modifiers)
has_groups = len(m.vertex_groups) > 0
report["skinned"].append(
{"mesh": m.name, "armature_mod": has_arm_mod,
"vertex_groups": len(m.vertex_groups)})
if not (has_arm_mod and has_groups):
print(json.dumps(report, indent=2))
die(f"mesh {m.name} is not skinned")
for act in bpy.data.actions:
fr = act.frame_range
n_frames = int(fr[1] - fr[0]) + 1
report["actions"][act.name] = {
"frames": n_frames, "fcurves": count_fcurves(act)}
if args.expect_anim:
good = [a for a, v in report["actions"].items()
if v["frames"] >= args.min_frames and v["fcurves"] > 0]
if not good:
print(json.dumps(report, indent=2))
die(f"no action with >= {args.min_frames} frames found")
print(json.dumps(report, indent=2))
print("[mirpamo] verify OK")
main()