Search Unity

Normalized Animation Curve

Discussion in 'Immediate Mode GUI (IMGUI)' started by lightbug14, Mar 26, 2019.

  1. lightbug14

    lightbug14

    Joined:
    Feb 3, 2018
    Posts:
    51
    Hello everyone, I have been asking myself about this for quite some time, is it possible to implement/draw a normalized animation curve? by normalized i mean fixed axes, horizontal axis = [0,1] and vertical axis = [0,1] , this is because i like to offer the maxValues (time and verticalAxis) as parameters for the user instead of modifying the curve directly, so by doing this i can set a "behaviour curve".

    This is an example of what i want (is a "Size By Speed" curve from the particle system), I've modified the max vertical value using MSPaint:

    ParticleANimCurve.jpg


    Thanks in advance!
    Regards.
     
  2. FeastSC2

    FeastSC2

    Joined:
    Sep 30, 2016
    Posts:
    598
    It's not quite what you want but I use this extention class for my animation curves so that the user can't go above the value of 1 or something else like you mentioned.

    The problem is that the curve (not the control points) can go above the max.


    Code (CSharp):
    1. using System;
    2. using UnityEngine;
    3.  
    4. public class AnimationCurveExt
    5. {
    6.     /// <summary>
    7.     /// You can call this OnValidate to keep the animation curve constrained!
    8.     /// </summary>
    9.     public static void ConstrainAnimCurve(ref AnimationCurve _curve, WrapMode _wrapMode = WrapMode.Loop,
    10.         float _from = -.1f, float _to = .1f,
    11.         bool _firstKeySameAsLast = false, Vector2? _firstKeyForce = null, Vector2? _lastKeyForce = null)
    12.     {
    13.         if (_curve != null)
    14.         {
    15.             _curve.postWrapMode = _wrapMode;
    16.             _curve.preWrapMode = _wrapMode;
    17.             if (_curve.keys.Length >= 2)
    18.             {
    19.                 var keys = _curve.keys;
    20.                 if (Math.Abs(keys[0].time) > 0.001f)
    21.                 {
    22.                     keys[0].time = 0f; // first key is set to 0f
    23.                     _curve.keys = keys;
    24.                 }
    25.  
    26.                 if (Math.Abs(keys[_curve.keys.Length - 1].time) > 0.001f)
    27.                 {
    28.                     keys[_curve.keys.Length - 1].time = 1f; // last key is set to 1f
    29.                     _curve.keys = keys;
    30.                 }
    31.  
    32.                 if (Math.Abs(keys[_curve.keys.Length - 1].value - keys[0].value) > 0.001f)
    33.                 {
    34.                     if (_firstKeySameAsLast) keys[_curve.keys.Length - 1].value = keys[0].value;
    35.                     _curve.keys = keys;
    36.                 }
    37.  
    38.                 keys = _curve.keys;
    39.                 for (var i = 0; i < _curve.keys.Length; i++)
    40.                 {
    41.                     if (keys[i].value > _to)
    42.                     {
    43.                         keys[i].value = _to;
    44.                         _curve.keys = keys;
    45.                     }
    46.                     else if (keys[i].value < _from)
    47.                     {
    48.                         keys[i].value = _from;
    49.                         _curve.keys = keys;
    50.                     }
    51.                 }
    52.  
    53.                 // Force first and last keys
    54.                 keys = _curve.keys;
    55.                 if (_firstKeyForce.HasValue)
    56.                 {
    57.                     ForceKey(_curve, _firstKeyForce, keys, 0);
    58.                 }
    59.  
    60.                 if (_lastKeyForce.HasValue)
    61.                 {
    62.                     ForceKey(_curve, _lastKeyForce, keys, _curve.keys.Length - 1);
    63.                 }
    64.             }
    65.         }
    66.     }
    67.  
    68.  
    69.  
    70.     private static void ForceKey(AnimationCurve _curve, Vector2? _keyForce, Keyframe[] keys, int _index)
    71.     {
    72.         bool hasChanged = false;
    73.         var time = _keyForce.Value.x;
    74.         var value = _keyForce.Value.y;
    75.         if (keys[_index].time != time)
    76.         {
    77.             keys[_index].time = time;
    78.             hasChanged = true;
    79.         }
    80.  
    81.         if (keys[_index].value != value)
    82.         {
    83.             keys[_index].value = value;
    84.             hasChanged = true;
    85.         }
    86.  
    87.         if (hasChanged)
    88.             _curve.keys = keys;
    89.     }
    90.  
    91.     public static void RandomizeCurve(ref AnimationCurve _curve, int _keysAmount, float _from, float _to)
    92.     {
    93.         if (_curve != null)
    94.         {
    95.             var keys = new Keyframe[_keysAmount];
    96.             for (var i = 0; i < keys.Length; i++)
    97.             {
    98.                 keys[i] = new Keyframe
    99.                 {
    100.                     time = 1f / _keysAmount * i,
    101.                     value = UnityEngine.Random.Range(_from, _to)
    102.                 };
    103.             }
    104.  
    105.             _curve.keys = keys;
    106.  
    107.             ConstrainAnimCurve(ref _curve);
    108.         }
    109.     }
    110. }
    111.  
    112.  
     
    lightbug14 likes this.
  3. lightbug14

    lightbug14

    Joined:
    Feb 3, 2018
    Posts:
    51
    Hi, thanks for the reply, i was thinking in constraining the values as well, that will work I guess, at least for the control points.
     
  4. Xarbrough

    Xarbrough

    Joined:
    Dec 11, 2014
    Posts:
    486
    You can constrain the curve editor to a fixed size if you use the editor API to draw the curve field yourself. Search for EditorGUI AnimationCurveField. This is a neater solution I think. You can write an attribute similar to the Range attribute for AnimationCurve and then implement a custom property drawer. I could show some code later, when I’m not on the phone.