对于一个兼职程序员的动画设计师(实际上就是个会 AE 的码农,还是二手的)来说,使用关键帧来设置动画是比较少的情况,虽然一开始操作的时候,使用关键帧设置可以快速上手粗略的调整出想要的动作,但是在项目实际执行过程中总是不免改来改去,关键帧打多了,修改起来就如同地狱一般。
![v2-bdd64402a7c99a27b56e4ed98956826e_b.gif](https://img-blog.csdnimg.cn/img_convert/583f97ac0b19cfa6c0dd40a37729a4f5.gif)
举一个例子,如果上面的这个动画要调整动画进入的持续时间,你要怎么修改?因为这里面实际包含了五组动画依次执行:
- 圆点缩放进入;
- 两个圆点水平位置拉开;
- 直线变长;
- 中文标题进入;
- 英文标题进入。
如果使用关键帧,并且这些属性分布在不同的图层,再去调整它们会是灾难性的,而且这里的插值还不是线性的,而是 easeOut,极有可能在操作的时候,插值方式自己发生改变。作为一个二手码农,一定要多用表达式做动画,因为表达式更具有复用性。
温馨提示:这篇教程里面不需要太多数学知识了,所以放心玩儿吧!
先看时间线,有一个大概的了解(一个关键帧也没打!):
![v2-5108d93f71b19219744ab531461e2c94_b.jpg](https://img-blog.csdnimg.cn/img_convert/bd9bd7b8477487f6890968b34c2a4733.png)
图形动画都在一个形状图层里面,时间线设置了合成 Marker,这个区间标记方法是之前一篇文章有同学在评论中问过,你可以设置一个标记,然后按住 Alt 拖拽成区间标记,通过表达式可以读取 time 和 duration 属性,time 就是开始时间,duration 就是持续时间,没有结束时间,因为结束时间 = time + duration,时间单位为秒。
通过这两属性可以设置总体的动画进入时间,还有持续时间,然后每一个动作的执行时间使用 duration 的百分比来控制。
![v2-00c50e141cecf305e6f1073553b645f4_b.jpg](https://img-blog.csdnimg.cn/img_convert/fe102288b3689cc3b77bb7aa421a7c6a.png)
首先看两个圆点。在形状图层添加两个表达式控制效果,它并不产生实际效果,只是用来为表达式提供索引的值,这里使用的是滑块控制,它可以设置单一维度的值。
![v2-95387cf49a843fa3a94b3b6f9aff5cb7_b.jpg](https://img-blog.csdnimg.cn/img_convert/f845e115ad161f011bd62df8ff9c58da.png)
圆点的缩放动画是第一个动画,就是出现的时候先让它从无到有,直接看代码:
![v2-64dc358446e38615ae6b78937b0c9f9d_b.png](https://img-blog.csdnimg.cn/img_convert/cb0ffec10b52726fd66fa4e52855eaa6.png)
// 读取合成 marker 的开始时间,作为动画的开始
let _start = thisComp.marker.key(1).time
// 读取合成 marker 的持续时间
let _duration = thisComp.marker.key(1).duration
// easeOut(t, tMin, tMax, value1, value2) 是插值方法,_start 就是当前动画开始的时间(tMin)
// _duration * .05 就是这个动画持续的时间,它的意思是按照总动画时长的百分之五执行
// 然后需要加上开始时间 _start 才能得到当前动画的结束时间(tMax)
// 参数 t = time 即保持与合成时间同步
// value1 设置为 0,作为第一个关键帧,第二个关键帧直接使用当前设置的值
// 这样就可以不需要设置关键帧,直接设定结束的值就可以
easeOut(time, _start, _start + _duration * .05, 0, value)
在椭圆路径的大小属性上调用的时候,因为是一个正圆形,因此可以直接简写为:
// Array(2) 即建立一个长度为 2 的空数组,然后使用 fill() 方法填充值为上面设定的值
// 将插值方法写在索引值里面也是避免每一次引用都要重新写一次,非常方便
Array(2).fill(effect("圆点尺寸")("滑块"))
直线动画中,直线延长的时候,两个圆点的位置也同步变化,实际上是圆点位置变化生成了一条直线。先看设置:
![v2-716946f0f7de00b66a8ad1fc9fe80704_b.png](https://img-blog.csdnimg.cn/img_convert/2062a6cdd4158d3db55bfdb0f10ae712.png)
let _start = thisComp.marker.key(1).time
let _duration = thisComp.marker.key(1).duration
// 这个动画紧接着上一个动画执行,然后在 35% 处结束
// 线长的取值能容纳文本就可以了,而且可以根据不同的文本字符数量实际调整
easeOut(time, _start + _duration * .05, _start + _duration * .35, 0, value)
AE 比较麻烦的一点是变量作用域比较小,只能在当前属性表达式中调用,一旦跨属性,则需要重新定义,当然之前也讲过一些全局变量的设置方法,但是实测中稳定性并不是很好,坑比较多。
下面我们来看看两个圆点和直线路径的生成方式:
![v2-c7788d997cb6f66708602b3c22f5527b_b.jpg](https://img-blog.csdnimg.cn/img_convert/ce2b05ca7e4197c812d151f1bf4bceb1.png)
两个圆点使用了中继器,原始的圆点从原点向左水平运动:
[effect("线长度")("滑块").value * -0.5, 0]
中继器复制的圆点以原始路径为参照,所以它距离原始路径的距离始终等于设置的“线长度”,因此要向右移动:
[effect("线长度")("滑块").value, 0]
直线路径使用 Path createPath() 方法绘制,路径的两个点分别是两个圆点的位置:
![v2-1ccc7066c273b03b70a6932c08272ae3_b.jpg](https://img-blog.csdnimg.cn/img_convert/b04f4ca14c4caf3105821bbedb5b67de.png)
// 第一个点是圆点的原始路径位置,第二个点是以原点为中心的镜像,
// 因为 y 值一直设置为 0 ,所以直接使用矢量数学方法中的矢量乘法 mul() 方法
createPath(
points = [
content("圆点").content("椭圆路径 1").position,
mul(content("圆点").content("椭圆路径 1").position, -1)
],
inTangents = [],
outTangents = [],
isClosed = false
)
描边宽度设置为原点尺寸的 10%(这个不重要,你愿意怎么设置都可以):
effect("圆点尺寸")("滑块").value * .1
到这里,所有图形动画设置完成,占用动画成体时长的 35%。
![v2-1abae68ff0fc7af577ed97cfad26eb28_b.jpg](https://img-blog.csdnimg.cn/img_convert/3d189d91af435947710fa78cd9770614.png)
主标题文本动画是按字符,每个字位置向上运动到目标位置,文本动画的设置方式比较简单,只需要设置偏移位置,然后使用范围选择器就可以完成。
let _start = thisComp.marker.key(1).time
let _duration = thisComp.marker.key(1).duration
// 35% 至 75%
easeOut(time, _start + _duration * .35, _start + _duration * .75, 0, value)
便宜位置使用了文本字体尺寸做了一个简单的处理,因为大部分文本的基线位置并不在正下方,因此乘以 1.25 的偏移系数可以避免错误。
[0, text.sourceText.style.fontSize * 1.25]
动画做好以后,还需要使用蒙版隐藏直线下面的部分,蒙版一般我习惯用形状图层而非路径蒙版,主要还是设置比较方便,你可以像这样直接使用表达式设置参数:
![v2-7a7beab90c75c0c36231c5bd4c1e958d_b.jpg](https://img-blog.csdnimg.cn/img_convert/c10215006fe42158da6b1f5dfb1db087.png)
// 蒙版大小为画面的一半高度
[thisComp.width, thisComp.height * .5]
然后调整一下位置:
[0, thisComp.height * -.25]
![v2-60e5401f9c2e749f8a250e383e124e8b_b.jpg](https://img-blog.csdnimg.cn/img_convert/c5af5ad6c36c5f9f15f2c0ce2763135e.png)
![v2-c620db2c6876ae2b8812a95e38dc9b10_b.jpg](https://img-blog.csdnimg.cn/img_convert/e2b1cf891d65b59a464266bd52e0be53.png)
英文标题的蒙版与上面相同,可以使用属性关联器进行同步,然后使用反向 Alpha 通道:
![v2-a740dabc25f7bdb739cdbd6feead43c2_b.jpg](https://img-blog.csdnimg.cn/img_convert/b53d447b43c0271c36614a8c0a099e88.png)
英文标题的动画比较简单,只是一个 y 位置的变化,定位方法还是根据字体尺寸自动计算:
let _start = thisComp.marker.key(1).time
let _duration = thisComp.marker.key(1).duration
easeOut(
time,
_start + _duration * .8, // 延迟执行 5%
_start + _duration, // 完整结束
// 初始位置从画面垂直中心再向上多偏移一些
[value[0], thisComp.height * .5 - text.sourceText.style.fontSize * .5],
value
)
![v2-91d6735af6017d2589401516bf13aff5_b.gif](https://img-blog.csdnimg.cn/img_convert/6153eaa8fe030e3a1975fa51bd267033.png)
这样整个动画过程就完整了,在父级合成中调用动画可以通过更新源标记来清楚的查看到动画设置情况,方便应用。
![v2-079680604dba9d0614fd2f201701e764_b.jpg](https://img-blog.csdnimg.cn/img_convert/c65bed8ca006fd79067df98f8d2d0e35.png)
就这样,先到这儿,工程文件下载链接(2021版本):
文本动画控件.aep有啥想聊的想问的或者想要我再写文章的可以在评论区留言~