c++ 缓入缓出动画公式

jv4diomz  于 2023-04-01  发布在  其他
关注(0)|答案(6)|浏览(149)

比如说,如果我在做一个物体从X1坐标到X2坐标的运动的先放松再放松的动画,以相等的时间间隔在S步内移动,有人能建议计算这个运动的X坐标的公式吗?

6ss1mwsb

6ss1mwsb1#

就我个人而言,我更愿意使用一个在[0;1]并输出[0;1],因此我们可以将结果应用于任何类型(2D向量,3D向量,...)。

溶液1

对于二次缓入/缓出,曲线根据t的值分为两个不同的函数:

  • t〈= 0.5时:f(x) = 2 * x * x其中x在[0;0.5](graph
  • t〉0.5时:f(x) = 2 * x * (1 - x) + 0.5其中x在[0;0.5](x一e1一f1 x)

以下是图表:

由于第二个函数也在[0;0.5],但是t〉0.5,当我们开始使用它时,我们需要将t减少0.5。
这是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;
}

方案二(贝塞尔曲线)

另一个有趣的混合曲线是由Bézier给出的,它的优点是非常优化(没有if)。下面是来自Wolfram的曲线:

下面是C代码:

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

方案三(参数函数)

@DannyYaroslavski提出的另一种方法是这里提出的简单公式。
它是参数化的,并得到一个很好的进/出加速和减速。
当alpha = 2时,你得到这个函数:

在C中的翻译如下:

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

c3frrgcw2#

二次缓出,其中:
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;
 };

来源:http://gizma.com/easing/

2uluyalo

2uluyalo3#

所有上述解决方案都缺乏使用示例。
找到良好的解决方案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);
    }

  });
}

用法示例:

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

其他功能:

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

更多here

huwehgph

huwehgph4#

我也有同样的问题:我想动画我的图表(Ease in-out)
Brainstorm给了我两种方法:
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)两个抛物线,不难,我就用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;
}

x=[0;1]使用这种方法,也返回y=[0;1]
现在,您可以比较这些图表:

gdx19jrr

gdx19jrr5#

这里是一个版本的曲率作为一个参数的数额,以下这个一般的解决方案链接到克里克。

/*
* 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
    }
}
iecba09b

iecba09b6#

此版本允许您使用任何缓入和缓出函数(EaseIn和EaseOut)。这两个函数都必须接受介于0和1之间的时间值参数,并返回介于0和1之间的缓入时间值。

float EaseInOut(float t)
{
    if (t <= 0.5f)
    {
        return EaseIn(t * 2) * 0.5f;
    }
    else
    {
        t -= 0.5f;
        return (EaseOut(t * 2) * 0.5f) + 0.5f;
    }
}

相关问题