Files
AIGame/Tools/model_tools/summarize_mixamo_playback.py

31 lines
1.8 KiB
Python

"""Compare Unity evaluation against raw FBX joint trajectories, pelvis-relative."""
import json,math
from pathlib import Path
ROOT=Path(__file__).resolve().parents[2]
OUT=ROOT/'Tools/output/campguide_studio/playback_audit'
reference=json.loads((OUT/'fbx_reference.json').read_text(encoding='utf-8'))[1]
comparison=json.loads((OUT/'comparison.json').read_text(encoding='utf-8'))
def sub(a,b):return [a[i]-b[i] for i in range(3)]
def length(a):return math.sqrt(sum(v*v for v in a))
def unity(p):return [-p[0],p[2],-p[1]]
def angle(a,b):return math.degrees(math.acos(max(-1,min(1,sum(a[i]*b[i] for i in range(3))/(length(a)*length(b))))))
report=[]
for entry in comparison['samples']:
maximum=0;feet_max=0;angles=[];gaps=[]
for frame,pose in enumerate(entry['frames']):
raw={name:unity(p) for name,p in reference['samples'][frame]['world'].items()}
for name,p in pose.items():
delta=sub(sub(p,pose['mixamorig:Hips']),sub(raw[name],raw['mixamorig:Hips']))
error=length(delta);maximum=max(maximum,error)
if name.endswith('Foot'):feet_max=max(feet_max,error)
for side in ('Left','Right'):
ankle='mixamorig:'+side+'Foot';toe='mixamorig:'+side+'ToeBase'
angles.append(angle(sub(pose[toe],pose[ankle]),sub(raw[toe],raw[ankle])))
gaps.append(pose['mixamorig:RightFoot'][0]-pose['mixamorig:LeftFoot'][0])
report.append(dict(variant=entry['tag'],max_joint_error_m=maximum,max_ankle_error_m=feet_max,
max_foot_direction_error_degrees=max(angles),min_signed_ankle_gap_m=min(gaps),crossed_frames=sum(g<0 for g in gaps)))
print(json.dumps(report,indent=2))
assert report[0]['max_joint_error_m']<.001,'Generic reference does not match the original FBX'
(OUT/'summary.json').write_text(json.dumps(report,indent=2),encoding='utf-8')