diff options
| author | Andrew Lee <alee14498@protonmail.com> | 2020-04-19 17:19:32 -0400 |
|---|---|---|
| committer | Andrew Lee <alee14498@protonmail.com> | 2020-04-19 17:19:32 -0400 |
| commit | c55fba8ab2a1c9d3df65eda4a5a1e957f4aa1f78 (patch) | |
| tree | ee4d51c7c1d633e11f46453ef1edd3c77c4ef9f7 /Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/AnimationPreviewUtilities.cs | |
| download | Project-Sandbox-c55fba8ab2a1c9d3df65eda4a5a1e957f4aa1f78.tar.gz Project-Sandbox-c55fba8ab2a1c9d3df65eda4a5a1e957f4aa1f78.tar.bz2 Project-Sandbox-c55fba8ab2a1c9d3df65eda4a5a1e957f4aa1f78.zip | |
Inital commit
Diffstat (limited to 'Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/AnimationPreviewUtilities.cs')
| -rw-r--r-- | Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/AnimationPreviewUtilities.cs | 266 |
1 files changed, 266 insertions, 0 deletions
diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/AnimationPreviewUtilities.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/AnimationPreviewUtilities.cs new file mode 100644 index 0000000..b8ab669 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/AnimationPreviewUtilities.cs @@ -0,0 +1,266 @@ +#if UNITY_EDITOR +using System.Collections.Generic; +using UnityEditor; + + +namespace UnityEngine.Timeline +{ + static class AnimationPreviewUtilities + { + private const string k_PosX = "m_LocalPosition.x"; + private const string k_PosY = "m_LocalPosition.y"; + private const string k_PosZ = "m_LocalPosition.z"; + private const string k_RotX = "m_LocalRotation.x"; + private const string k_RotY = "m_LocalRotation.y"; + private const string k_RotZ = "m_LocalRotation.z"; + private const string k_RotW = "m_LocalRotation.w"; + private const string k_ScaleX = "m_LocalScale.x"; + private const string k_ScaleY = "m_LocalScale.y"; + private const string k_ScaleZ = "m_LocalScale.z"; + private const string k_EulerAnglesRaw = "localEulerAnglesRaw"; + private const string k_EulerHint = "m_LocalEulerAnglesHint"; + private const string k_Pos = "m_LocalPosition"; + private const string k_Rot = "m_LocalRotation"; + private const string k_MotionT = "MotionT"; + private const string k_MotionQ = "MotionQ"; + private const string k_RootT = "RootT"; + private const string k_RootQ = "RootQ"; + + + internal class EditorCurveBindingComparer : IEqualityComparer<EditorCurveBinding> + { + public bool Equals(EditorCurveBinding x, EditorCurveBinding y) { return x.path.Equals(y.path) && x.type == y.type && x.propertyName == y.propertyName; } + public int GetHashCode(EditorCurveBinding obj) + { + return obj.propertyName.GetHashCode() ^ obj.path.GetHashCode(); + } + + public static readonly EditorCurveBindingComparer Instance = new EditorCurveBindingComparer(); + } + + // a dictionary is faster than a hashset, because the capacity can be pre-set + private static readonly Dictionary<EditorCurveBinding, int> s_CurveSet = new Dictionary<EditorCurveBinding, int>(10000, EditorCurveBindingComparer.Instance); + private static readonly AnimatorBindingCache s_BindingCache = new AnimatorBindingCache(); + + public static void ClearCaches() + { + s_BindingCache.Clear(); + s_CurveSet.Clear(); + } + + public static EditorCurveBinding[] GetBindings(GameObject animatorRoot, IEnumerable<AnimationClip> clips) + { + s_CurveSet.Clear(); + foreach (var clip in clips) + { + AddBindings(s_BindingCache.GetCurveBindings(clip)); + } + + // if we have a transform binding, bind the entire skeleton + if (NeedsSkeletonBindings(s_CurveSet.Keys)) + AddBindings(s_BindingCache.GetAnimatorBindings(animatorRoot)); + + var bindings = new EditorCurveBinding[s_CurveSet.Keys.Count]; + s_CurveSet.Keys.CopyTo(bindings, 0); + return bindings; + } + + public static void PreviewFromCurves(GameObject animatorRoot, IEnumerable<EditorCurveBinding> keys) + { + if (!AnimationMode.InAnimationMode()) + return; + + var avatarRoot = GetAvatarRoot(animatorRoot); + foreach (var binding in keys) + { + if (IsAvatarBinding(binding) || IsEuler(binding)) + continue; + + bool isTransform = typeof(Transform).IsAssignableFrom(binding.type); + if (isTransform && binding.propertyName == AnimatorBindingCache.TRPlaceHolder) + AddTRBinding(animatorRoot, binding); + else if (isTransform && binding.propertyName == AnimatorBindingCache.ScalePlaceholder) + AddScaleBinding(animatorRoot, binding); + else + AnimationMode.AddEditorCurveBinding(avatarRoot, binding); + } + } + + public static AnimationClip CreateDefaultClip(GameObject animatorRoot, IEnumerable<EditorCurveBinding> keys) + { + AnimationClip animClip = new AnimationClip() { name = "DefaultPose" }; + var keyFrames = new[] {new Keyframe(0, 0)}; + var curve = new AnimationCurve(keyFrames); + bool rootMotion = false; + var avatarRoot = GetAvatarRoot(animatorRoot); + + foreach (var binding in keys) + { + if (IsRootMotion(binding)) + { + rootMotion = true; + continue; + } + + if (typeof(Transform).IsAssignableFrom(binding.type) && binding.propertyName == AnimatorBindingCache.TRPlaceHolder) + { + if (string.IsNullOrEmpty(binding.path)) + rootMotion = true; + else + { + var transform = animatorRoot.transform.Find(binding.path); + if (transform != null) + { + var pos = transform.localPosition; + var rot = transform.localRotation; + animClip.SetCurve(binding.path, typeof(Transform), k_PosX, SetZeroKey(curve, keyFrames, pos.x)); + animClip.SetCurve(binding.path, typeof(Transform), k_PosY, SetZeroKey(curve, keyFrames, pos.y)); + animClip.SetCurve(binding.path, typeof(Transform), k_PosZ, SetZeroKey(curve, keyFrames, pos.z)); + animClip.SetCurve(binding.path, typeof(Transform), k_RotX, SetZeroKey(curve, keyFrames, rot.x)); + animClip.SetCurve(binding.path, typeof(Transform), k_RotY, SetZeroKey(curve, keyFrames, rot.y)); + animClip.SetCurve(binding.path, typeof(Transform), k_RotZ, SetZeroKey(curve, keyFrames, rot.z)); + animClip.SetCurve(binding.path, typeof(Transform), k_RotW, SetZeroKey(curve, keyFrames, rot.w)); + } + } + + continue; + } + + if (typeof(Transform).IsAssignableFrom(binding.type) && binding.propertyName == AnimatorBindingCache.ScalePlaceholder) + { + var transform = animatorRoot.transform.Find(binding.path); + if (transform != null) + { + var scale = transform.localScale; + animClip.SetCurve(binding.path, typeof(Transform), k_ScaleX, SetZeroKey(curve, keyFrames, scale.x)); + animClip.SetCurve(binding.path, typeof(Transform), k_ScaleY, SetZeroKey(curve, keyFrames, scale.y)); + animClip.SetCurve(binding.path, typeof(Transform), k_ScaleZ, SetZeroKey(curve, keyFrames, scale.z)); + } + + continue; + } + + // Not setting curves through AnimationUtility.SetEditorCurve to avoid reentrant + // onCurveWasModified calls in timeline. This means we don't get sprite curves + // in the default clip right now. + if (IsAvatarBinding(binding) || IsEulerHint(binding) || binding.isPPtrCurve) + continue; + + float floatValue; + AnimationUtility.GetFloatValue(avatarRoot, binding, out floatValue); + animClip.SetCurve(binding.path, binding.type, binding.propertyName, SetZeroKey(curve, keyFrames, floatValue)); + } + + // add root motion explicitly. + if (rootMotion) + { + var pos = Vector3.zero; // the appropriate root motion offsets are applied by timeline + var rot = Quaternion.identity; + animClip.SetCurve(string.Empty, typeof(Transform), k_PosX, SetZeroKey(curve, keyFrames, pos.x)); + animClip.SetCurve(string.Empty, typeof(Transform), k_PosY, SetZeroKey(curve, keyFrames, pos.y)); + animClip.SetCurve(string.Empty, typeof(Transform), k_PosZ, SetZeroKey(curve, keyFrames, pos.z)); + animClip.SetCurve(string.Empty, typeof(Transform), k_RotX, SetZeroKey(curve, keyFrames, rot.x)); + animClip.SetCurve(string.Empty, typeof(Transform), k_RotY, SetZeroKey(curve, keyFrames, rot.y)); + animClip.SetCurve(string.Empty, typeof(Transform), k_RotZ, SetZeroKey(curve, keyFrames, rot.z)); + animClip.SetCurve(string.Empty, typeof(Transform), k_RotW, SetZeroKey(curve, keyFrames, rot.w)); + } + + return animClip; + } + + public static bool IsRootMotion(EditorCurveBinding binding) + { + // Root Transform TR. + if (typeof(Transform).IsAssignableFrom(binding.type) && string.IsNullOrEmpty(binding.path)) + { + return binding.propertyName.StartsWith(k_Pos) || binding.propertyName.StartsWith(k_Rot); + } + + // MotionCurves/RootCurves. + if (binding.type == typeof(Animator)) + { + return binding.propertyName.StartsWith(k_MotionT) || binding.propertyName.StartsWith(k_MotionQ) || + binding.propertyName.StartsWith(k_RootT) || binding.propertyName.StartsWith(k_RootQ); + } + + return false; + } + + private static bool NeedsSkeletonBindings(IEnumerable<EditorCurveBinding> bindings) + { + foreach (var b in bindings) + { + if (IsSkeletalBinding(b)) + return true; + } + + return false; + } + + private static void AddBindings(IEnumerable<EditorCurveBinding> bindings) + { + foreach (var b in bindings) + { + if (!s_CurveSet.ContainsKey(b)) + s_CurveSet[b] = 1; + } + } + + private static void AddTRBinding(GameObject root, EditorCurveBinding binding) + { + // This is faster than AnimationMode.AddTransformTR + binding.propertyName = k_PosX; AnimationMode.AddEditorCurveBinding(root, binding); + binding.propertyName = k_PosY; AnimationMode.AddEditorCurveBinding(root, binding); + binding.propertyName = k_PosZ; AnimationMode.AddEditorCurveBinding(root, binding); + binding.propertyName = k_RotX; AnimationMode.AddEditorCurveBinding(root, binding); + binding.propertyName = k_RotY; AnimationMode.AddEditorCurveBinding(root, binding); + binding.propertyName = k_RotZ; AnimationMode.AddEditorCurveBinding(root, binding); + binding.propertyName = k_RotW; AnimationMode.AddEditorCurveBinding(root, binding); + } + + private static void AddScaleBinding(GameObject root, EditorCurveBinding binding) + { + // AnimationMode.AddTransformTRS is slow + binding.propertyName = k_ScaleX; AnimationMode.AddEditorCurveBinding(root, binding); + binding.propertyName = k_ScaleY; AnimationMode.AddEditorCurveBinding(root, binding); + binding.propertyName = k_ScaleZ; AnimationMode.AddEditorCurveBinding(root, binding); + } + + private static bool IsEuler(EditorCurveBinding binding) + { + return typeof(Transform).IsAssignableFrom(binding.type) && binding.propertyName.StartsWith(k_EulerAnglesRaw); + } + + private static bool IsAvatarBinding(EditorCurveBinding binding) + { + return typeof(Animator).IsAssignableFrom(binding.type) && string.IsNullOrEmpty(binding.path); + } + + private static bool IsSkeletalBinding(EditorCurveBinding binding) + { + // skin mesh incorporates blend shapes + return typeof(Transform).IsAssignableFrom(binding.type) || typeof(SkinnedMeshRenderer).IsAssignableFrom(binding.type); + } + + private static AnimationCurve SetZeroKey(AnimationCurve curve, Keyframe[] keys, float val) + { + keys[0].value = val; + curve.keys = keys; + return curve; + } + + private static bool IsEulerHint(EditorCurveBinding binding) + { + return typeof(Transform).IsAssignableFrom(binding.type) && binding.propertyName.StartsWith(k_EulerHint); + } + + private static GameObject GetAvatarRoot(GameObject animatorRoot) + { + var animator = animatorRoot.GetComponent<Animator>(); + if (animator != null && animator.avatarRoot != animatorRoot.transform) + return animator.avatarRoot.gameObject; + return animatorRoot; + } + } +} +#endif |
