C# 缓入缓出动画公式
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 
原文地址: http://stackoverflow.com/questions/13462001/
Warning: these are provided under cc-by-sa 4.0 license.  You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Ease-in and ease-out animation formula
提问by ahmd0
Say, if I'm doing the Ease-Out and then Ease-In animationof 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?
比如说,如果我正在执行对象从 X1 坐标到 X2 坐标以相等的时间间隔在 S 步上的移动的缓出和缓入动画。有人可以建议计算这个运动的X坐标的公式吗?
采纳答案by Toad
Quadratic ease out where:
二次缓出,其中:
t = current time
b = start value
c = change in value
d = duration
t = 当前时间
b = 起始值
c = 值的变化
d = 持续时间
 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/
回答by Creak
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, ...).
就我个人而言,我宁愿使用在 [0; 中获得时间的函数;1]并输出[0; 1],以便我们可以将结果应用于任何类型(2D 矢量、3D 矢量,...)。
Solution 1
解决方案1
For the quadratic easing in/out, the curve is separated in two distinct functions depending on the value of t:
对于二次缓入/缓出,曲线根据 的值分为两个不同的函数t:
- when 
t<= 0.5:f(x) = 2 * x * xwith x in [0;0.5] (graph) - when 
t> 0.5:f(x) = 2 * x * (1 - x) + 0.5with x in [0;0.5] (graph) 
Here are the graphs:
以下是图表:
Since the second function is also in [0;0.5], but t> 0.5 when we start to use it, we need to reduce tby 0.5.
由于第二个函数也在[0;0.5]中,但是t当我们开始使用时>0.5,我们需要减少t0.5。
This is the result, in C:
这是结果,在 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)
解决方案 2(贝塞尔曲线)
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:
另一个有趣的混合曲线是Bézier给出的曲线,它的优点是非常优化(如果不是)。这是Wolfram的曲线:
And here is the C code:
这是 C 代码:
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.
@DannyYaroslavski 提出的另一种方法是这里提出的简单公式。
It is parametric and gets a nice in/out acceleration and deceleration.
它是参数化的,并获得了很好的输入/输出加速和减速。
With alpha = 2, you get this function:
当 alpha = 2 时,你会得到这个函数:


Which translates in C like this:
在 C 中这样翻译:
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
编辑 1:从@DannyYaroslavski 添加解决方案 3
编辑 2:对解决方案 1 的更好解释
编辑 3:向所有解决方案添加图形
回答by Egor Randomize
I got same problem: wanted to animate my chart (Ease in-out).
我遇到了同样的问题:想为我的图表设置动画(Ease in-out)。
Brainstorm gave me two ways:
头脑风暴给了我两种方法:
1) Trygonometric formula. Firstly, I wrote y=(sin(x/π*10-π/2)+1)/2,which analog is sin^2((5*x)/π)
1) 试算公式。首先,我写道y=(sin(x/π*10-π/2)+1)/2,哪个模拟是sin^2((5*x)/π)
float TrygoEase (float x) {
    float y=(float)Math.pow(Math.sin(5*x/Math.PI),2);
    return y;
}
2) Two parabolas. It was not hard. I just used y=2*x*xon [0;0.5], and y=-2(x-1)^2+1on [0.5;1]
2) 两条抛物线。这并不难。我只是用y=2*x*x的[0;0.5],和y=-2(x-1)^2+1上[0.5;1]
float ParabolEase(float x) {
    float y=2*x*x;
    if(x>0.5f){
        x-=1;
        y=-2*x*x+1;
    }
    return y;
} 
Use this ways for x=[0;1], what returns also y=[0;1].
用此为x=[0;1],何返还y=[0;1]。
Now You can compare this graphs:
现在你可以比较这个图:
回答by Alexander Poshtaruk
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
更多在这里
回答by Mattijs
Here is a version with the amount of curvature as an argument, following this general solutionlinked to by Creak.
这是一个以曲率作为参数的版本,遵循由 Creak 链接的这个通用解决方案。
/*
* applyCurve: apply an S-curve to an input value.
* The highest positive curvature will result in a step from 0 to 1,
* the most negative curvature will result in a constant of 0.5.
*
* progress: the input value between 0 and 1,
* curvature: the amount of curvature between -1 and 1.
*  Negative values curve the other way, 0 applies no curvature.
*/
double applyCurve(double progress, double curvature) {
    assert(progress >= 0.0 && progress <= 1.0);
    assert(curvature >= -1.0 && curvature <= 1.0);
    if (curvature >= 0.0) {
        if (curvature > 0.99999) return progress > 0.5 ? 1.0 : 0.0;
        float exp = 1.0 / (1.0 - curvature); // find s-curve exponent
        return pow(progress, exp) / (pow(progress, exp) + pow(1.0 - progress, exp)); // apply s-curve
    } else {
        if (curvature < -0.99999) return 0.5;
        float exp = 1.0 + curvature; // find s-curve exponent
        return pow(progress, exp) / (pow(progress, exp) + pow(1.0 - progress, exp)); // apply s-curve
    }
}

