#if UNITY_EDITOR using System; using System.IO; using System.Linq; using System.Collections.Generic; using Newtonsoft.Json; using UnityEditor; using UnityEditor.Animations; using UnityEditor.SceneManagement; using UnityEngine; public static class DiagnoseBotWalkTranslation { static float[] V(Vector3 v) => new[] { v.x, v.y, v.z }; public static string Run() { const string common = "Assets/Bundles/Characters/Human/Common"; var reports = new List(); foreach (string name in new[] { "XBot", "YBot", "XBot25", "XBot41" }) { var scene = EditorSceneManager.NewPreviewScene(); try { var go = (GameObject)PrefabUtility.InstantiatePrefab(AssetDatabase.LoadAssetAtPath(common + "/Prefabs/" + name + ".prefab"), scene); var a = go.GetComponent(); a.applyRootMotion = false; a.cullingMode = AnimatorCullingMode.AlwaysAnimate; a.Rebind(); a.SetInteger("Motion",1); a.Update(0); var clip = (AnimationClip)((AnimatorController)a.runtimeAnimatorController).layers[0].stateMachine.states.Single(s=>s.state.name=="Walk").state.motion; var importer = (ModelImporter)AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(clip)); var settings = importer.clipAnimations.Single(); var points = new List(); var roots = new List(); var samples = new List(); for (int i=0;i<=60;i++) { float phase = i/60f; a.Play("Base Layer.Walk",0,Mathf.Min(.99999f,phase)); a.Update(0); Vector3 hip = a.GetBoneTransform(HumanBodyBones.Hips).position-go.transform.position; points.Add(hip); roots.Add(go.transform.position); if (i%15==0) samples.Add(new { phase, hipsFromRoot=V(hip), root=V(go.transform.position) }); } var min = points.Aggregate(Vector3.positiveInfinity,Vector3.Min); var max = points.Aggregate(Vector3.negativeInfinity,Vector3.Max); var rootMin=roots.Aggregate(Vector3.positiveInfinity,Vector3.Min);var rootMax=roots.Aggregate(Vector3.negativeInfinity,Vector3.Max); reports.Add(new { name, clip=AssetDatabase.GetAssetPath(clip), clip.length, applyRootMotion=a.applyRootMotion, settings.lockRootPositionXZ, settings.keepOriginalPositionXZ, settings.loopTime, hipRangeWorldMeters=V(max-min), hipNetTravelWorldMeters=V(points.Last()-points.First()), rootRangeWorldMeters=V(rootMax-rootMin), samples }); } finally { EditorSceneManager.ClosePreviewScene(scene); } } string json=JsonConvert.SerializeObject(reports,Formatting.Indented); string folder=Path.Combine(Directory.GetParent(Application.dataPath).Parent.FullName,"Tools/output/bot_animation_lab"); Directory.CreateDirectory(folder);File.WriteAllText(Path.Combine(folder,"walk_translation_diagnostic.json"),json); return json; } public static string CompareExtraction() { const string common="Assets/Bundles/Characters/Human/Common"; const string folder="Assets/Review/BotAnimationLab/TranslationProbe"; if (AssetDatabase.IsValidFolder(folder)) throw new Exception("Probe folder already exists"); AssetDatabase.CreateFolder("Assets/Review/BotAnimationLab","TranslationProbe"); var reports=new List(); try { foreach(string name in new[]{"XBot","YBot"}) { string source=common+"/Anim"+(name=="XBot"?"X":"Y")+"/"+(name=="XBot"?"X":"Y")+" Bot@Walking.fbx"; string path=folder+"/"+name+"_Probe.fbx"; if(!AssetDatabase.CopyAsset(source,path))throw new Exception("Copy failed"); var importer=(ModelImporter)AssetImporter.GetAtPath(path); var settings=importer.clipAnimations; settings[0].lockRootPositionXZ=false; settings[0].keepOriginalPositionXZ=false; importer.clipAnimations=settings;importer.SaveAndReimport(); var clip=AssetDatabase.LoadAllAssetsAtPath(path).OfType().Single(c=>!c.name.StartsWith("__preview__")); var scene=EditorSceneManager.NewPreviewScene(); AnimatorOverrideController controller=null; try { var go=(GameObject)PrefabUtility.InstantiatePrefab(AssetDatabase.LoadAssetAtPath(common+"/Prefabs/"+name+".prefab"),scene); var a=go.GetComponent(); controller=new AnimatorOverrideController(a.runtimeAnimatorController); var original=controller.animationClips.Single(c=>c.name=="Walk");controller[original]=clip; a.runtimeAnimatorController=controller;a.applyRootMotion=false;a.Rebind();a.SetInteger("Motion",1);a.Update(0); var points=new List();var roots=new List(); for(int i=0;i<=60;i++) { a.Play("Base Layer.Walk",0,Mathf.Min(.99999f,i/60f));a.Update(0); points.Add(a.GetBoneTransform(HumanBodyBones.Hips).position-go.transform.position);roots.Add(go.transform.position); } var range=points.Aggregate(Vector3.negativeInfinity,Vector3.Max)-points.Aggregate(Vector3.positiveInfinity,Vector3.Min); var rootRange=roots.Aggregate(Vector3.negativeInfinity,Vector3.Max)-roots.Aggregate(Vector3.positiveInfinity,Vector3.Min); reports.Add(new{name,lockRootPositionXZ=false,keepOriginalPositionXZ=false,hipRangeWorldMeters=V(range),rootRangeWorldMeters=V(rootRange)}); } finally { EditorSceneManager.ClosePreviewScene(scene);if(controller)UnityEngine.Object.DestroyImmediate(controller); } } } finally { AssetDatabase.DeleteAsset(folder); } string json=JsonConvert.SerializeObject(reports,Formatting.Indented); string output=Path.Combine(Directory.GetParent(Application.dataPath).Parent.FullName,"Tools/output/bot_animation_lab/walk_translation_extraction_comparison.json"); File.WriteAllText(output,json);return json; } } #endif