AEJoy —— 表达式之弹性震动模拟详解【JS】

228 阅读1分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

效果图

102.gif

设计部分

首先添加文字,并为该文字设置了三个关键帧位置,如下所示

image.png

同时还通过 F9 增加了缓动效果

image.png

然后在位置属性上应用如下表达式

表达式与详解

具体请看代码注释

e = .7; ///< 衰减系数
g = 5000;
nMax = 9; ///< 最大跳跃次数

n = 0;
if (numKeys > 0) {
    n = nearestKey(time).index;
    if (key(n).time > time) 
        n--;
}
if (n > 0) {
    t = time - key(n).time; ///< 当前时间和(前头)临近关键帧的时间差
    v = -velocityAtTime(key(n).time - .001) * e;
    vl = length(v);
    if (value instanceof Array) {
        /// @note vl 如果大于 0 的话就对向量 v 进行归一化
        vu = (vl > 0) ? normalize(v) : [0, 0, 0];
    } else {
        vu = (v < 0) ? -1 : 1;
    }

    /// @note 根据每个衰减阶段,计算衰减时间和跳跃次数
    tCur = 0;
    segDur = 2 * vl / g;
    tNext = segDur;
    nb = 1; // 跳跃次数
    while (tNext < t && nb <= nMax) {
        /// @note 衰减
        vl *= e;
        segDur *= e;
        /// @note 更新衰减时间和跳跃次数
        tCur = tNext;
        tNext += segDur;
        nb++
    }
    if (nb <= nMax) {
        delta = t - tCur; ///< 计算剩余时间
        /// @note 加号的右半部分的函数示意图其实就是个(倒)抛物线
        value + vu * delta * (vl - g * delta / 2);
    } else {
        value
    }
} else
    value

改进与优化

为了增加趣味性,还可以加一点尺寸上拉伸的效果

102.gif

将以下表达式应用在缩放属性上即可。

freq = 3;
amplitude = 20;
decay = 1.0; 
t = time - inPoint;
x = scale[0] + amplitude*Math.sin(freq*t*2*Math.PI)/Math.exp(decay*t);
y = (1/x)*10000;
[x,y]