分析ae阻尼振动表达式
接上回, 网上广为流传的ae万能弹性表达式, 在完全不理解的情况下, 其实不一定生效.
本文会通过解释表达式, 来分析表达式的效果, 什么情况下使用表达式.
更深一步可以知道如何修改表达式来应用到本不可以用到的场景.
表达式解析
1 | const amp = 0.1; |
表达式先贴出来, 接下来我们会逐行读代码分析意义并总结使用效果和场景.
代码的运行环境和意义要去看上篇文章.
概述
这是一个与阻尼振动的s-t函数结合的ae表达式, 阻尼振动的场景用在表情角色的身体抖动上.
身体进行了一定加速后突然停止, 皮肤表面的振动就很接近阻尼振动.
另外荡秋千/钟摆的物品形成的接近简谐运动就是阻尼振动, 阻尼为0时的函数.
首先我们要明确简谐运动的s-t函数是个余弦函数, 阻尼振动是在此基础上变化, 所以会有余弦函数的一些变量.
变量介绍
表达式里有一些变量, 我们要明白他们的意义:
- amp(amplitude): 振幅系数. amp本身是振幅, 但在这个表达式里解释为振幅系数, 之后会细说.
- freq(frequence): 频率.
- decay: 减速系数.
上面这些是与正弦函数相关的参数, 还有一些表达式里使用的变量, 在看变量前要先理解表达式做了什么:
- 假设一个动效, 人物的脸从a移动到了b.
- 那么b点人物制动以后, 脸上的肉会因为惯性开始振动. (受力分析和方向先不讨论)
- 那么我们把b点(运动结束的kf)称作”起振点”.
- 无论b点以后是否有后续kf, 表达式会把”以b点初速度方向的阻尼位移”作为后续属性值的增量. (如果没有后续kf, 表现就是在b点的属性值上做加减.)
我们以刚才的”起振点”概念, 来继续理解其他3个变量:
- n: 起振点的kf索引. 即”起振点是第几个关键帧”.
- t: 以起振点作为原点, t轴的值.
- v: 起振点初速度.
读代码
第一部分: 正弦函数参数的变量设置, 使用者可以调整这些变量来修改效果.
第二部分: 把上一个kf作为”起振点”, 算出n和t的值.
第三部分: 把起振点初速度 * 振幅系数
作为振幅, 代入阻尼振动的s-t函数. 作为增量加到属性值上.
那么为什么要把起振点初速度 * 振幅系数
作为振幅呢, 这点我觉得值得深入讨论一下.
初速度的讨论
这个初速度需要深入说两点:
- 初速度是个矢量, 其实s-t图的s也是个矢量, 所以公式里光乘以振幅系数是得不到矢量的.
- 如果b点后面还有kf, 那么b点是不可导的, 这个速度其实是s关于t在b点的左导数.
说到这里, 没有理解ae表达式执行环境的读者已经坐不住了.
这里的value根据不同属性, 可以是值, 也可以是数组. (表达式最后的value也比较特殊, 还是得去前一篇文章看执行环境的介绍)
当value是一个数组(比如表达式是关于位置的情况下), +
操作符的执行其实还附带map()
的效果.
当velocityAtTime()
的返回结果是个数组(矢量), value的+
也会获取v
的对应维度来进行加减.
如此这样, 位置属性被有方向地加上了 由t经过函数得到的s 的增量 了.
表达式效果总结和使用场景
由上面的分析可以知道, 这个弹性公式是适用于不同属性的. 在二维属性上, 还是支持矢量增量的.
除了位置, 弹性公式还可以应用到缩放上. (其他属性还不知道, 因为我电脑没有ae)
表达式功能总结: 根据每个关键帧的初速度, 给后续帧加上阻尼振动公式产生的增量. 并且有以下特点:
- 如果只有2个kf, 效果是第二个kf后属性值会正负振动, 减缓到0.
- 如果有多个kf, 第二个后的每个kf都会振动, 这个振动会叠加到属性值的变化上.
- 如果有多个kf, 在振动还未减缓到0前就进入了下一个kf, 这个振动不会带入下一个kf.
这个公式应该还可以用到角度, 透明度, 缩放, 锚点上. 颜色行不行我还不知道.
在理解了这个公式的含义后, 进行操作, 应该可以做到路径/颜色的弹性, 也可以做到确定某个kf后做弹性.
阻尼函数简单解释
那么还剩一个问题, 阻尼函数是怎么得到的? 公式的正确性是很重要的, 公式不对动效就会不自然, 虽然用户说不上哪里有问题, 但用户会说”感觉不生动”.
要推出物体的s-t函数, 就需要一定程度的物理知识和数学知识, 我对数学知识忘记得比较多, 于是看了<<普林斯顿微积分读本>>来复习并记录一下, 这里微分和积分的概念引入都会用运动物体s-t变化为例讨论.
微分
有一个物体在运动, 路程-时间
(s - t) 的关系是: $$s = f(t)$$. (如果全程能脑子里想着图像会更好理解)
现在我们想求一个 瞬时速度-路程
(v - t) 的函数. 于是在t轴上取一小段时间, 称作 d.
来算一下 v - t 关系: $$v_{瞬}=\frac{f(t + d) - f(t)}{d}$$. 这个式子中, d越小, 瞬时速度就越精确.
当d趋向于无穷小的时候, 这个(v - t)函数就是精确的了: $$v=\lim_{d \to 0}\frac{f(t + d) - f(t)}{d}$$.
而每次都写limit很麻烦, 我们用$$\mathrm{d} s$$和$$\mathrm{d} t$$来代表 d 趋向于0的时候, s 和 t 的变化.
上面的式子有了个等价的写法: $$v=\frac{\mathrm{d} s}{\mathrm{d} t}$$. 意思是速度等于在很小的时间段里, 路程和时间的比值.
故事说完了, 接下来我们总结一下并提炼一些概念.
- 上面这种关于原函数 $$f(t)$$ 的”斜率函数”, 称作 $$f(t)$$ 的导函数, 记作 f’(t).
- 导数的计算方法是, 取一段 $$f(t)$$ 的变化, 除以 $$t$$ 的变化, 计算变化值趋向于0的极限.
所以, 基于 $$s = f’(t)$$, 以下几个概念是等价的:
$$v=f’(t)=\lim_{d \to 0}\frac{f(t + d) - f(t)}{d}=\frac{\mathrm{d} s}{\mathrm{d} t}$$.
描述为: v是s关于t的导数.
我们会发现, 速度也是会随着时间变化而变化的, 这种变化用导数表示也很容易, 只要把$$\frac{\mathrm{d} s}{\mathrm{d} t}$$当做之前的$$s$$处理.
学过物理的我们已经知道这正是加速度, 这种把导数关于$$t$$再次求导数的结果成为二次导数, 记作$$f’’(t)$$:
$$a=f’’(t)=\frac{\mathrm{d}\frac{\mathrm{d}s}{\mathrm{d}t}}{\mathrm{d}t}$$. 这个式子其实是没法简化的, 于是我们把他规定写成: $$\frac{\mathrm{d}^2s}{\mathrm{d}t^2}$$.
描述为: a是s关于t的二阶导数.
导数是可以多阶的, 可以记作: $$f^{(n)}(t)=\frac{\mathrm{d}^ns}{\mathrm{d}t^n}$$.
导数的求法有2种, 一种是根据定义代入求极限, 另外一种是根据定义得出的一些运算法则, 基于第一种的结果求导.
积分
积分的主角变成了 $$v=g(t)$$. 在知道 (v - t) 函数的前提下, 我们想求 t 从 a 到 b, 物体经过的路程.
如果速度是个常数, 保持不变的, 我们是知道 $$s=v*t$$的, 但在别的任何情况下, 我们就要进一步思考了.
于是我们的思路是: 把面积切成一个个长条, 计算长条的面积和.
在长条的宽无限小, 数量无限大的情况下, 长条的面积是个长方形了, 而面积的和就等于要求的面积. (非常不严谨, 要用夹逼定理)
并且我们(并不是)又发明了一个新符号来表示积分: $$\int_{a}^{b}f(t)\mathrm{d}t=\lim_{n \to \infty} \sum_{j = 1}^{n}g(c_{j})(t_{j}-t_{j - 1}) $$.
其中, $$c_{j}$$代表在$$[t_{j}, t_{j - 1}]$$区间里的时间, 并且 $$a < t_{0} < … < t_{n} < b$$.
这个式子挺复杂的, 还需要下面的话描述, 才是完整的式子.
和微分一样, 第一种求积分的方法, 就是利用定义求积分了, 定义里无限方块的面积和叫做黎曼和.
使用这种方法求积分相当麻烦, 需要一边代入, 一边思考式子的意义, 再采取正确的简化.
还有一个别的求积分的方法, 需要用到微积分的2个基本定理.
第一条: 图形面积的变化, 其实就等于围面积那条函数.
我们用之前的例子举例. 路程s随着时间t的变化, 其实就是速度, 就是函数v.
假设 $$s=f(t), v=g(t)$$ , 那么 $$s’=f’(t)=g(t)=v$$ .
我们再来观察$$s=f(t)$$, 通过时间t求面积的时候, 自变量实际意义上是积分的上限, 而长方形的面积的表示可以换一个字母来区别于自变量t了: $$s=f(t)=\int_{a}^{t}g(x)\mathrm{d}x $$.
第二条定理是: 一个函数从 a 到 b 的定积分, 等于 反导数(b) - 反导数(a).
用图像来看就是 0~b 的面积 减去 0~a 的面积, 就是 a~b 的面积了, 比较好理解.
其实不写积分的上下限也可以表示”函数的反函数”, 不确定积分的上下限, 只会差一个常数C.
这种形式叫做不定积分, 我们用这个形式来表示”函数的反函数集合”.
即: $$\int g(t)=f(t)+ C$$, 可以用这个理解下: $$\int v = s + C$$
微分方程
微分方程是方程的一种, 所以方程是干嘛的, 他就是干嘛的, 只是有微积分的符号.
那微积分符号是用来干嘛的? 用来把一个物理量拆解成基础量, 减少变量的.
相对地, 微分方程会有一些被推出来的定理和运算规则, 偶尔能解决一些问题, 但总的来说, 微分方程比较难解, 符号不容易化开.
下面开始阻尼的公式分析, 就会对微分方程有所体会了.
阻尼振动分析
理想的阻尼振动受力分析很简单, 弹簧的力和阻力. 设位移是x.
弹簧的力和位移有关: $$F=-kx$$. 阻力和速度相关: $$f_{阻}=-\gamma v_{x}$$. 这2个式子和牛二联立:
$$F=ma=-kx-\gamma v$$ . $$m\frac{\mathrm{d}^2x}{\mathrm{d}t^2}=-kx-\gamma \frac{\mathrm{d}x}{\mathrm{d}t}$$.
怎么解方程好复杂不想看了, 方程的解是 $$x=Ae^{-\beta t}cos(\omega t+\varphi) $$.
如果能看到这里, 你肯定发现这个解和ae表达式里的不同.
表达式里的公式是: value += $$vAe^{-\beta t}sin(2\pi f t)$$. 有三处不同, 稍作解释:
- A乘了一个v, 上面有提到, 原函数的x是忽略方向的, 需要v来提供表达式的位移方向.
- $$\omega$$ 是角频率, 所以要把我们设置的f乘一个$$2\pi$$.
- 原函数是余弦函数, $$t=0$$处的值是A. 我们令$$\varphi = \frac{\pi}{2}$$, 余弦就变正弦了.
(本文完)
如果你可以 点击这个链接打赏我5毛来鼓励我, 非常感谢.
本文遵循 cc协议
你可以在注明出处和非商用的前提下任意复制及演绎