“这是一篇非编程向、数学向、物理向的技术探讨小文,一切从视觉效果出发,向设计师朋友们介绍如何通过表达式而不需要手动K帧的方式来实现真实细腻的铃铛摆动动画。”
前言
这是一篇非编程向、数学向、物理向的技术探讨小文,一切从视觉效果出发,向设计师朋友们介绍如何通过表达式而不需要手动K帧的方式来实现真实细腻的铃铛摆动动画。请编程高手、数学课代表,物理老师自觉忽略其中不科学、不正统的细节,同时有好的方法也希望不吝赐教,至于我能不能看懂就随缘吧。
正文
在一个阳光明媚的下午,我在生产力工具iPad上看剧,频繁的消息提醒让我不得不注意到了这个按钮:
精巧的物理动效让我瞬间流下了没有技术的泪水。痛定思痛,我开始琢磨如何来实现这个动效,当然第一时间我肯定想到了万能的K帧,然后付诸了行动,步骤和最终效果如下:
1、绘制铃铛
2、整理图层关系。使用AEUX插件将在Sketch中绘制的铃铛图标同步到AE中,用AI绘制的铃铛也可以导入到AE中(具体操作请咨询搜索引擎),设置合成帧率为60帧/秒(为体现动画细节和便于计算,本文全部案例的合成均为60帧/s),并将图层关系组织成下图的样子,组织完毕将在合成窗口中得到右侧的图形。
3、打关键帧。设置铃铛罩的旋转中心点并在旋转属性上打下关键帧,由于铃铛芯是被罩子带动而进行摆动的,所以复制罩子的旋转关键帧粘贴到铃铛芯并往后一点错位放置,利用两个部件运动的时间差就能做出铃铛罩子先动带动铃铛芯后动的效果。如下图所示:
4、播(bē)放。动画效果如下:
显然这样的效果没脸说精巧,铃铛晃动几下就停了,如果想持久一点就需要打上更多的关键帧,还要保证从动画曲线上看这个衰减过程是平滑有规律的,可是我拿什么保证呢?我这么懒怎么可能给你手动K那么多帧,我再一次流下没有技术的泪水…
后来我就想到了表达式——在AE大神之间流传的一种独门秘法,传说只要写几行代码,就能自动生成行云流水的动画。
于是,我开始为此求索。
在AE中图层或图形的属性都会对应一个或者一组参数,动画的本质就是特定属性参数的持续变化。比如,一个图形在1秒内顺时针旋转了90度,即该图形的旋转属性(Rotation)参数在1秒内在初始值的基础上累加了90,当我们按住Alt键并点击旋转属性左端的小秒表时就会在右边原来打关键帧的区域出现表达式的输入框,在这个框中输入数值,就相当于把这个值赋给所对应的属性,在旋转属性下的表达式输入框中输入90就表示该图层/图形的旋转角度为90度,即便时间指针走动,它依然保持90度,这种情形下这个图层/图形是静态的。
但如果我们输入的是一个公式,这个公式能根据某个参数变化产生不一样的值,比如能根据时间的变化(时间指针的走动)持续计算出新的结果,那动画就产生了,这个公式就是表达式了。举例,我们在旋转属性下填入以下公式:
time*90;
如上图,time是AE系统时间变量(即那根走动的指针),从0开始累加,当累加到1的时候表示时间从0秒走到1秒,time*90则意味着在1秒时间内,该图层/图形旋转角度从0度逐渐变成90度,再走0.5秒,就再旋转45度。
路漫漫其修远兮,我了解了表达式的基本用法,但是想更进一步却毫无头绪。我要通过一个怎样的表达式产生出一组连续的运算结果使得铃铛来回摆动呢?
直到又在一个阳光明媚的下午,我看着那K帧的一波三折的动画曲线脑海中突然闪过了高中数学,等等,这根线有点眼熟,对,没错,是他就是他,我们的朋友正弦函数!
很快的,我实现了一个永不停摆的铃铛罩子,用到的表达式只有一句:
r=Math.sin(time*10)*100;
Math.sin是AE中正弦函数,忽略上图里的公式,简单解释一下time*10是为了使铃铛摆动的频率更高,*100是为了使铃铛摆动的幅度更大,也就是旋转的角度更大。效果如下:
作为一个上大学就永别了数学课的文科生,面对这熟悉又陌生的波浪线,这一次,流下的是没有文化的泪水…我要怎么做才能使这波越来越平、越来越平、直到变成男的呢?
我首先想到了减法,在公式后面加上一个跟随time变大的减数,比如r=Math.sin(time*10)*100-time*10,随着时间值越来越大,r的值也会越来越小,那不就是我想要的摆动幅度越来越小的效果吗?但事实是r值越来越小却不会停留在0附近,它会变成越来越小的负数,铃铛就会往逆时针方向继续甩下去,如下图:
接着我就想到了除法,没办法,中学数学水平的人只会下意识地去小学数学的加减乘除里找出路,比如把公式改造成r=Math.sin(time*10)*100/(time*10),老师说分母越大分数越小,但我又很快意识到time为0的时候,分母/除数就等于0了,小学数学老师说,这是不行的。但如果再给除数加上1,r=Math.sin(time*10)*100/(time*10+1)不就避免这个问题了吗?经过实测,我们确实得到了一条逐渐变平的波浪线,但线性增大的除数使r值的衰减过程非常缓慢,像一个永远不能达成的减肥计划一样,这个波变平的时间非常漫长,铃铛会在较剧烈晃动几下之后持续摆动许久,根本停不下来…
-
注:放大看r=Math.sin(time*10)*100/(time*10+1)得到的运动曲线,几乎没有要衰减的意思
很显然,小学数学已经不能帮到我了,我又开始翻阅资料,也直接去翻看了物理学中简谐运动和单摆运动的词条,没看完我就乖巧地回来了,还是高中数学好懂,却意外地接触了高等数学,“exp,高等数学里以自然常数e为底的指数函数”百度百科如是说,函数Math.exp(x)等于指数e的x次方,e≈2.7,当我们把x替换成time,就算time为0,用来做分母的Math.exp(time)也不会等于0,同时,用它做除数/分母它的增长是非线性的指数增长,就像你的年纪跟体重的关系一样,年纪越大,发胖的速度越快,一如下图:
至此,我在感慨岁月是把猪饲料之余,用以下表达式,我们终于得到了一条这样的曲线和这样的动画。
r=Math.sin(time*10)*100/(Math.exp(time))
-
铃铛罩摆动至停止动画(录屏动画掉帧比较厉害,建议查看工程文件)
接下来要实现的就是铃铛芯的摆动,跟K帧动画思路一样,同样要对铃铛芯做一个延迟动画,通过观测发现,客观上,在这个60帧/s的合成里,当指针刚走1帧,铃铛罩子“内壁”就已经挨到了铃铛芯,故延时时间可以设为1/60≈0.0167s。但主观上,我为了数字更简洁就再约等于一下,直接写成0.02s,所以我宣布铃铛芯最佳的延时时间是0.02s,没有异议!
一个公式可以是一个表达式,但一个表达式却可能包含不止一个公式,AE表达式的编写语言基于JavaScript,所以除了算术运算,还会有逻辑运算(且容我在胜利在即的时候正式地装会儿逼)。复用罩子摆动的表达式,替换上延迟的时间并作条件判断,芯子的旋转属性下的表达式为:
delay=0.02;//定义铃铛芯开始运动相对于罩子延时0.02s delay_t=time-delay;//结合上一句,铃铛芯的时间应减去0.02s的时间差 if (time>delay){//如果时间大于0.02s时 amp=100;//定义铃铛芯的振幅初始值为100 r=Math.sin(delay_t*10)*amp/Math.exp(delay_t);//铃铛芯可劲儿嗨 } else{ r=0; };//时间小于0.02s时,铃铛芯旋转角度为0,就是时机不到按兵不动 r;//表达式最终需要传出一个或者一组参数给到相应属性,涉及到较多的运算时,最后最好再把变量名/参数拎出来一下,不然它可能会迷路
动画效果如下,铃铛终于在我精妙表达式的驱动下放肆摇摆了,我仿佛听到了“叮叮当、叮叮当、铃儿响叮当”的美妙歌声:
-
铃铛芯运动衰减比较快
我终于准备放下电脑重新举起生产力工具的时候,又瞅了眼iOS的小铃铛,几番对比,我长叹一口气,最后郑重地决定把装逼这件事再往后放放。定睛看,iOS的小铃铛芯在罩子已经甩不动的时候依然活力充沛地甩了好几个来回,这个细节更真实地还原了物理世界的情形——小铃铛的内芯比“外表”要浪得多。
我这里忍不住要插一句有点离题的话,我一直有一个观点(说“一直”纯粹是为了烘托我的英明神武):iOS在静态视觉层面抛弃拟物化多年,但在动效上的“拟物化”却始终如一地做到精准且统一,这就是苹果味儿。即便在iOS代码质量越来越咖喱味儿的今天,动效上体现的苹果味儿却始终没变,没人逼我一般不吃苹果,但苹果产品却因为这种气质每次出新都让我有下单的冲动,不过贫穷使人清醒…
我还是继续写小文吧,我如何才能做到苹果年年出新我年年换新呢,哦不,我如何才能让我的小铃铛芯比罩子更浪呢?这次,我终于如愿地用上了小学数学,我在时间大于1秒时强行加大芯子的摆动幅度, amp=time*50+50,这种写法保证时间刚好在1秒时,amp的值仍然是初始值amp=1*50+50=100,这样1秒前后的动画曲线就会顺滑衔接,动画当然就不会出现跳跃。类似的写法还有:amp=time*75+25,甚至直接是amp=time*100,同样能保证1秒处的自然衔接,但是这个芯子浪的有点过头,所以,我决定还是让它矜持一点,维持了amp=time*50+50的写法。
delay=0.02; delay_t=time-delay; if (time>delay){ amp=100; r=Math.sin(delay_t*10)*amp/Math.exp(delay_t); if (time>1){ amp=time*50+50; r=Math.sin(delay_t*10)*amp/Math.exp(delay_t); }; } else{ r=0; }; r;
-
铃铛芯运动衰减变慢
对比上一个比较安分的铃铛芯(黄色),红色是更浪的铃铛芯,从曲线部分也可以看出红线在一开始规规矩矩与黄线完全重合,后面就逐渐冒尖勇敢做自己。
-
铃铛芯优化前后对比
- 调速过后的铃铛
把最终版的铃铛动画调速过后就更自然了, 到这里我终于可以叉会儿腰了吧。
后记
还在一个阳光明媚的下午,我在熬了几个夜之后终于写到了这里,手打3800字的文章加繁琐的视频转GIF来配图,终于流下了心力交瘁的泪水…但这仅仅是个开始,在完成铃铛摆动动画之后,我又用表达式实现了几种最常用到的弹跳动画,有兴趣的话可以关注我、催促我、赞助我、贿赂我、包养我,我将会在下一个阳光明媚的下午继续为你分解。
另外,关注我公众号“好像不明白”并回复“铃铛”可领取案例中的全部工程文件哦~
Powered by Froala Editor