Maze / Library /PackageCache /com.unity.timeline@1.6.5 /Editor /inspectors /AnimationPlayableAssetInspector.cs
| using System; | |
| using System.Linq; | |
| using UnityEngine; | |
| using UnityEngine.Timeline; | |
| namespace UnityEditor.Timeline | |
| { | |
| [] | |
| class AnimationPlayableAssetInspector : Editor | |
| { | |
| static class Styles | |
| { | |
| public static readonly GUIContent RotationText = L10n.TextContent("Rotation"); | |
| public static readonly GUIContent AnimClipText = L10n.TextContent("Animation Clip"); | |
| public static readonly GUIContent TransformOffsetTitle = L10n.TextContent("Clip Transform Offsets", "Use this to offset the root transform position and rotation relative to the track when playing this clip"); | |
| public static readonly GUIContent AnimationClipName = L10n.TextContent("Animation Clip Name"); | |
| public static readonly GUIContent MatchTargetFieldsTitle = L10n.TextContent("Offsets Match Fields", "Fields to apply when matching offsets on clips. The defaults can be set on the track."); | |
| public static readonly GUIContent UseDefaults = L10n.TextContent("Use defaults"); | |
| public static readonly GUIContent RemoveStartOffset = L10n.TextContent("Remove Start Offset", "Makes playback of the clip play relative to first key of the root transform"); | |
| public static readonly GUIContent ApplyFootIK = L10n.TextContent("Foot IK", "Enable to apply foot IK to the AnimationClip when the target is humanoid."); | |
| public static readonly GUIContent Loop = L10n.TextContent("Loop", "Whether the source Animation Clip loops during playback."); | |
| } | |
| TimelineWindow m_TimelineWindow; | |
| GameObject m_Binding; | |
| TimelineAnimationUtilities.OffsetEditMode m_OffsetEditMode = TimelineAnimationUtilities.OffsetEditMode.None; | |
| EditorClip m_EditorClip; | |
| EditorClip[] m_EditorClips; | |
| SerializedProperty m_PositionProperty; | |
| SerializedProperty m_RotationProperty; | |
| SerializedProperty m_AnimClipProperty; | |
| SerializedProperty m_UseTrackMatchFieldsProperty; | |
| SerializedProperty m_MatchTargetFieldsProperty; | |
| SerializedObject m_SerializedAnimClip; | |
| SerializedProperty m_SerializedAnimClipName; | |
| SerializedProperty m_RemoveStartOffsetProperty; | |
| SerializedProperty m_ApplyFootIK; | |
| SerializedProperty m_Loop; | |
| Vector3 m_LastPosition; | |
| Vector3 m_LastRotation; | |
| public override void OnInspectorGUI() | |
| { | |
| if (target == null) | |
| return; | |
| serializedObject.Update(); | |
| if (!m_TimelineWindow) m_TimelineWindow = TimelineWindow.instance; | |
| ShowAnimationClipField(); | |
| ShowRecordableClipRename(); | |
| ShowAnimationClipWarnings(); | |
| EditorGUI.BeginChangeCheck(); | |
| TransformOffsetsGUI(); | |
| // extra checks are because the context menu may need to cause a re-evaluate | |
| bool changed = EditorGUI.EndChangeCheck() || | |
| m_LastPosition != m_PositionProperty.vector3Value || | |
| m_LastRotation != m_RotationProperty.vector3Value; | |
| m_LastPosition = m_PositionProperty.vector3Value; | |
| m_LastRotation = m_RotationProperty.vector3Value; | |
| if (changed) | |
| { | |
| // updates the changed properties and pushes them to the active playable | |
| serializedObject.ApplyModifiedProperties(); | |
| ((AnimationPlayableAsset)target).LiveLink(); | |
| // force an evaluate to happen next frame | |
| if (TimelineWindow.instance != null && TimelineWindow.instance.state != null) | |
| { | |
| TimelineWindow.instance.state.Evaluate(); | |
| } | |
| } | |
| EditorGUI.BeginChangeCheck(); | |
| EditorGUILayout.PropertyField(m_ApplyFootIK, Styles.ApplyFootIK); | |
| EditorGUILayout.PropertyField(m_Loop, Styles.Loop); | |
| if (EditorGUI.EndChangeCheck()) | |
| TimelineEditor.Refresh(RefreshReason.ContentsModified); | |
| serializedObject.ApplyModifiedProperties(); | |
| } | |
| void ShowAnimationClipField() | |
| { | |
| bool disabled = m_EditorClips == null || m_EditorClips.Any(c => c.clip == null || c.clip.recordable); | |
| using (new EditorGUI.DisabledScope(disabled)) | |
| { | |
| EditorGUI.BeginChangeCheck(); | |
| EditorGUILayout.PropertyField(m_AnimClipProperty, Styles.AnimClipText); | |
| if (EditorGUI.EndChangeCheck()) | |
| { | |
| // rename the timeline clips to match the animation name if it did previously | |
| if (m_AnimClipProperty.objectReferenceValue != null && m_EditorClips != null) | |
| { | |
| var newName = m_AnimClipProperty.objectReferenceValue.name; | |
| foreach (var c in m_EditorClips) | |
| { | |
| if (c == null || c.clip == null || c.clip.asset == null) | |
| continue; | |
| var apa = c.clip.asset as AnimationPlayableAsset; | |
| if (apa != null && apa.clip != null && c.clip.displayName == apa.clip.name) | |
| { | |
| if (c.clip.GetParentTrack() != null) | |
| Undo.RegisterCompleteObjectUndo(c.clip.GetParentTrack(), L10n.Tr("Inspector")); | |
| c.clip.displayName = newName; | |
| } | |
| } | |
| } | |
| TimelineEditor.Refresh(RefreshReason.ContentsModified); | |
| } | |
| } | |
| } | |
| void TransformOffsetsMatchFieldsGUI() | |
| { | |
| var rect = EditorGUILayout.GetControlRect(true); | |
| EditorGUI.BeginProperty(rect, Styles.MatchTargetFieldsTitle, m_UseTrackMatchFieldsProperty); | |
| rect = EditorGUI.PrefixLabel(rect, Styles.MatchTargetFieldsTitle); | |
| int oldIndent = EditorGUI.indentLevel; | |
| EditorGUI.indentLevel = 0; | |
| EditorGUI.BeginChangeCheck(); | |
| bool val = m_UseTrackMatchFieldsProperty.boolValue; | |
| val = EditorGUI.ToggleLeft(rect, Styles.UseDefaults, val); | |
| if (EditorGUI.EndChangeCheck()) | |
| m_UseTrackMatchFieldsProperty.boolValue = val; | |
| EditorGUI.indentLevel = oldIndent; | |
| EditorGUI.EndProperty(); | |
| if (!val || m_UseTrackMatchFieldsProperty.hasMultipleDifferentValues) | |
| { | |
| EditorGUI.indentLevel++; | |
| AnimationTrackInspector.MatchTargetsFieldGUI(m_MatchTargetFieldsProperty); | |
| EditorGUI.indentLevel--; | |
| } | |
| } | |
| void TransformOffsetsGUI() | |
| { | |
| if (ShouldShowOffsets()) | |
| { | |
| EditorGUILayout.Space(); | |
| EditorGUILayout.LabelField(Styles.TransformOffsetTitle); | |
| EditorGUI.indentLevel++; | |
| using (new EditorGUI.DisabledScope(targets.Length > 1)) | |
| { | |
| var previousOffsetMode = m_OffsetEditMode; | |
| AnimationTrackInspector.ShowMotionOffsetEditModeToolbar(ref m_OffsetEditMode); | |
| if (previousOffsetMode != m_OffsetEditMode) | |
| { | |
| SetTimeToClip(); | |
| SceneView.RepaintAll(); | |
| } | |
| } | |
| EditorGUILayout.BeginHorizontal(); | |
| EditorGUILayout.PropertyField(m_PositionProperty); | |
| EditorGUILayout.EndHorizontal(); | |
| EditorGUILayout.BeginHorizontal(); | |
| EditorGUILayout.PropertyField(m_RotationProperty, Styles.RotationText); | |
| EditorGUILayout.EndHorizontal(); | |
| EditorGUILayout.Space(); | |
| EditorGUI.indentLevel--; | |
| TransformOffsetsMatchFieldsGUI(); | |
| EditorGUI.BeginChangeCheck(); | |
| EditorGUILayout.PropertyField(m_RemoveStartOffsetProperty, Styles.RemoveStartOffset); | |
| if (EditorGUI.EndChangeCheck()) | |
| { | |
| TimelineEditor.Refresh(RefreshReason.ContentsAddedOrRemoved); | |
| Repaint(); | |
| } | |
| } | |
| } | |
| void Reevaluate() | |
| { | |
| if (m_TimelineWindow != null && m_TimelineWindow.state != null) | |
| { | |
| m_TimelineWindow.state.Refresh(); | |
| m_TimelineWindow.state.EvaluateImmediate(); | |
| } | |
| } | |
| // Make sure the director time is within the bounds of the clip | |
| void SetTimeToClip() | |
| { | |
| if (m_TimelineWindow != null && m_TimelineWindow.state != null) | |
| { | |
| m_TimelineWindow.state.editSequence.time = Math.Min(m_EditorClip.clip.end, Math.Max(m_EditorClip.clip.start, m_TimelineWindow.state.editSequence.time)); | |
| } | |
| } | |
| public void OnEnable() | |
| { | |
| if (target == null) // case 946080 | |
| return; | |
| m_EditorClip = UnityEditor.Selection.activeObject as EditorClip; | |
| m_EditorClips = UnityEditor.Selection.objects.OfType<EditorClip>().ToArray(); | |
| SceneView.duringSceneGui += OnSceneGUI; | |
| m_PositionProperty = serializedObject.FindProperty("m_Position"); | |
| m_PositionProperty.isExpanded = true; | |
| m_RotationProperty = serializedObject.FindProperty("m_EulerAngles"); | |
| m_AnimClipProperty = serializedObject.FindProperty("m_Clip"); | |
| m_UseTrackMatchFieldsProperty = serializedObject.FindProperty("m_UseTrackMatchFields"); | |
| m_MatchTargetFieldsProperty = serializedObject.FindProperty("m_MatchTargetFields"); | |
| m_RemoveStartOffsetProperty = serializedObject.FindProperty("m_RemoveStartOffset"); | |
| m_ApplyFootIK = serializedObject.FindProperty("m_ApplyFootIK"); | |
| m_Loop = serializedObject.FindProperty("m_Loop"); | |
| m_LastPosition = m_PositionProperty.vector3Value; | |
| m_LastRotation = m_RotationProperty.vector3Value; | |
| } | |
| void OnDestroy() | |
| { | |
| SceneView.duringSceneGui -= OnSceneGUI; | |
| } | |
| void OnSceneGUI(SceneView sceneView) | |
| { | |
| DoManipulators(); | |
| } | |
| Transform GetTransform() | |
| { | |
| if (m_Binding != null) | |
| return m_Binding.transform; | |
| if (m_TimelineWindow != null && m_TimelineWindow.state != null && | |
| m_TimelineWindow.state.editSequence.director != null && | |
| m_EditorClip != null && m_EditorClip.clip != null) | |
| { | |
| var obj = TimelineUtility.GetSceneGameObject(m_TimelineWindow.state.editSequence.director, | |
| m_EditorClip.clip.GetParentTrack()); | |
| m_Binding = obj; | |
| if (obj != null) | |
| return obj.transform; | |
| } | |
| return null; | |
| } | |
| void DoManipulators() | |
| { | |
| if (m_EditorClip == null || m_EditorClip.clip == null) | |
| return; | |
| AnimationPlayableAsset animationPlayable = m_EditorClip.clip.asset as AnimationPlayableAsset; | |
| AnimationTrack track = m_EditorClip.clip.GetParentTrack() as AnimationTrack; | |
| Transform transform = GetTransform(); | |
| if (transform != null && animationPlayable != null && m_OffsetEditMode != TimelineAnimationUtilities.OffsetEditMode.None && track != null) | |
| { | |
| UndoExtensions.RegisterPlayableAsset(animationPlayable, L10n.Tr("Inspector")); | |
| Vector3 position = transform.position; | |
| Quaternion rotation = transform.rotation; | |
| EditorGUI.BeginChangeCheck(); | |
| if (m_OffsetEditMode == TimelineAnimationUtilities.OffsetEditMode.Translation) | |
| { | |
| position = Handles.PositionHandle(position, Tools.pivotRotation == PivotRotation.Global ? Quaternion.identity : rotation); | |
| } | |
| else if (m_OffsetEditMode == TimelineAnimationUtilities.OffsetEditMode.Rotation) | |
| { | |
| rotation = Handles.RotationHandle(rotation, position); | |
| } | |
| if (EditorGUI.EndChangeCheck()) | |
| { | |
| var res = TimelineAnimationUtilities.UpdateClipOffsets(animationPlayable, track, transform, position, rotation); | |
| animationPlayable.position = res.position; | |
| animationPlayable.eulerAngles = AnimationUtility.GetClosestEuler(res.rotation, animationPlayable.eulerAngles, RotationOrder.OrderZXY); | |
| Reevaluate(); | |
| Repaint(); | |
| } | |
| } | |
| } | |
| void ShowAnimationClipWarnings() | |
| { | |
| AnimationClip clip = m_AnimClipProperty.objectReferenceValue as AnimationClip; | |
| if (clip == null) | |
| { | |
| EditorGUILayout.HelpBox(AnimationPlayableAssetEditor.k_NoClipAssignedError, MessageType.Warning); | |
| } | |
| else if (clip.legacy) | |
| { | |
| EditorGUILayout.HelpBox(AnimationPlayableAssetEditor.k_LegacyClipError, MessageType.Warning); | |
| } | |
| } | |
| bool ShouldShowOffsets() | |
| { | |
| return targets.OfType<AnimationPlayableAsset>().All(x => x.hasRootTransforms); | |
| } | |
| void ShowRecordableClipRename() | |
| { | |
| if (targets.Length > 1 || m_EditorClip == null || m_EditorClip.clip == null || !m_EditorClip.clip.recordable) | |
| return; | |
| AnimationClip clip = m_AnimClipProperty.objectReferenceValue as AnimationClip; | |
| if (clip == null || !AssetDatabase.IsSubAsset(clip)) | |
| return; | |
| if (m_SerializedAnimClip == null) | |
| { | |
| m_SerializedAnimClip = new SerializedObject(clip); | |
| m_SerializedAnimClipName = m_SerializedAnimClip.FindProperty("m_Name"); | |
| } | |
| if (m_SerializedAnimClipName != null) | |
| { | |
| m_SerializedAnimClip.Update(); | |
| EditorGUI.BeginChangeCheck(); | |
| EditorGUILayout.DelayedTextField(m_SerializedAnimClipName, Styles.AnimationClipName); | |
| if (EditorGUI.EndChangeCheck()) | |
| m_SerializedAnimClip.ApplyModifiedProperties(); | |
| } | |
| } | |
| } | |
| } | |