Files
AIGame/AIClient/AgentScripts/DiagnoseBotWalkTranslation.cs
T

101 lines
6.3 KiB
C#

#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<object>();
foreach (string name in new[] { "XBot", "YBot", "XBot25", "XBot41" })
{
var scene = EditorSceneManager.NewPreviewScene();
try
{
var go = (GameObject)PrefabUtility.InstantiatePrefab(AssetDatabase.LoadAssetAtPath<GameObject>(common + "/Prefabs/" + name + ".prefab"), scene);
var a = go.GetComponent<Animator>(); 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<Vector3>(); var roots = new List<Vector3>(); var samples = new List<object>();
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<object>();
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<AnimationClip>().Single(c=>!c.name.StartsWith("__preview__"));
var scene=EditorSceneManager.NewPreviewScene();
AnimatorOverrideController controller=null;
try
{
var go=(GameObject)PrefabUtility.InstantiatePrefab(AssetDatabase.LoadAssetAtPath<GameObject>(common+"/Prefabs/"+name+".prefab"),scene);
var a=go.GetComponent<Animator>();
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<Vector3>();var roots=new List<Vector3>();
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