Exemple #1
0
        internal static AnimationClipSettings GetAnimationClipSettings([NotNull] AnimationClip clip)
        {
            if (!k_ClipSettingsCache.ContainsKey(clip))
            {
                k_ClipSettingsCache.Add(clip, clip.legacy ? null : TinyAnimationEditorBridge.GetAnimationClipSettings(clip));
            }

            return(k_ClipSettingsCache[clip]);
        }
        void OnEnable()
        {
            m_TinyAnimationAuthoring = (TinyAnimationAuthoring)target;
            m_Animator          = m_TinyAnimationAuthoring.GetComponent <Animator>();
            m_CurrentController = TinyAnimationEditorBridge.GetEffectiveAnimatorController(m_Animator);

            // Ensures an update during first pass
            m_TargetDirtyCount   = -1;
            m_AnimatorDirtyCount = -1;

            m_AnimationClipsProp          = serializedObject.FindProperty(nameof(TinyAnimationAuthoring.animationClips));
            m_PlayAutomaticallyProp       = serializedObject.FindProperty(nameof(TinyAnimationAuthoring.playAutomatically));
            m_PatchScaleProp              = serializedObject.FindProperty(nameof(TinyAnimationAuthoring.patchMissingScaleIfNeeded));
            m_AdditionalAnimatorClipsProp = serializedObject.FindProperty(nameof(TinyAnimationAuthoring.additionalAnimatorClips));
        }
        void OnDisable()
        {
            if (m_CurrentController != null)
            {
                TinyAnimationEditorBridge.UnregisterDirtyCallbackFromAnimatorController(m_CurrentController, OnControllerDirty);
                m_CurrentController = null;
            }

            m_TinyAnimationAuthoring = null;
            m_Animator = null;

            m_AnimationClipsProp          = null;
            m_PlayAutomaticallyProp       = null;
            m_PatchScaleProp              = null;
            m_AdditionalAnimatorClipsProp = null;
        }
        public override void OnInspectorGUI()
        {
            serializedObject.UpdateIfRequiredOrScript();
            EditorGUILayout.PropertyField(m_AnimationClipsProp, true, null);
            EditorGUILayout.PropertyField(m_PlayAutomaticallyProp, false, null);
            EditorGUILayout.PropertyField(m_PatchScaleProp, false, null);
            serializedObject.ApplyModifiedProperties();

            var newTargetDirtyCount   = EditorUtility.GetDirtyCount(m_TinyAnimationAuthoring);
            var newAnimatorDirtyCount = EditorUtility.GetDirtyCount(m_Animator);

            var targetIsDirty                  = m_TargetDirtyCount != newTargetDirtyCount;
            var animatorComponentIsDirty       = m_AnimatorDirtyCount != newAnimatorDirtyCount;
            var animatorControllerAssetIsDirty = m_AnimatorControllerIsDirty;

            if (targetIsDirty)
            {
                m_TargetDirtyCount = newTargetDirtyCount;
            }

            if (animatorComponentIsDirty)
            {
                m_AnimatorDirtyCount = newAnimatorDirtyCount;

                if (m_CurrentController != null)
                {
                    TinyAnimationEditorBridge.UnregisterDirtyCallbackFromAnimatorController(m_CurrentController, OnControllerDirty);
                }

                m_CurrentController = TinyAnimationEditorBridge.GetEffectiveAnimatorController(m_Animator);

                if (m_CurrentController != null)
                {
                    TinyAnimationEditorBridge.RegisterDirtyCallbackForAnimatorController(m_CurrentController, OnControllerDirty);
                }
            }

            if (animatorControllerAssetIsDirty)
            {
                m_AnimatorControllerIsDirty = false;
            }

            if (targetIsDirty || animatorComponentIsDirty || animatorControllerAssetIsDirty)
            {
                m_TinyAnimationAuthoring.UpdateAdditionalAnimatorClips();
            }

            if (m_TinyAnimationAuthoring.additionalAnimatorClips.Count == 0)
            {
                return;
            }

            if (targetIsDirty)
            {
                UpdateNonNullUserClipsCount();
            }

            EditorGUILayout.Space();

            EditorGUILayout.HelpBox($"The following clips will be converted (in that order, starting at index {m_NonNullUserClipsCount.ToString(CultureInfo.InvariantCulture)}) from the Animator.\n" +
                                    "Note that the Animator's state machine will not get converted; only the clips.", MessageType.Info, true);

            using (new EditorGUI.DisabledScope(true))
            {
                EditorGUILayout.PropertyField(m_AdditionalAnimatorClipsProp, true, null);
            }
        }
        static BlobAssetReference <CurvesInfo> ConvertFloatCurves([NotNull] AnimationClip clip)
        {
            var bindings = AnimationUtility
                           .GetCurveBindings(clip)
                           .OrderBy(b => b.path)        // Ensures we are processing one target at a time
                           .ThenBy(b => b.propertyName) // Ensures we are processing vector properties together
                           .ToArray();

            var numBindings = bindings.Length;

            var blobAssetRef = BlobAssetReference <CurvesInfo> .Null;

            if (numBindings == 0)
            {
                return(blobAssetRef);
            }

            var targetPaths = new List <FixedString512>(numBindings);
            var animationBindingsConvertedNames = new List <FixedString512>(numBindings);
            var keyframeCurves = new List <KeyframeCurve>(numBindings);

            var scaleRequired = false;
            var numKeys       = 0;
            var numBindingsAfterConversion = numBindings;

            for (var i = 0; i < numBindings; i++)
            {
                var binding      = bindings[i];
                var rotationMode = TinyAnimationEditorBridge.GetRotationMode(binding);

                // Handle non quaternion rotation.
                if (rotationMode != TinyAnimationEditorBridge.RotationMode.Undefined && rotationMode != TinyAnimationEditorBridge.RotationMode.RawQuaternions)
                {
                    // TODO: Handle other modes when/if they show up
                    if (rotationMode == TinyAnimationEditorBridge.RotationMode.RawEuler)
                    {
                        var currentPath = binding.path;

                        var xBinding = default(EditorCurveBinding);
                        var yBinding = default(EditorCurveBinding);
                        var zBinding = default(EditorCurveBinding);

                        var rotationBindingOffset = 0;
                        while (rotationBindingOffset < 3 && i + rotationBindingOffset < numBindings)
                        {
                            var nextBinding = bindings[i + rotationBindingOffset];
                            if (!string.Equals(currentPath, nextBinding.path, StringComparison.Ordinal) || TinyAnimationEditorBridge.GetRotationMode(nextBinding) != TinyAnimationEditorBridge.RotationMode.RawEuler)
                            {
                                // Binding is either for a different target or not a rotation: skip!
                                break;
                            }

                            if (nextBinding.propertyName.EndsWith(".x", StringComparison.Ordinal))
                            {
                                xBinding = nextBinding;
                            }
                            else if (nextBinding.propertyName.EndsWith(".y", StringComparison.Ordinal))
                            {
                                yBinding = nextBinding;
                            }
                            else
                            {
                                zBinding = nextBinding;
                            }

                            rotationBindingOffset++;
                        }

                        var xCurveOriginal = xBinding != default
                            ? AnimationUtility.GetEditorCurve(clip, xBinding)
                            : new AnimationCurve(new UnityEngine.Keyframe(0.0f, 0.0f), new UnityEngine.Keyframe(clip.length, 0.0f));

                        var yCurveOriginal = yBinding != default
                            ? AnimationUtility.GetEditorCurve(clip, yBinding)
                            : new AnimationCurve(new UnityEngine.Keyframe(0.0f, 0.0f), new UnityEngine.Keyframe(clip.length, 0.0f));

                        var zCurveOriginal = zBinding != default
                            ? AnimationUtility.GetEditorCurve(clip, zBinding)
                            : new AnimationCurve(new UnityEngine.Keyframe(0.0f, 0.0f), new UnityEngine.Keyframe(clip.length, 0.0f));

                        var xCurveNew = new AnimationCurve();
                        var yCurveNew = new AnimationCurve();
                        var zCurveNew = new AnimationCurve();
                        var wCurveNew = new AnimationCurve();

                        // We *need* to resample at the framerate when converting from Euler to Quaternion
                        var step = clip.length / clip.frameRate;
                        var time = 0.0f;
                        do
                        {
                            EvaluateAndConvert(time);
                            time += step;
                        }while (time <= clip.length - step);

                        // Setting the last frame explicitly to avoid precision errors
                        EvaluateAndConvert(clip.length);

                        void EvaluateAndConvert(float t)
                        {
                            var euler = new float3(xCurveOriginal.Evaluate(t), yCurveOriginal.Evaluate(t), zCurveOriginal.Evaluate(t));
                            var quat  = quaternion.Euler(math.radians(euler));

                            xCurveNew.AddKey(new UnityEngine.Keyframe(t, quat.value.x, Mathf.Infinity, Mathf.Infinity));
                            yCurveNew.AddKey(new UnityEngine.Keyframe(t, quat.value.y, Mathf.Infinity, Mathf.Infinity));
                            zCurveNew.AddKey(new UnityEngine.Keyframe(t, quat.value.z, Mathf.Infinity, Mathf.Infinity));
                            wCurveNew.AddKey(new UnityEngine.Keyframe(t, quat.value.w, Mathf.Infinity, Mathf.Infinity));
                        }

                        var resampledKeysCount = xCurveNew.length;

                        var xPropName = GetConvertedName(binding.type, TinyAnimationEditorBridge.CreateRawQuaternionsBindingName("x"));
                        var yPropName = GetConvertedName(binding.type, TinyAnimationEditorBridge.CreateRawQuaternionsBindingName("y"));
                        var zPropName = GetConvertedName(binding.type, TinyAnimationEditorBridge.CreateRawQuaternionsBindingName("z"));
                        var wPropName = GetConvertedName(binding.type, TinyAnimationEditorBridge.CreateRawQuaternionsBindingName("w"));

                        animationBindingsConvertedNames.Add(new FixedString512(xPropName));
                        animationBindingsConvertedNames.Add(new FixedString512(yPropName));
                        animationBindingsConvertedNames.Add(new FixedString512(zPropName));
                        animationBindingsConvertedNames.Add(new FixedString512(wPropName));

                        keyframeCurves.Add(xCurveNew.ToKeyframeCurve());
                        keyframeCurves.Add(yCurveNew.ToKeyframeCurve());
                        keyframeCurves.Add(zCurveNew.ToKeyframeCurve());
                        keyframeCurves.Add(wCurveNew.ToKeyframeCurve());

                        numKeys += resampledKeysCount * 4;

                        var targetPath = string.IsNullOrEmpty(binding.path) ? string.Empty : binding.path;
                        targetPaths.Add(targetPath);
                        targetPaths.Add(targetPath);
                        targetPaths.Add(targetPath);
                        targetPaths.Add(targetPath);

                        // How many new bindings were added by this conversion?
                        // e.g.:
                        //     Euler bindings to [x,y,z] converts to quaternion bindings [x,y,z,w], so we added 1 new binding
                        //     Euler bindings to [y] converts to  quaternion bindings [x,y,z,w], so we added 3 new binding
                        numBindingsAfterConversion += 4 - rotationBindingOffset;

                        // Skip already processed bindings
                        i += rotationBindingOffset - 1;
                    }
                    else
                    {
                        throw new InvalidOperationException($"Rotation mode: {rotationMode} is not supported.");
                    }
                }
                else
                {
                    // Note: Empty string maps to self in Transform.Find()
                    targetPaths.Add(string.IsNullOrEmpty(binding.path) ? string.Empty : binding.path);

                    var bindingPropertyName = binding.propertyName;
                    var convertedName       = GetConvertedName(binding.type, bindingPropertyName);

                    animationBindingsConvertedNames.Add(new FixedString512(convertedName));

                    var animationCurve = AnimationUtility.GetEditorCurve(clip, binding);
                    var curve          = animationCurve.ToKeyframeCurve();
                    keyframeCurves.Add(curve);
                    numKeys += curve.Length;

                    if (!scaleRequired && binding.type == typeof(Transform) && bindingPropertyName.StartsWith("m_LocalScale.", StringComparison.Ordinal))
                    {
                        scaleRequired = true;
                    }
                }
            }

            using (var blobBuilder = new BlobBuilder(Allocator.Temp))
            {
                ref var builderRoot = ref blobBuilder.ConstructRoot <CurvesInfo>();

                var keyframesBuilder    = blobBuilder.Allocate(ref builderRoot.Keyframes, numKeys);
                var curveOffsetsBuilder = blobBuilder.Allocate(ref builderRoot.CurveOffsets, numBindingsAfterConversion);
                var bindingNamesBuilder = blobBuilder.Allocate(ref builderRoot.BindingNames, numBindingsAfterConversion);
                var targetPathsBuilder  = blobBuilder.Allocate(ref builderRoot.TargetGameObjectPaths, numBindingsAfterConversion);

                // We don't care about that field in this case
                blobBuilder.Allocate(ref builderRoot.AnimatedAssetGroupings, 0);

                for (int bindingIndex = 0, keyIndex = 0, curveOffset = 0; bindingIndex < numBindingsAfterConversion; ++bindingIndex)
                {
                    var keyframeCurve = keyframeCurves[bindingIndex];
                    for (var i = 0; i < keyframeCurve.Length; ++i)
                    {
                        keyframesBuilder[keyIndex++] = keyframeCurve[i];
                    }

                    curveOffsetsBuilder[bindingIndex] = curveOffset;
                    curveOffset += keyframeCurve.Length;
                    bindingNamesBuilder[bindingIndex] = animationBindingsConvertedNames[bindingIndex];
                    targetPathsBuilder[bindingIndex]  = targetPaths[bindingIndex];
                }

                builderRoot.ConversionActions = scaleRequired ? RequiredConversionActions.PatchScale : RequiredConversionActions.None;

                blobAssetRef = blobBuilder.CreateBlobAssetReference <CurvesInfo>(Allocator.Persistent);
            }