123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709 |
- using System.Collections.Generic;
- using System.Linq;
- using UnityEditorInternal;
- using UnityEngine;
- using UnityEngine.Timeline;
- using System.Globalization;
- namespace UnityEditor.Timeline
- {
- // Methods and data for handling recording to monobehaviours
- static partial class TimelineRecording
- {
- internal class RecordingState : IAnimationRecordingState
- {
- public GameObject activeGameObject { get; set; }
- public GameObject activeRootGameObject { get; set; }
- public AnimationClip activeAnimationClip { get; set; }
- public void SaveCurve(AnimationWindowCurve curve)
- {
- Undo.RegisterCompleteObjectUndo(activeAnimationClip, "Edit Curve");
- AnimationWindowUtility.SaveCurve(activeAnimationClip, curve);
- }
- public void AddPropertyModification(EditorCurveBinding binding, PropertyModification propertyModification, bool keepPrefabOverride)
- {
- AnimationMode.AddPropertyModification(binding, propertyModification, keepPrefabOverride);
- }
- public bool addZeroFrame
- {
- get { return false; }
- }
- public int currentFrame { get; set; }
- public bool DiscardModification(PropertyModification modification)
- {
- return false;
- }
- }
- static readonly RecordingState s_RecordState = new RecordingState();
- static readonly AnimationTrackRecorder s_TrackRecorder = new AnimationTrackRecorder();
- static readonly List<UndoPropertyModification> s_UnprocessedMods = new List<UndoPropertyModification>();
- static readonly List<UndoPropertyModification> s_ModsToProcess = new List<UndoPropertyModification>();
- static AnimationTrack s_LastTrackWarning;
- public const string kLocalPosition = "m_LocalPosition";
- public const string kLocalRotation = "m_LocalRotation";
- public const string kLocalEulerHint = "m_LocalEulerAnglesHint";
- const string kRotationWarning = "You are recording with an initial rotation offset. This may result in a misrepresentation of euler angles. When recording transform properties, it is recommended to reset rotation prior to recording";
- public static bool IsRecordingAnimationTrack { get; private set; }
- internal static UndoPropertyModification[] ProcessMonoBehaviourModification(UndoPropertyModification[] modifications, WindowState state)
- {
- if (state == null || state.editSequence.director == null)
- return modifications;
- s_UnprocessedMods.Clear();
- s_TrackRecorder.PrepareForRecord(state);
- s_ModsToProcess.Clear();
- s_ModsToProcess.AddRange(modifications.Reverse());
- while (s_ModsToProcess.Count > 0)
- {
- var modification = s_ModsToProcess[s_ModsToProcess.Count - 1];
- s_ModsToProcess.RemoveAt(s_ModsToProcess.Count - 1);
- // grab the clip we need to apply to
- var modifiedGO = GetGameObjectFromModification(modification);
- var track = GetTrackForGameObject(modifiedGO, state);
- if (track != null)
- {
- IsRecordingAnimationTrack = true;
- double startTime = 0;
- var clip = s_TrackRecorder.PrepareTrack(track, state, modifiedGO, out startTime);
- if (clip == null)
- {
- s_ModsToProcess.Reverse();
- return s_ModsToProcess.ToArray();
- }
- s_RecordState.activeAnimationClip = clip;
- s_RecordState.activeRootGameObject = state.GetSceneReference(track);
- s_RecordState.activeGameObject = modifiedGO;
- s_RecordState.currentFrame = Mathf.RoundToInt((float)startTime);
- EditorUtility.SetDirty(clip);
- var toProcess = GatherRelatedModifications(modification, s_ModsToProcess);
- var animator = s_RecordState.activeRootGameObject.GetComponent<Animator>();
- var animTrack = track as AnimationTrack;
- // update preview mode before recording so the correct values get placed (in case we modify offsets)
- // Case 900624
- UpdatePreviewMode(toProcess, modifiedGO);
- // if this is the first position/rotation recording, copy the current position / rotation to the track offset
- AddTrackOffset(animTrack, toProcess, clip, animator);
- // same for clip mod clips being created
- AddClipOffset(animTrack, toProcess, s_TrackRecorder.recordClip, animator);
- // Check if we need to handle position/rotation offsets
- var handleOffsets = animator != null && modification.currentValue != null &&
- modification.currentValue.target == s_RecordState.activeRootGameObject.transform &&
- HasOffsets(animTrack, s_TrackRecorder.recordClip);
- if (handleOffsets)
- {
- toProcess = HandleEulerModifications(animTrack, s_TrackRecorder.recordClip, clip, s_RecordState.currentFrame * clip.frameRate, toProcess);
- RemoveOffsets(modification, animTrack, s_TrackRecorder.recordClip, toProcess);
- }
- var remaining = AnimationRecording.Process(s_RecordState, toProcess);
- if (remaining != null && remaining.Length != 0)
- {
- s_UnprocessedMods.AddRange(remaining);
- }
- if (handleOffsets)
- {
- ReapplyOffsets(modification, animTrack, s_TrackRecorder.recordClip, toProcess);
- }
- s_TrackRecorder.FinializeTrack(track, state);
- IsRecordingAnimationTrack = false;
- }
- else
- {
- s_UnprocessedMods.Add(modification);
- }
- }
- s_TrackRecorder.FinalizeRecording(state);
- return s_UnprocessedMods.ToArray();
- }
- internal static bool IsPosition(UndoPropertyModification modification)
- {
- if (modification.currentValue != null)
- return modification.currentValue.propertyPath.StartsWith(kLocalPosition);
- else if (modification.previousValue != null)
- return modification.previousValue.propertyPath.StartsWith(kLocalPosition);
- return false;
- }
- internal static bool IsRotation(UndoPropertyModification modification)
- {
- if (modification.currentValue != null)
- return modification.currentValue.propertyPath.StartsWith(kLocalRotation) ||
- modification.currentValue.propertyPath.StartsWith(kLocalEulerHint);
- if (modification.previousValue != null)
- return modification.previousValue.propertyPath.StartsWith(kLocalRotation) ||
- modification.previousValue.propertyPath.StartsWith(kLocalEulerHint);
- return false;
- }
- // Test if this modification position or rotation
- internal static bool IsPositionOrRotation(UndoPropertyModification modification)
- {
- return IsPosition(modification) || IsRotation(modification);
- }
- internal static void UpdatePreviewMode(UndoPropertyModification[] mods, GameObject go)
- {
- if (mods.Any(x => IsPositionOrRotation(x) && IsRootModification(x)))
- {
- bool hasPosition = false;
- bool hasRotation = false;
- foreach (var mod in mods)
- {
- EditorCurveBinding binding = new EditorCurveBinding();
- if (AnimationUtility.PropertyModificationToEditorCurveBinding(mod.previousValue, go, out binding) != null)
- {
- hasPosition |= IsPosition(mod);
- hasRotation |= IsRotation(mod);
- AnimationMode.AddPropertyModification(binding, mod.previousValue, true);
- }
- }
- // case 931859 - if we are only changing one field, all fields must be registered before
- // any recording modifications
- var driver = WindowState.previewDriver;
- if (driver != null && AnimationMode.InAnimationMode(driver))
- {
- if (hasPosition)
- {
- DrivenPropertyManager.RegisterProperty(driver, go.transform, kLocalPosition + ".x");
- DrivenPropertyManager.RegisterProperty(driver, go.transform, kLocalPosition + ".y");
- DrivenPropertyManager.RegisterProperty(driver, go.transform, kLocalPosition + ".z");
- }
- else if (hasRotation)
- {
- DrivenPropertyManager.RegisterProperty(driver, go.transform, kLocalRotation + ".x");
- DrivenPropertyManager.RegisterProperty(driver, go.transform, kLocalRotation + ".y");
- DrivenPropertyManager.RegisterProperty(driver, go.transform, kLocalRotation + ".z");
- DrivenPropertyManager.RegisterProperty(driver, go.transform, kLocalRotation + ".w");
- }
- }
- }
- }
- internal static bool IsRootModification(UndoPropertyModification modification)
- {
- string path = string.Empty;
- if (modification.currentValue != null)
- path = modification.currentValue.propertyPath;
- else if (modification.previousValue != null)
- path = modification.previousValue.propertyPath;
- return !path.Contains('/') && !path.Contains('\\');
- }
- // test if the clip has any position or rotation bindings
- internal static bool ClipHasPositionOrRotation(AnimationClip clip)
- {
- if (clip == null || clip.empty)
- return false;
- var info = AnimationClipCurveCache.Instance.GetCurveInfo(clip);
- for (var i = 0; i < info.bindings.Length; i++)
- {
- bool isPositionOrRotation =
- info.bindings[i].type != null &&
- typeof(Transform).IsAssignableFrom(info.bindings[i].type) &&
- (
- info.bindings[i].propertyName.StartsWith(kLocalPosition) ||
- info.bindings[i].propertyName.StartsWith(kLocalRotation) ||
- info.bindings[i].propertyName.StartsWith("localEuler")
- );
- if (isPositionOrRotation)
- return true;
- }
- return false;
- }
- internal static TimelineAnimationUtilities.RigidTransform ComputeInitialClipOffsets(AnimationTrack track, UndoPropertyModification[] mods, Animator animator)
- {
- // take into account the track transform
- var target = GetInitialTransform(mods, animator);
- var trackToClip = TimelineAnimationUtilities.RigidTransform.identity;
- if (track.trackOffset == TrackOffset.ApplyTransformOffsets)
- trackToClip = TimelineAnimationUtilities.RigidTransform.Compose(track.position, track.rotation);
- else if (track.trackOffset == TrackOffset.ApplySceneOffsets)
- trackToClip = TimelineAnimationUtilities.RigidTransform.Compose(track.sceneOffsetPosition, Quaternion.Euler(track.sceneOffsetRotation));
- target = TimelineAnimationUtilities.RigidTransform.Mul(TimelineAnimationUtilities.RigidTransform.Inverse(trackToClip), target);
- // set the previous position in case the animation system adds a default key
- SetPreviousPositionAndRotation(mods, animator, trackToClip.position, trackToClip.rotation);
- return target;
- }
- internal static TimelineAnimationUtilities.RigidTransform GetInitialTransform(UndoPropertyModification[] mods, Animator animator)
- {
- var pos = Vector3.zero;
- var rot = Quaternion.identity;
- // if we are operating on the root, grab the transform from the undo
- if (mods[0].previousValue.target == animator.transform)
- {
- GetPreviousPositionAndRotation(mods, ref pos, ref rot);
- }
- // otherwise we need to grab it from the root object, which is the one with the actual animator
- else
- {
- pos = animator.transform.localPosition;
- rot = animator.transform.localRotation;
- }
- // take into account the track transform
- return TimelineAnimationUtilities.RigidTransform.Compose(pos, rot);
- }
- internal static void SetPreviousPositionAndRotation(UndoPropertyModification[] mods, Animator animator, Vector3 pos, Quaternion rot)
- {
- if (mods[0].previousValue.target == animator.transform)
- {
- SetPreviousPositionAndRotation(mods, pos, rot);
- }
- }
- // If we are adding to an infinite clip, strip the objects position and rotation and set it as the clip offset
- internal static void AddTrackOffset(AnimationTrack track, UndoPropertyModification[] mods, AnimationClip clip, Animator animator)
- {
- var copyTrackOffset = !track.inClipMode &&
- !ClipHasPositionOrRotation(clip) &&
- mods.Any(x => IsPositionOrRotation(x) && IsRootModification(x)) &&
- animator != null;
- if (copyTrackOffset)
- {
- // in scene offset mode, makes sure we have the correct initial transform set
- if (track.trackOffset == TrackOffset.ApplySceneOffsets)
- {
- var rigidTransform = GetInitialTransform(mods, animator);
- track.sceneOffsetPosition = rigidTransform.position;
- track.sceneOffsetRotation = rigidTransform.rotation.eulerAngles;
- SetPreviousPositionAndRotation(mods, animator, rigidTransform.position, rigidTransform.rotation);
- }
- else
- {
- var rigidTransform = ComputeInitialClipOffsets(track, mods, animator);
- track.infiniteClipOffsetPosition = rigidTransform.position;
- track.infiniteClipOffsetEulerAngles = rigidTransform.rotation.eulerAngles;
- }
- }
- }
- internal static void AddClipOffset(AnimationTrack track, UndoPropertyModification[] mods, TimelineClip clip, Animator animator)
- {
- if (clip == null || clip.asset == null)
- return;
- var clipAsset = clip.asset as AnimationPlayableAsset;
- var copyClipOffset = track.inClipMode &&
- clipAsset != null && !ClipHasPositionOrRotation(clipAsset.clip) &&
- mods.Any(x => IsPositionOrRotation(x) && IsRootModification(x)) &&
- animator != null;
- if (copyClipOffset)
- {
- var rigidTransform = ComputeInitialClipOffsets(track, mods, animator);
- clipAsset.position = rigidTransform.position;
- clipAsset.rotation = rigidTransform.rotation;
- }
- }
- internal static TimelineAnimationUtilities.RigidTransform GetLocalToTrack(AnimationTrack track, TimelineClip clip)
- {
- if (track == null)
- return TimelineAnimationUtilities.RigidTransform.Compose(Vector3.zero, Quaternion.identity);
- var trackPos = track.position;
- var trackRot = track.rotation;
- if (track.trackOffset == TrackOffset.ApplySceneOffsets)
- {
- trackPos = track.sceneOffsetPosition;
- trackRot = Quaternion.Euler(track.sceneOffsetRotation);
- }
- var clipWrapper = clip == null ? null : clip.asset as AnimationPlayableAsset;
- var clipTransform = TimelineAnimationUtilities.RigidTransform.Compose(Vector3.zero, Quaternion.identity);
- if (clipWrapper != null)
- {
- clipTransform = TimelineAnimationUtilities.RigidTransform.Compose(clipWrapper.position, clipWrapper.rotation);
- }
- else
- {
- clipTransform = TimelineAnimationUtilities.RigidTransform.Compose(track.infiniteClipOffsetPosition, track.infiniteClipOffsetRotation);
- }
- var trackTransform = TimelineAnimationUtilities.RigidTransform.Compose(trackPos, trackRot);
- return TimelineAnimationUtilities.RigidTransform.Mul(trackTransform, clipTransform);
- }
- // Checks whether there are any offsets applied to a clip
- internal static bool HasOffsets(AnimationTrack track, TimelineClip clip)
- {
- if (track == null)
- return false;
- bool hasClipOffsets = false;
- bool hasTrackOffsets = false;
- var clipWrapper = clip == null ? null : clip.asset as AnimationPlayableAsset;
- if (clipWrapper != null)
- hasClipOffsets |= clipWrapper.position != Vector3.zero || clipWrapper.rotation != Quaternion.identity;
- if (track.trackOffset == TrackOffset.ApplySceneOffsets)
- {
- hasTrackOffsets = track.sceneOffsetPosition != Vector3.zero || track.sceneOffsetRotation != Vector3.zero;
- }
- else
- {
- hasTrackOffsets = (track.position != Vector3.zero || track.rotation != Quaternion.identity);
- if (!track.inClipMode)
- hasClipOffsets |= track.infiniteClipOffsetPosition != Vector3.zero || track.infiniteClipOffsetRotation != Quaternion.identity;
- }
- return hasTrackOffsets || hasClipOffsets;
- }
- internal static void RemoveOffsets(UndoPropertyModification modification, AnimationTrack track, TimelineClip clip, UndoPropertyModification[] mods)
- {
- if (IsPositionOrRotation(modification))
- {
- var modifiedGO = GetGameObjectFromModification(modification);
- var target = TimelineAnimationUtilities.RigidTransform.Compose(modifiedGO.transform.localPosition, modifiedGO.transform.localRotation);
- var localToTrack = GetLocalToTrack(track, clip);
- var trackToLocal = TimelineAnimationUtilities.RigidTransform.Inverse(localToTrack);
- var localSpace = TimelineAnimationUtilities.RigidTransform.Mul(trackToLocal, target);
- // Update the undo call values
- var prevPos = modifiedGO.transform.localPosition;
- var prevRot = modifiedGO.transform.localRotation;
- GetPreviousPositionAndRotation(mods, ref prevPos, ref prevRot);
- var previousRigidTransform = TimelineAnimationUtilities.RigidTransform.Mul(trackToLocal, TimelineAnimationUtilities.RigidTransform.Compose(prevPos, prevRot));
- SetPreviousPositionAndRotation(mods, previousRigidTransform.position, previousRigidTransform.rotation);
- var currentPos = modifiedGO.transform.localPosition;
- var currentRot = modifiedGO.transform.localRotation;
- GetCurrentPositionAndRotation(mods, ref currentPos, ref currentRot);
- var currentRigidTransform = TimelineAnimationUtilities.RigidTransform.Mul(trackToLocal, TimelineAnimationUtilities.RigidTransform.Compose(currentPos, currentRot));
- SetCurrentPositionAndRotation(mods, currentRigidTransform.position, currentRigidTransform.rotation);
- modifiedGO.transform.localPosition = localSpace.position;
- modifiedGO.transform.localRotation = localSpace.rotation;
- }
- }
- internal static void ReapplyOffsets(UndoPropertyModification modification, AnimationTrack track, TimelineClip clip, UndoPropertyModification[] mods)
- {
- if (IsPositionOrRotation(modification))
- {
- var modifiedGO = GetGameObjectFromModification(modification);
- var target = TimelineAnimationUtilities.RigidTransform.Compose(modifiedGO.transform.localPosition, modifiedGO.transform.localRotation);
- var localToTrack = GetLocalToTrack(track, clip);
- var trackSpace = TimelineAnimationUtilities.RigidTransform.Mul(localToTrack, target);
- // Update the undo call values
- var prevPos = modifiedGO.transform.localPosition;
- var prevRot = modifiedGO.transform.localRotation;
- GetPreviousPositionAndRotation(mods, ref prevPos, ref prevRot);
- var previousRigidTransform = TimelineAnimationUtilities.RigidTransform.Mul(localToTrack, TimelineAnimationUtilities.RigidTransform.Compose(prevPos, prevRot));
- SetPreviousPositionAndRotation(mods, previousRigidTransform.position, previousRigidTransform.rotation);
- var currentPos = modifiedGO.transform.localPosition;
- var currentRot = modifiedGO.transform.localRotation;
- GetCurrentPositionAndRotation(mods, ref currentPos, ref currentRot);
- var currentRigidTransform = TimelineAnimationUtilities.RigidTransform.Mul(localToTrack, TimelineAnimationUtilities.RigidTransform.Compose(currentPos, currentRot));
- SetCurrentPositionAndRotation(mods, currentRigidTransform.position, currentRigidTransform.rotation);
- modifiedGO.transform.localPosition = trackSpace.position;
- modifiedGO.transform.localRotation = trackSpace.rotation;
- }
- }
- // This will gather the modifications that modify the same property on the same object (rgba of a color, xyzw of a vector)
- // Note: This will modify the list, removing any elements that match
- static UndoPropertyModification[] GatherRelatedModifications(UndoPropertyModification toMatch, List<UndoPropertyModification> list)
- {
- var matching = new List<UndoPropertyModification> {toMatch};
- for (var i = list.Count - 1; i >= 0; i--)
- {
- var undo = list[i];
- if (undo.previousValue.target == toMatch.previousValue.target &&
- DoesPropertyPathMatch(undo.previousValue.propertyPath, toMatch.previousValue.propertyPath))
- {
- matching.Add(undo);
- list.RemoveAt(i);
- }
- }
- return matching.ToArray();
- }
- // Grab the game object out of the modification object
- static GameObject GetGameObjectFromModification(UndoPropertyModification mod)
- {
- // grab the GO this is modifying
- GameObject modifiedGO = null;
- if (mod.previousValue.target is GameObject)
- modifiedGO = mod.previousValue.target as GameObject;
- else if (mod.previousValue.target is Component)
- modifiedGO = (mod.previousValue.target as Component).gameObject;
- return modifiedGO;
- }
- // returns the level of the child in the hierarchy relative to the parent,
- // or -1 if the child is not the parent or a descendent of it
- static int GetChildLevel(GameObject parent, GameObject child)
- {
- var level = 0;
- while (child != null)
- {
- if (parent == child)
- break;
- if (child.transform.parent == null)
- return -1;
- child = child.transform.parent.gameObject;
- level++;
- }
- if (child != null)
- return level;
- return -1;
- }
- static bool DoesPropertyPathMatch(string a, string b)
- {
- return AnimationWindowUtility.GetPropertyGroupName(a).Equals(AnimationWindowUtility.GetPropertyGroupName(a));
- }
- internal static void GetPreviousPositionAndRotation(UndoPropertyModification[] mods, ref Vector3 position, ref Quaternion rotation)
- {
- var t = mods[0].previousValue.target as Transform;
- if (t == null)
- t = (Transform)mods[0].currentValue.target;
- position = t.localPosition;
- rotation = t.localRotation;
- foreach (var mod in mods)
- {
- switch (mod.previousValue.propertyPath)
- {
- case kLocalPosition + ".x":
- position.x = ParseFloat(mod.previousValue.value, position.x);
- break;
- case kLocalPosition + ".y":
- position.y = ParseFloat(mod.previousValue.value, position.y);
- break;
- case kLocalPosition + ".z":
- position.z = ParseFloat(mod.previousValue.value, position.z);
- break;
- case kLocalRotation + ".x":
- rotation.x = ParseFloat(mod.previousValue.value, rotation.x);
- break;
- case kLocalRotation + ".y":
- rotation.y = ParseFloat(mod.previousValue.value, rotation.y);
- break;
- case kLocalRotation + ".z":
- rotation.z = ParseFloat(mod.previousValue.value, rotation.z);
- break;
- case kLocalRotation + ".w":
- rotation.w = ParseFloat(mod.previousValue.value, rotation.w);
- break;
- }
- }
- }
- internal static void GetCurrentPositionAndRotation(UndoPropertyModification[] mods, ref Vector3 position, ref Quaternion rotation)
- {
- var t = (Transform)mods[0].currentValue.target;
- position = t.localPosition;
- rotation = t.localRotation;
- foreach (var mod in mods)
- {
- switch (mod.currentValue.propertyPath)
- {
- case kLocalPosition + ".x":
- position.x = ParseFloat(mod.currentValue.value, position.x);
- break;
- case kLocalPosition + ".y":
- position.y = ParseFloat(mod.currentValue.value, position.y);
- break;
- case kLocalPosition + ".z":
- position.z = ParseFloat(mod.currentValue.value, position.z);
- break;
- case kLocalRotation + ".x":
- rotation.x = ParseFloat(mod.currentValue.value, rotation.x);
- break;
- case kLocalRotation + ".y":
- rotation.y = ParseFloat(mod.currentValue.value, rotation.y);
- break;
- case kLocalRotation + ".z":
- rotation.z = ParseFloat(mod.currentValue.value, rotation.z);
- break;
- case kLocalRotation + ".w":
- rotation.w = ParseFloat(mod.currentValue.value, rotation.w);
- break;
- }
- }
- }
- // when making the previous position and rotation
- internal static void SetPreviousPositionAndRotation(UndoPropertyModification[] mods, Vector3 pos, Quaternion rot)
- {
- foreach (var mod in mods)
- {
- switch (mod.previousValue.propertyPath)
- {
- case kLocalPosition + ".x":
- mod.previousValue.value = pos.x.ToString(EditorGUI.kFloatFieldFormatString);
- break;
- case kLocalPosition + ".y":
- mod.previousValue.value = pos.y.ToString(EditorGUI.kFloatFieldFormatString);
- break;
- case kLocalPosition + ".z":
- mod.previousValue.value = pos.z.ToString(EditorGUI.kFloatFieldFormatString);
- break;
- case kLocalRotation + ".x":
- mod.previousValue.value = rot.x.ToString(EditorGUI.kFloatFieldFormatString);
- break;
- case kLocalRotation + ".y":
- mod.previousValue.value = rot.y.ToString(EditorGUI.kFloatFieldFormatString);
- break;
- case kLocalRotation + ".z":
- mod.previousValue.value = rot.z.ToString(EditorGUI.kFloatFieldFormatString);
- break;
- case kLocalRotation + ".w":
- mod.previousValue.value = rot.w.ToString(EditorGUI.kFloatFieldFormatString);
- break;
- }
- }
- }
- internal static void SetCurrentPositionAndRotation(UndoPropertyModification[] mods, Vector3 pos, Quaternion rot)
- {
- foreach (var mod in mods)
- {
- switch (mod.previousValue.propertyPath)
- {
- case kLocalPosition + ".x":
- mod.currentValue.value = pos.x.ToString(EditorGUI.kFloatFieldFormatString);
- break;
- case kLocalPosition + ".y":
- mod.currentValue.value = pos.y.ToString(EditorGUI.kFloatFieldFormatString);
- break;
- case kLocalPosition + ".z":
- mod.currentValue.value = pos.z.ToString(EditorGUI.kFloatFieldFormatString);
- break;
- case kLocalRotation + ".x":
- mod.currentValue.value = rot.x.ToString(EditorGUI.kFloatFieldFormatString);
- break;
- case kLocalRotation + ".y":
- mod.currentValue.value = rot.y.ToString(EditorGUI.kFloatFieldFormatString);
- break;
- case kLocalRotation + ".z":
- mod.currentValue.value = rot.z.ToString(EditorGUI.kFloatFieldFormatString);
- break;
- case kLocalRotation + ".w":
- mod.currentValue.value = rot.w.ToString(EditorGUI.kFloatFieldFormatString);
- break;
- }
- }
- }
- internal static float ParseFloat(string str, float defaultVal)
- {
- float temp = 0.0f;
- if (float.TryParse(str, NumberStyles.Float, CultureInfo.InvariantCulture.NumberFormat, out temp))
- return temp;
- return defaultVal;
- }
- internal static UndoPropertyModification[] HandleEulerModifications(AnimationTrack track, TimelineClip clip, AnimationClip animClip, float time, UndoPropertyModification[] mods)
- {
- if (mods.Any(x => x.currentValue.propertyPath.StartsWith(kLocalEulerHint) || x.currentValue.propertyPath.StartsWith(kLocalRotation)))
- {
- // if there is a rotational offsets, we need to strip the euler hints, since they are used by the animation recording system
- // over the quaternion.
- var localToTrack = GetLocalToTrack(track, clip);
- if (localToTrack.rotation != Quaternion.identity)
- {
- if (s_LastTrackWarning != track)
- {
- s_LastTrackWarning = track;
- Debug.LogWarning(kRotationWarning);
- }
- Transform transform = mods[0].currentValue.target as Transform;
- if (transform != null)
- {
- var trackToLocal = TimelineAnimationUtilities.RigidTransform.Inverse(localToTrack);
- // since the euler angles are going to be transformed, we do a best guess at a euler that gives the shortest path
- var quatMods = mods.Where(x => !x.currentValue.propertyPath.StartsWith(kLocalEulerHint));
- var eulerMods = FindBestEulerHint(trackToLocal.rotation * transform.localRotation, animClip, time, transform);
- return quatMods.Union(eulerMods).ToArray();
- }
- return mods.Where(x => !x.currentValue.propertyPath.StartsWith(kLocalEulerHint)).ToArray();
- }
- }
- return mods;
- }
- internal static IEnumerable<UndoPropertyModification> FindBestEulerHint(Quaternion rotation, AnimationClip clip, float time, Transform transform)
- {
- Vector3 euler = rotation.eulerAngles;
- var xCurve = AnimationUtility.GetEditorCurve(clip, EditorCurveBinding.FloatCurve(string.Empty, typeof(Transform), "localEulerAnglesRaw.x"));
- var yCurve = AnimationUtility.GetEditorCurve(clip, EditorCurveBinding.FloatCurve(string.Empty, typeof(Transform), "localEulerAnglesRaw.y"));
- var zCurve = AnimationUtility.GetEditorCurve(clip, EditorCurveBinding.FloatCurve(string.Empty, typeof(Transform), "localEulerAnglesRaw.z"));
- if (xCurve != null)
- euler.x = xCurve.Evaluate(time);
- if (yCurve != null)
- euler.y = yCurve.Evaluate(time);
- if (zCurve != null)
- euler.z = zCurve.Evaluate(time);
- euler = QuaternionCurveTangentCalculation.GetEulerFromQuaternion(rotation, euler);
- return new[]
- {
- PropertyModificationToUndoPropertyModification(new PropertyModification {target = transform, propertyPath = kLocalEulerHint + ".x", value = euler.x.ToString() }),
- PropertyModificationToUndoPropertyModification(new PropertyModification {target = transform, propertyPath = kLocalEulerHint + ".y", value = euler.y.ToString() }),
- PropertyModificationToUndoPropertyModification(new PropertyModification {target = transform, propertyPath = kLocalEulerHint + ".z", value = euler.z.ToString() })
- };
- }
- }
- }
|