#if UNITY_EDITOR using System; using System.Collections.Generic; using System.IO; using System.Linq; using AIGame.Review; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using UnityEditor; using UnityEngine; using UnityEngine.UI; public static class VerifyCharacterAnimationLab { static string Repo => Directory.GetParent(Application.dataPath).Parent.FullName; static string Output => Path.Combine(Repo,"Tools/output/campguide_studio/rig_mixamo41/unity_review"); const string Root="Assets/Review/CharacterAnimationLab"; public static string Verify() { var data=JObject.Parse(File.ReadAllText(Path.Combine(Output,"review_data.json"))); var expected=JArray.Parse(File.ReadAllText(Path.Combine(Output,"../comparison.json"))).Concat(JArray.Parse(File.ReadAllText(Path.Combine(Output,"../comparison_local.json")))).ToArray(); var prefab=PrefabUtility.LoadPrefabContents(Root+"/Generated/CharacterAnimationLab.prefab"); var previous=QualitySettings.skinWeights;var baked=new Mesh(); try { QualitySettings.skinWeights=SkinWeights.Unlimited; var viewer=prefab.GetComponent(); viewer.inPlace=false;viewer.yaw=0;viewer.playing=false; // BakeMesh includes the presentation scale in this hierarchy. Audit // at the original 1.135m source scale used for the Blender metrics. foreach(var actor in viewer.actors)actor.rig.transform.localScale=Vector3.one; var results=new List(); string[] prefixes={"Mixamo","TokenRig41","TokenRigLocal"}; string[] labels={"Walking","Breathing Idle","Happy Idle"}; for(int c=0;c<3;c++) { viewer.motion=c; var max=new float[3,4];var over=new int[3]; int frames=((JArray)data["clips"][c]["samples"]).Count; for(int frame=0;frame2)over[actor]++; } } } for(int actor=0;actor<3;actor++) { var reference=expected.First(x=>(string)x["label"]==prefixes[actor]+" "+labels[c]); string[] regions={"all","hands","neck","head"}; float worstError=0; for(int region=0;region<4;region++)worstError=Mathf.Max(worstError,Mathf.Abs(max[actor,region]-(float)reference["animation"]["summary"][regions[region]]["max_edge_stretch"])); if(worstError>.003f)throw new InvalidOperationException(prefixes[actor]+" "+labels[c]+" native skinning mismatch "+worstError+" actual="+max[actor,0]); results.Add(new {variant=prefixes[actor],motion=labels[c],frames,maxStretch=max[actor,0],handMax=max[actor,1],neckMax=max[actor,2],maxDifferenceFromBlender=worstError}); } } int buttons=viewer.ui.GetComponentsInChildren