101 lines
6.3 KiB
C#
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
|