AEJoy —— 表达式之模拟超越与反弹(二)【JS】

353 阅读2分钟

效果图

超越动画的振幅与传入动画的速度相匹配 02.gif

深入超越(Overshoot)

看一下指数衰减正弦波的基本表达式:

amp = 80;
freq = 1;
decay = 1;

t = time - inPoint;
amp*Math.sin(t*freq*Math.PI*2)/Math.exp(t*decay);

当它静止时,这个表达式将在层的 In Point 触发衰减的正弦波振荡。前三行只是设置波形的参数:

  • 最大振幅为 80,
  • 每秒一个振荡的频率,
  • 衰减值(振幅衰减的速度)为 1 。
  • 变量 t 用于计算从层的 In Point 开始的时间。

所有真正的数学都在最后一行。

最后一行有三件事。Math.sin() 产生一个频率为 freq 的正弦波,其振幅在正负一之间变化。Math.exp() 块生成一条曲线,它以由变量 decay (衰减)确定的指数速度增长的。正弦波乘以 amp(振幅)变量,结果除以指数曲线的值,得到所需的指数衰减正弦波。

这是一个很方便的表达方式,有时它就是你所需要的。更常见的是,你会想要使用指数衰减的正弦波在另一个运动结束时提供一些振荡超越。诀窍是使超越振荡的振幅与传入速度相匹配。 实现这一点的方法取决于动画的性质。在某些情况下,可能会有一个动画,其中传入速度是由表达式本身决定的。例如,假设你想让一个图层在短时间内从 0 放大到 200% ,然后稍稍超越,最终稳定在 200% 。我们将设置它,使动画在图层的 In Point 触发。下面是一个基本的表达式,可以在十分之一秒内将图层从 0 缩放到 100% ,从图层的 In Point 开始:

t = time - inPoint;
startVal = [0,0];
endVal = [200,200];
dur = 0.1;
linear(t,0,dur,startVal,endVal);

计算超越(OverShoot)

现在我们要加一些超越。在本例中,由于进入动画是由一个 linear() 函数生成的,我们可以很容易地计算进入超越的速度。结果是,速度只是结束值减去开始值,除以持续时间,在本例中是

(endVal - startVal)/dur 

因此,我们需要修改放大表达式,使它向上倾斜,直到到达 endVal ,然后切换到超越振荡。

最后一个表达式是这样的:

freq = 3;
decay = 5;

t = time - inPoint;
startVal = [0,0];
endVal = [200,200];
dur = 0.1;
if (t < dur){
  linear(t,0,dur,startVal,endVal);
}else{
  amp = (endVal - startVal)/dur;
  w = freq*Math.PI*2;
  endVal + amp*(Math.sin((t-dur)*w)/Math.exp(decay*(t-dur))/w);
}

注意,从线性上升到超越振荡(发生在第 5 帧)的过渡非常匹配

image.png