Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Normalized Animation Curve

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

  1. lightbug14

    lightbug14

    Joined:
    Feb 3, 2018
    Posts:
    447
    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.
     
    PixelLifetime likes this.
  2. FeastSC2

    FeastSC2

    Joined:
    Sep 30, 2016
    Posts:
    978
    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:
    447
    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:
    1,188
    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.
     
    Celezt likes this.