Files
AIGame/AIClient/AgentScripts/DiagnoseRockBallOrient.cs

84 lines
4.3 KiB
C#

#if UNITY_EDITOR
using System.Linq;
using System.Text;
using UnityEditor;
using UnityEngine;
public static class DiagnoseRockBallOrient
{
static string Fmt(Vector3 v) => $"({v.x:F3},{v.y:F3},{v.z:F3})";
static string FmtE(Quaternion q) => $"({q.eulerAngles.x:F1},{q.eulerAngles.y:F1},{q.eulerAngles.z:F1})";
static Bounds MeshBounds(GameObject go)
{
var rs = go.GetComponentsInChildren<Renderer>()
.Where(r => r.name != "ForwardMinusZ" && r.GetComponent<TextMesh>() == null)
.ToArray();
var b = rs[0].bounds;
for (int i = 1; i < rs.Length; i++) b.Encapsulate(rs[i].bounds);
return b;
}
public static string Run()
{
var sb = new StringBuilder();
var staticP = AssetDatabase.LoadAssetAtPath<GameObject>("Assets/Bundles/Characters/Animal/RockBall/RockBall.prefab");
var rigP = AssetDatabase.LoadAssetAtPath<GameObject>("Assets/Bundles/Characters/Animal/RockBall/RockBall_Rigged.prefab");
var a = (GameObject)PrefabUtility.InstantiatePrefab(staticP);
a.transform.SetPositionAndRotation(Vector3.zero, Quaternion.identity);
var ba = MeshBounds(a);
sb.AppendLine($"STATIC bounds min={Fmt(ba.min)} size={Fmt(ba.size)}");
Object.DestroyImmediate(a);
var b = (GameObject)PrefabUtility.InstantiatePrefab(rigP);
b.transform.SetPositionAndRotation(new Vector3(3, 0, 0), Quaternion.identity);
var anim = b.GetComponentInChildren<Animator>();
var bone0 = b.GetComponentsInChildren<Transform>().FirstOrDefault(t => t.name == "bone_0");
var arm = b.GetComponentsInChildren<Transform>().FirstOrDefault(t => t.name == "Armature");
anim.Rebind();
anim.Update(0f);
var br = MeshBounds(b);
sb.AppendLine($"RIGGED rebind bounds min={Fmt(br.min)} size={Fmt(br.size)}");
if (arm != null) sb.AppendLine($" Armature up={Fmt(arm.up)} fwd={Fmt(arm.forward)} euler={FmtE(arm.rotation)}");
if (bone0 != null) sb.AppendLine($" bone0 up={Fmt(bone0.up)} fwd={Fmt(bone0.forward)} euler={FmtE(bone0.rotation)}");
foreach (var motion in new[] { 0, 1, 2 })
{
anim.Rebind();
anim.SetInteger("Motion", motion);
anim.Update(0f);
for (int i = 0; i < 15; i++) anim.Update(0.05f);
var bm = MeshBounds(b);
string name = motion == 0 ? "Idle" : motion == 1 ? "Walk" : "Attack";
sb.AppendLine($"{name}: bounds min={Fmt(bm.min)} size={Fmt(bm.size)} extentY/X={(bm.size.y / Mathf.Max(0.001f, bm.size.x)):F2}");
if (bone0 != null)
sb.AppendLine($" bone0 up={Fmt(bone0.up)} euler={FmtE(bone0.rotation)}");
}
// clip: does Armature/bone_0 leave bind orientation?
foreach (var name in new[] { "Idle", "Walk", "Attack" })
{
var clip = AssetDatabase.LoadAssetAtPath<AnimationClip>($"Assets/Bundles/Characters/Animal/RockBall/Clips/{name}.anim");
if (clip == null) continue;
sb.AppendLine($"clip {name}:");
foreach (var path in new[] { "Armature", "Armature/bone_0" })
{
var qx = AnimationUtility.GetEditorCurve(clip, new EditorCurveBinding { path = path, propertyName = "m_LocalRotation.x", type = typeof(Transform) });
var qy = AnimationUtility.GetEditorCurve(clip, new EditorCurveBinding { path = path, propertyName = "m_LocalRotation.y", type = typeof(Transform) });
var qz = AnimationUtility.GetEditorCurve(clip, new EditorCurveBinding { path = path, propertyName = "m_LocalRotation.z", type = typeof(Transform) });
var qw = AnimationUtility.GetEditorCurve(clip, new EditorCurveBinding { path = path, propertyName = "m_LocalRotation.w", type = typeof(Transform) });
if (qx == null) continue;
var q0 = new Quaternion(qx.Evaluate(0), qy.Evaluate(0), qz.Evaluate(0), qw.Evaluate(0));
var q1 = new Quaternion(qx.Evaluate(clip.length * 0.5f), qy.Evaluate(clip.length * 0.5f), qz.Evaluate(clip.length * 0.5f), qw.Evaluate(clip.length * 0.5f));
sb.AppendLine($" {path} t0 euler={FmtE(q0)} tMid euler={FmtE(q1)} angleDelta={Quaternion.Angle(q0, q1):F1}");
}
}
Object.DestroyImmediate(b);
return sb.ToString();
}
}
#endif