Ease-in and ease-out animation formula

60,697

Solution 1

Quadratic ease out where:

t = current time
b = start value
c = change in value
d = duration

 function (float time, float startValue, float change, float duration) {
     time /= duration / 2;
     if (time < 1)  {
          return change / 2 * time * time + startValue;
     }

     time--;
     return -change / 2 * (time * (time - 2) - 1) + startValue;
 };

source: http://gizma.com/easing/

Solution 2

Personally, I'd rather use a function that gets a time in [0; 1] and output a value in [0; 1], so that we can apply the result to any type (2D vector, 3D vector, ...).

Solution 1

For the quadratic easing in/out, the curve is separated in two distinct functions depending on the value of t:

  • when t <= 0.5: f(x) = 2 * x * x with x in [0;0.5] (graph)
  • when t > 0.5: f(x) = 2 * x * (1 - x) + 0.5 with x in [0;0.5] (graph)

Here are the graphs:

graph - part 1
graph - part 2

Since the second function is also in [0;0.5], but t > 0.5 when we start to use it, we need to reduce t by 0.5.

This is the result, in C:

float InOutQuadBlend(float t)
{
    if(t <= 0.5f)
        return 2.0f * t * t;
    t -= 0.5f;
    return 2.0f * t * (1.0f - t) + 0.5f;
}

Solution 2 (Bézier)

Another interesting blend curve is the one given by Bézier, which have the advantage to be quite optimized (no if). Here is the curve from Wolfram:

Bezier curve

And here is the C code:

float BezierBlend(float t)
{
    return t * t * (3.0f - 2.0f * t);
}

Solution 3 (parametric function)

Another method proposed by @DannyYaroslavski is the simple formula proposed here.

It is parametric and gets a nice in/out acceleration and deceleration.

With alpha = 2, you get this function:

curve

Which translates in C like this:

float ParametricBlend(float t)
{
    float sqt = t * t;
    return sqt / (2.0f * (sqt - t) + 1.0f);
}

Edit 1: Add solution 3 from @DannyYaroslavski
Edit 2: Better explanation for solution 1
Edit 3: Add graphs to all solutions

Solution 3

All the above solutions lack examples of usage.

Found good solution here:

 function animate({timing, draw, duration}) {

  let start = performance.now();

  requestAnimationFrame(function animate(time) {
    // timeFraction goes from 0 to 1
    let timeFraction = (time - start) / duration;
    if (timeFraction > 1) timeFraction = 1;

    // calculate the current animation state
    let progress = timing(timeFraction)

    draw(progress); // draw it

    if (timeFraction < 1) {
      requestAnimationFrame(animate);
    }

  });
}

Example of usage:

animate({
  duration: 1000,
  timing(timeFraction) { // here you can put other functions
    return timeFraction;
  },
  draw(progress) {
    elem.style.width = progress * 100 + '%';
  }
});

Other function:

function quad(timeFraction) {
  return Math.pow(timeFraction, 2)
}

More here

Share:
60,697

Related videos on Youtube

ahmd0
Author by

ahmd0

Updated on May 01, 2021

Comments

  • ahmd0
    ahmd0 almost 3 years

    Say, if I'm doing the Ease-Out and then Ease-In animation of an object's movement from X1 coordinate to X2 coordinate over S steps at equal time intervals. Can some suggest the formula to calculate this movement's X coordinates?

    • Matthew
      Matthew over 11 years
      Check out robertpenner.com/easing, in particular the action script 2.0 source. From that you should be able to convert it to C#.
  • ahmd0
    ahmd0 over 9 years
    "quite optimized (no if)" Are you kidding me? Do you know how much square root function is slower than a simple if?
  • Creak
    Creak over 9 years
    That's what I said: sqr != sqrt ;)
  • Danny Yaroslavski
    Danny Yaroslavski almost 9 years
    There is some bug in the InOutQuadBlend function, specifically in the second return. For example, at t=1, the last two lines will evaluate to 2*(.5)*(1-.5) = .5, and not the expected 1. I've found the formula shown at math.stackexchange.com/a/121755 does what Creak tries to do.
  • Creak
    Creak almost 9 years
    You're right @DannyYaroslavski, I changed the formula to fix that.
  • Sir
    Sir over 8 years
    Toad, when you say t = time do you mean time from start of animation or time from previous frame ?
  • Toad
    Toad over 8 years
    t goes from 0 - 1 where 0 is the beginning of the animation, and 1 is the end. For every keyframe, you should change the values and let t again go from 0 to 1
  • starbeamrainbowlabs
    starbeamrainbowlabs over 8 years
    What is the change in value? I don't understand where that comes from.
  • Toad
    Toad over 8 years
    You first use the formula to go from keyframe1 to keyframe 2. (So b is keyframe1 value and c is keyframe 2 value). Then you let the t go from 0.0 to 1.0. By the time you are at 1.0 you repeat these steps, only now you use keyframe2 and keyframe 3
  • Milad.Nozari
    Milad.Nozari about 8 years
    This answer should get 1M thumbs ups. I looked 10 sources, found the same formula, but none of them mentioned what the hell t, b, c and d where. Thanks man
  • Myke Dev
    Myke Dev almost 7 years
    ok, I kind of understand, this, but what do you do with the returned value?
  • Toad
    Toad almost 7 years
    say you ease from the value b=8 to c=17. Then given the current t (time) in respect to the total duration(d) it returns the adjusted value which eases the motion instead of that it interpolates linearly
  • Coldsteel48
    Coldsteel48 almost 7 years
    In the last function I suppose that X is actually a T parameter of the funcrion, right ?
  • Toad
    Toad over 6 years
    Say the startvalue = 3 and you want to ease to the value 5. Then the change in value is 2. So the change in value is the endvalue - the start value.
  • TimSim
    TimSim over 6 years
    I was confused because I thought the return value was by how much the initial value (what the startValue is based on) should change, but instead it's what that initial value should become. "return change" threw me off.
  • ygoe
    ygoe over 4 years
    The second part on the original formula in solution 1 seems wrong. I don't understand it and Wolfram shows a completely wrong graph for it. The C code version is correct though but I also can't follow it. I'm trying to change this to a cubic function and am struggling.
  • Creak
    Creak over 4 years
    You're right @ygoe, I've fixed the formula and the explanation. Thank you!
  • SaganRitual
    SaganRitual over 2 years
    Tried and tested in the wild in here 2021. Looks a beaut 🙏
  • ashleedawg
    ashleedawg about 2 years
    In case anyone else in looking here are all 3 functions, in JavaScript and compressed . . . . . . . . . function InOutQuad(n){return n<=.5?2*n*n:2*(n-=.5)*(1-n)+.5} function Bezier(t){return t*t*(3-2*t)} function Parametric(t){return t*t/(2*(t*t-t)+1)} (Give 'em a number between 0 and +1 and they'll return a number between 0 and +1.)