AnimatorBindingCache.cs
5.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#if UNITY_EDITOR
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Timeline;
using UnityEditor;
namespace UnityEngine.Timeline
{
/// <summary>
/// Animator to Editor Curve Binding cache. Used to prevent frequent calls to GetAnimatorBindings which can be costly
/// </summary>
class AnimatorBindingCache
{
public const string TRPlaceHolder = "TransformTR";
public const string ScalePlaceholder = "TransformScale";
struct AnimatorEntry
{
public int animatorID;
public bool applyRootMotion;
public bool humanoid;
}
class AnimatorEntryComparer : IEqualityComparer<AnimatorEntry>
{
public bool Equals(AnimatorEntry x, AnimatorEntry y) { return x.animatorID == y.animatorID && x.applyRootMotion == y.applyRootMotion && x.humanoid == y.humanoid; }
public int GetHashCode(AnimatorEntry obj) { return HashUtility.CombineHash(obj.animatorID, obj.applyRootMotion.GetHashCode(), obj.humanoid.GetHashCode()); }
public static readonly AnimatorEntryComparer Instance = new AnimatorEntryComparer();
}
readonly Dictionary<AnimatorEntry, EditorCurveBinding[]> m_AnimatorCache = new Dictionary<AnimatorEntry, EditorCurveBinding[]>(AnimatorEntryComparer.Instance);
readonly Dictionary<AnimationClip, EditorCurveBinding[]> m_ClipCache = new Dictionary<AnimationClip, EditorCurveBinding[]>();
private static readonly EditorCurveBinding[] kEmptyArray = new EditorCurveBinding[0];
private static readonly List<EditorCurveBinding> s_BindingScratchPad = new List<EditorCurveBinding>(1000);
public AnimatorBindingCache()
{
AnimationUtility.onCurveWasModified += OnCurveWasModified;
}
public EditorCurveBinding[] GetAnimatorBindings(GameObject gameObject)
{
if (gameObject == null)
return kEmptyArray;
Animator animator = gameObject.GetComponent<Animator>();
if (animator == null)
return kEmptyArray;
AnimatorEntry entry = new AnimatorEntry()
{
animatorID = animator.GetInstanceID(),
applyRootMotion = animator.applyRootMotion,
humanoid = animator.isHuman
};
EditorCurveBinding[] result = null;
if (m_AnimatorCache.TryGetValue(entry, out result))
return result;
s_BindingScratchPad.Clear();
// Replacement for AnimationMode.GetAnimatorBinding - this is faster and allocates kB instead of MB
var transforms = animator.GetComponentsInChildren<Transform>();
foreach (var t in transforms)
{
if (animator.IsBoneTransform(t))
s_BindingScratchPad.Add(EditorCurveBinding.FloatCurve(AnimationUtility.CalculateTransformPath(t, animator.transform), typeof(Transform), TRPlaceHolder));
}
var streamBindings = AnimationUtility.GetAnimationStreamBindings(animator.gameObject);
UpdateTransformBindings(streamBindings);
s_BindingScratchPad.AddRange(streamBindings);
result = new EditorCurveBinding[s_BindingScratchPad.Count];
s_BindingScratchPad.CopyTo(result);
m_AnimatorCache[entry] = result;
return result;
}
public EditorCurveBinding[] GetCurveBindings(AnimationClip clip)
{
if (clip == null)
return kEmptyArray;
EditorCurveBinding[] result;
if (!m_ClipCache.TryGetValue(clip, out result))
{
result = AnimationMode.GetCurveBindings(clip);
UpdateTransformBindings(result);
m_ClipCache[clip] = result;
}
return result;
}
private static void UpdateTransformBindings(EditorCurveBinding[] bindings)
{
for (int i = 0; i < bindings.Length; i++)
{
var binding = bindings[i];
if (AnimationPreviewUtilities.IsRootMotion(binding))
{
binding.type = typeof(Transform);
binding.propertyName = TRPlaceHolder;
}
else if (typeof(Transform).IsAssignableFrom(binding.type) && (binding.propertyName.StartsWith("m_LocalRotation.") || binding.propertyName.StartsWith("m_LocalPosition.")))
{
binding.propertyName = TRPlaceHolder;
}
else if (typeof(Transform).IsAssignableFrom(binding.type) && binding.propertyName.StartsWith("m_LocalScale."))
{
binding.propertyName = ScalePlaceholder;
}
bindings[i] = binding;
}
}
public void Clear()
{
m_AnimatorCache.Clear();
m_ClipCache.Clear();
}
void OnCurveWasModified(AnimationClip clip, EditorCurveBinding binding, AnimationUtility.CurveModifiedType modification)
{
m_ClipCache.Remove(clip);
}
}
}
#endif