///----------------------------------------------------------------------------------------------

        ///Try add key at time, with identity value either from existing curves or in case of no curves, from current property value.
        public bool TryKeyIdentity(float time)
        {
#if UNITY_EDITOR
            if (!HasAnyKey())
            {
                SetKeyCurrent(time);
                return(true);
            }

            RecordUndo();
            var keyAdded = false;
            var mode     = parameterModel.ForceStepMode() ? TangentMode.Constant : Prefs.defaultTangentMode;
            for (var i = 0; i < curves.Length; i++)
            {
                if (CurveUtility.AddKey(curves[i], time, curves[i].Evaluate(time), mode))
                {
                    keyAdded = true;
                }
            }
            NotifyChange();
            return(keyAdded);
#else
            return(false);
#endif
        }
示例#2
0
        ///Add key at time - value
        bool AddKey(AnimationCurve curve, float time, float value)
        {
            RecordUndo();

                        #if UNITY_EDITOR
            time = Mathf.Max(time, 0);

            var keys = curve.keys;
            for (var i = 0; i < keys.Length; i++)
            {
                if (Mathf.Abs(keys[i].time - time) < PROXIMITY_TOLERANCE)
                {
                    var key = keys[i];
                    key.time  = time;
                    key.value = value;
                    curve.MoveKey(i, key);
                    curve.UpdateTangentsFromMode();
                    return(false);
                }
            }

            var index = curve.AddKey(time, value);
            if (animatedType == typeof(bool) || animatedType == typeof(int))
            {
                curve.SetKeyTangentMode(index, TangentMode.Constant);
            }
            else
            {
                //if it's the first key added and preference is set to specific mode
                if (curve.length == 1 && Prefs.defaultTangentMode != TangentMode.Editable)
                {
                    curve.SetKeyTangentMode(index, Prefs.defaultTangentMode);
                    //else set mode from neighbors
                }
                else
                {
                    var nextIndex = index + 1;
                    if (nextIndex < curve.length)
                    {
                        var nextTangent = CurveUtility.GetKeyLeftTangentMode(curve[nextIndex]);
                        CurveUtility.SetKeyTangentMode(curve, index, nextTangent);
                    }

                    var previousIndex = index - 1;
                    if (previousIndex >= 0)
                    {
                        var previousTangent = CurveUtility.GetKeyRightTangentMode(curve[previousIndex]);
                        CurveUtility.SetKeyTangentMode(curve, index, previousTangent);
                    }
                }
            }

            curve.UpdateTangentsFromMode();
                        #else
            curve.AddKey(time, value);
                        #endif

            NotifyChange();
            return(true);
        }
        ///Remove keys at time
        public void RemoveKey(float time)
        {
#if UNITY_EDITOR
            RecordUndo();
            CurveUtility.RemoveKeys(time, curves);
            NotifyChange();
#endif
        }
示例#4
0
            ///Should be called after each change to the curves
            public void RefreshDopeKeys(IAnimatableData animatable)
            {
                //get all curve keys
                allCurves = animatable.GetCurves();
                allKeys   = new List <Keyframe>();
                for (var i = 0; i < allCurves.Length; i++)
                {
                    allKeys.AddRange(allCurves[i].keys);
                    //cache wrapmode to parameters
                    if (animatable is AnimatedParameter && i == 0)
                    {
                        preWrapMode  = allCurves[i].preWrapMode;
                        postWrapMode = allCurves[i].postWrapMode;
                    }
                }
                allKeys = allKeys.OrderBy(k => k.time).ToList();

                //create dope key times and cache related data
                currentTimes = new List <float>();
                tangentModes = new List <TangentMode>();
                keyLabels    = new List <string>();
                for (var i = 0; i < allKeys.Count; i++)
                {
                    var key = allKeys[i];
                    if (!currentTimes.Any(t => Mathf.Abs(t - key.time) <= KEY_PROXIMITY_TOLERANCE))
                    {
                        currentTimes.Add(key.time);

                        //cache tangent mode
                        var keyTangent = CurveUtility.GetKeyTangentMode(key);
                        foreach (var otherKey in allKeys.Where(k => k.time == key.time))
                        {
                            var otherKeyTangent = CurveUtility.GetKeyTangentMode(otherKey);
                            if (otherKeyTangent != keyTangent)
                            {
                                keyTangent = TangentMode.Editable;
                                break;
                            }
                        }
                        tangentModes.Add(keyTangent);

                        //cache key labels
                        keyLabels.Add(string.Format("<size=8>{0}</size>", animatable.GetKeyLabel(key.time)));
                    }
                }
            }
        ///Sets a key on target at time with it's current property value
        public void SetKeyCurrent(float time)
        {
#if UNITY_EDITOR
            RecordUndo();
            var floats = GetCurrentValueAsFloats();
            var mode   = parameterModel.ForceStepMode() ? TangentMode.Constant : Prefs.defaultTangentMode;
            if (enabled)
            {
                for (var i = 0; i < curves.Length; i++)
                {
                    CurveUtility.AddKey(curves[i], time, floats[i], mode);
                }
            }
            lastEval = floats;
            NotifyChange();
#endif
        }
示例#6
0
            ///Display curves that belong to serializeContext and transformContext parent, at time and with timeSpan.
            public void Draw3DCurve(IAnimatableData animatable, IKeyable keyable, Transform transformContext, float time, float timeSpan = 50f)
            {
                this.animatable = animatable;
                // this.keyable = keyable;

                var curves = animatable.GetCurves();

                if (curves == null || curves.Length != 3)
                {
                    return;
                }

                var curveX = curves[0];
                var curveY = curves[1];
                var curveZ = curves[2];

                if (curveX.length < 2 || curveY.length < 2 || curveZ.length < 2)
                {
                    return;
                }

                if (curveX.length != curveY.length || curveY.length != curveZ.length)
                {
                    return;
                }


                var serializeContext = keyable as Object;
                var e = Event.current;

                var start = (float)Mathf.FloorToInt(time - (timeSpan / 2));
                var end   = (float)Mathf.CeilToInt(time + (timeSpan / 2));

                start = Mathf.Max(start, Mathf.Min(curveX[0].time, curveY[0].time, curveZ[0].time));
                end   = Mathf.Min(end, Mathf.Max(curveX[curveX.length - 1].time, curveY[curveY.length - 1].time, curveZ[curveZ.length - 1].time));

                if (curveX.length != lastCurveLength)
                {
                    lastCurveLength = curveX.length;
                    kIndex          = -1;
                }

                //1. Keyframes.
                for (var k = 0; k < curveX.length; k++)
                {
                    EditorGUI.BeginChangeCheck();
                    var forceChanged = false;

                    var keyX = curveX[k];
                    var keyY = curveY[k];
                    var keyZ = curveZ[k];

                    if (keyX.time < start)
                    {
                        continue;
                    }
                    if (keyX.time > end)
                    {
                        break;
                    }

                    var tangentModeX     = CurveUtility.GetKeyTangentMode(keyX);
                    var tangentModeY     = CurveUtility.GetKeyTangentMode(keyY);
                    var tangentModeZ     = CurveUtility.GetKeyTangentMode(keyZ);
                    var haveSameTangents = tangentModeX == tangentModeY && tangentModeY == tangentModeZ;
                    var tangentMode      = haveSameTangents ? tangentModeX : TangentMode.Editable;
                    var isBroken         = CurveUtility.GetKeyBroken(keyX) && CurveUtility.GetKeyBroken(keyY) && CurveUtility.GetKeyBroken(keyZ);

                    var pos = new Vector3(keyX.value, keyY.value, keyZ.value);

                    if (transformContext != null)
                    {
                        pos = transformContext.TransformPoint(pos);
                    }

                    Handles.Label(pos, keyX.time.ToString("0.00"));

                    ///MOUSE EVENTS
                    var screenPos = HandleUtility.WorldToGUIPoint(pos);
                    if (((Vector2)screenPos - e.mousePosition).magnitude < 10)
                    {
                        if (e.type == EventType.MouseDown)
                        {
                            if (e.button == 0 && kIndex != k)
                            {
                                kIndex = k;
                                GUIUtility.hotControl = 0;
                                SceneView.RepaintAll();
                                e.Use();
                            }

                            if (e.button == 1 && kIndex == k)
                            {
                                var menu = new GenericMenu();
                                menu.AddItem(new GUIContent("Jump Time Here"), false, () => { keyable.root.currentTime = curveX[kIndex].time + keyable.startTime; });
                                menu.AddItem(new GUIContent("Smooth"), tangentMode == TangentMode.Smooth, () => { contextAction = ContextAction.SetTangentMode; contextTangentMode = TangentMode.Smooth; });
                                menu.AddItem(new GUIContent("Linear"), tangentMode == TangentMode.Linear, () => { contextAction = ContextAction.SetTangentMode; contextTangentMode = TangentMode.Linear; });
                                menu.AddItem(new GUIContent("Constant"), tangentMode == TangentMode.Constant, () => { contextAction = ContextAction.SetTangentMode; contextTangentMode = TangentMode.Constant; });
                                menu.AddItem(new GUIContent("Editable"), tangentMode == TangentMode.Editable, () => { contextAction = ContextAction.SetTangentMode; contextTangentMode = TangentMode.Editable; });
                                if (tangentMode == TangentMode.Editable)
                                {
                                    menu.AddItem(new GUIContent("Tangents/Connected"), !isBroken, () => { contextAction = ContextAction.SetBrokenMode; contextBrokenMode = false; });
                                    menu.AddItem(new GUIContent("Tangents/Broken"), isBroken, () => { contextAction = ContextAction.SetBrokenMode; contextBrokenMode = true; });
                                }
                                menu.AddSeparator("/");
                                menu.AddItem(new GUIContent("Delete"), false, () => { contextAction = ContextAction.Delete; });
                                menu.ShowAsContext();
                                e.Use();
                            }
                        }
                    }

                    ///APPLY CONTEXT ACTIONS
                    if (contextAction != ContextAction.None && k == kIndex)
                    {
                        var _contextAction = contextAction;
                        contextAction = ContextAction.None;
                        forceChanged  = true;
                        if (_contextAction == ContextAction.SetBrokenMode)
                        {
                            Undo.RecordObject(serializeContext, "Animation Curve Change");
                            curveX.SetKeyBroken(kIndex, contextBrokenMode);
                            curveY.SetKeyBroken(kIndex, contextBrokenMode);
                            curveZ.SetKeyBroken(kIndex, contextBrokenMode);

                            NotifyChange();
                            return;
                        }

                        if (_contextAction == ContextAction.SetTangentMode)
                        {
                            Undo.RecordObject(serializeContext, "Animation Curve Change");
                            curveX.SetKeyTangentMode(kIndex, contextTangentMode);
                            curveY.SetKeyTangentMode(kIndex, contextTangentMode);
                            curveZ.SetKeyTangentMode(kIndex, contextTangentMode);

                            NotifyChange();
                            return;
                        }

                        if (_contextAction == ContextAction.Delete)
                        {
                            Undo.RecordObject(serializeContext, "Animation Curve Change");
                            curveX.RemoveKey(k);
                            curveY.RemoveKey(k);
                            curveZ.RemoveKey(k);
                            kIndex = -1;

                            NotifyChange();
                            return;
                        }
                    }


                    ///POSITION
                    var pointSize = HandleUtility.GetHandleSize(pos) * 0.05f;
                    var newValue  = pos;
                    if (kIndex == k)
                    {
                        if (Tools.current == Tool.Move)
                        {
                            newValue = Handles.PositionHandle(pos, Quaternion.identity);
                        }
                        else
                        {
                            newValue = Handles.FreeMoveHandle(pos, Quaternion.identity, pointSize, Vector3.zero, Handles.RectangleCap);
                        }
                    }
                    var cam = SceneView.lastActiveSceneView.camera;
                    Handles.RectangleCap(0, pos, cam.transform.rotation, pointSize);

                    if (transformContext != null)
                    {
                        newValue = transformContext.InverseTransformPoint(newValue);
                    }

                    keyX.value = newValue.x;
                    keyY.value = newValue.y;
                    keyZ.value = newValue.z;


                    ///TANGENTS
                    if (haveSameTangents && tangentMode == TangentMode.Editable)
                    {
                        if (kIndex == k)
                        {
                            if (k != 0)
                            {
                                var inHandle = new Vector3(-keyX.inTangent, -keyY.inTangent, -keyZ.inTangent);
                                inHandle /= HANDLE_DISTANCE_COMPENSATION;
                                inHandle  = newValue + inHandle;
                                if (transformContext != null)
                                {
                                    inHandle = transformContext.TransformPoint(inHandle);
                                }
                                var handleSize  = HandleUtility.GetHandleSize(inHandle) * 0.05f;
                                var newInHandle = Handles.FreeMoveHandle(inHandle, Quaternion.identity, handleSize, Vector3.zero, Handles.CircleCap);
                                Handles.DrawLine(pos, newInHandle);
                                if (transformContext != null)
                                {
                                    newInHandle = transformContext.InverseTransformPoint(newInHandle);
                                }

                                newInHandle   -= newValue;
                                newInHandle   *= HANDLE_DISTANCE_COMPENSATION;
                                keyX.inTangent = -newInHandle.x;
                                keyY.inTangent = -newInHandle.y;
                                keyZ.inTangent = -newInHandle.z;
                                if (!isBroken)
                                {
                                    keyX.outTangent = keyX.inTangent;
                                    keyY.outTangent = keyY.inTangent;
                                    keyZ.outTangent = keyZ.inTangent;
                                }
                            }

                            if (k < curveX.length - 1)
                            {
                                var outHandle = new Vector3(keyX.outTangent, keyY.outTangent, keyZ.outTangent);
                                outHandle /= HANDLE_DISTANCE_COMPENSATION;
                                outHandle  = newValue + outHandle;
                                if (transformContext != null)
                                {
                                    outHandle = transformContext.TransformPoint(outHandle);
                                }
                                var handleSize   = HandleUtility.GetHandleSize(outHandle) * 0.05f;
                                var newOutHandle = Handles.FreeMoveHandle(outHandle, Quaternion.identity, handleSize, Vector3.zero, Handles.CircleCap);
                                Handles.DrawLine(pos, newOutHandle);
                                if (transformContext != null)
                                {
                                    newOutHandle = transformContext.InverseTransformPoint(newOutHandle);
                                }
                                newOutHandle   -= newValue;
                                newOutHandle   *= HANDLE_DISTANCE_COMPENSATION;
                                keyX.outTangent = newOutHandle.x;
                                keyY.outTangent = newOutHandle.y;
                                keyZ.outTangent = newOutHandle.z;
                                if (!isBroken)
                                {
                                    keyX.inTangent = keyX.outTangent;
                                    keyY.inTangent = keyY.outTangent;
                                    keyZ.inTangent = keyZ.outTangent;
                                }
                            }
                        }
                    }

                    ///APPLY
                    if (EditorGUI.EndChangeCheck() || forceChanged)
                    {
                        Undo.RecordObject(serializeContext, "Animation Curve Change");
                        curveX.MoveKey(k, keyX);
                        curveY.MoveKey(k, keyY);
                        curveZ.MoveKey(k, keyZ);
                        EditorUtility.SetDirty(serializeContext);
                        NotifyChange();
                    }
                }


                ///2. Motion Path
                Handles.color = Prefs.motionPathsColor;
                var lastDrawnPos = Vector3.zero;

                for (var t = start; t <= end; t += DRAW_RESOLUTION)
                {
                    var pos     = new Vector3(curveX.Evaluate(t), curveY.Evaluate(t), curveZ.Evaluate(t));
                    var nextPos = new Vector3(curveX.Evaluate(t + DRAW_RESOLUTION), curveY.Evaluate(t + DRAW_RESOLUTION), curveZ.Evaluate(t + DRAW_RESOLUTION));

                    if (transformContext != null)
                    {
                        pos     = transformContext.TransformPoint(pos);
                        nextPos = transformContext.TransformPoint(nextPos);
                    }

                    if ((pos - lastDrawnPos).magnitude > DRAW_THRESHOLD)
                    {
                        lastDrawnPos = pos;
                        Handles.SphereCap(0, pos, Quaternion.identity, 0.02f);
                        Handles.DrawLine(pos, nextPos);
                    }
                }
                Handles.color = Color.white;


                ///3. GUI
                if (kIndex >= 0)
                {
                    var guiRect = new Rect(Screen.width - 300, Screen.height - 170, 280, 130);
                    var kx      = curveX[kIndex];
                    var ky      = curveY[kIndex];
                    var kz      = curveZ[kIndex];
                    EditorGUI.BeginChangeCheck();
                    {
                        Handles.BeginGUI();
                        GUILayout.BeginArea(guiRect);
                        EditorTools.BeginBody("Keyframe Parameters");
                        kx.value = EditorGUILayout.FloatField("X", kx.value);
                        ky.value = EditorGUILayout.FloatField("Y", ky.value);
                        kz.value = EditorGUILayout.FloatField("Z", kz.value);

                        GUI.enabled = CurveUtility.GetKeyTangentMode(kx) == TangentMode.Editable;
                        var inTangent = new Vector3(kx.inTangent, ky.inTangent, kz.inTangent);
                        inTangent    = EditorGUILayout.Vector3Field("", inTangent);
                        kx.inTangent = inTangent.x;
                        ky.inTangent = inTangent.y;
                        kz.inTangent = inTangent.z;

                        GUI.enabled = CurveUtility.GetKeyBroken(kx);
                        var outTangent = new Vector3(kx.outTangent, ky.outTangent, kz.outTangent);
                        outTangent    = EditorGUILayout.Vector3Field("", outTangent);
                        kx.outTangent = outTangent.x;
                        ky.outTangent = outTangent.y;
                        kz.outTangent = outTangent.z;

                        GUI.enabled = true;

                        EditorTools.EndBody();
                        GUILayout.EndArea();
                        Handles.EndGUI();
                    }
                    if (EditorGUI.EndChangeCheck())
                    {
                        Undo.RecordObject(serializeContext, "Animation Curve Change");
                        curveX.MoveKey(kIndex, kx);
                        curveY.MoveKey(kIndex, ky);
                        curveZ.MoveKey(kIndex, kz);
                        EditorUtility.SetDirty(serializeContext);
                        NotifyChange();
                    }
                }


                /*
                 *              for (var k = 0; k < curveX.length - 1; k++){
                 *                  var keyX = curveX[k];
                 *                  var keyY = curveY[k];
                 *                  var keyZ = curveZ[k];
                 *                  var nextKeyX = curveX[k+1];
                 *                  var nextKeyY = curveY[k+1];
                 *                  var nextKeyZ = curveZ[k+1];
                 *
                 *                  var t = new Vector3(keyX.time, keyY.time, keyZ.time);
                 *                  var nextT = new Vector3(nextKeyX.time, nextKeyY.time, nextKeyZ.time);
                 *
                 *                  var tangent = new Vector3( keyX.outTangent, keyY.outTangent, keyZ.outTangent );
                 *                  var nextTangent = new Vector3( nextKeyX.inTangent, nextKeyY.inTangent, nextKeyZ.inTangent );
                 *
                 *                  var pos = new Vector3( keyX.value, keyY.value, keyZ.value );
                 *                  var nextPos = new Vector3( nextKeyX.value, nextKeyY.value, nextKeyZ.value );
                 *
                 *                  if (transformContext != null){
                 *                      pos = transformContext.TransformPoint(pos);
                 *                      nextPos = transformContext.TransformPoint(nextPos);
                 *                  }
                 *
                 *                  var num = (nextT - t) * 0.333333f;
                 *                  var tangentPos = new Vector3( pos.x + num.x * tangent.x, pos.y + num.y * tangent.y, pos.z + num.z * tangent.z );
                 *                  var nextTangentPos = new Vector3( nextPos.x - num.x * nextTangent.x, nextPos.y - num.y * nextTangent.y, nextPos.z - num.z * nextTangent.z );
                 *
                 *                  Handles.DrawBezier(pos, nextPos, tangentPos, nextTangentPos, Prefs.motionPathsColor, null, 1.5f);
                 *              }
                 */
            }
 ///Returns the key time before time, or last key if time is first key time.
 public float GetKeyPrevious(float time)
 {
     return(CurveUtility.GetKeyPrevious(time, curves));
 }
 ///Returns the key time after time, or first key if time is last key time.
 public float GetKeyNext(float time)
 {
     return(CurveUtility.GetKeyNext(time, curves));
 }
 ///Has any key at time?
 public bool HasKey(float time)
 {
     return(CurveUtility.HasKey(time, curves));
 }
 ///Are there any keys at all?
 public bool HasAnyKey()
 {
     return(CurveUtility.HasAnyKey(curves));
 }