【AE表达式】制作windows加载动画

/*表达式文末自取,以下为整体思路*/

分析
很容易看出加载动画是由很多圆跟着一个圆旋转一圈,形成延迟或拖尾的效果;
每个圆的角速度都是慢-快-慢的循环,每经过一次角速度的循环周期,该圆刚好转过360°;
圆的不透明度变化与角速度变化相反

思路
角速度周期变化可以用函数1-cosX解决/*1-cosX恒大于等于0,这意味着圆不会走到一半突然调头跑,它的速度始终为正*/
至于让每经过一次角速度周期刚好转过360°,只需要先通过角速度公式确定角度公式/*根据导数找原函数*/
再使自变量变化一个周期时因变量变化360°
不透明度用linear直接把角速度线性映射过来
延迟效果用 .valueAtTime(time-延迟时间) 很容易实现,但本文选择改变三角函数的相位
//表达式生成动画只需要在一个图层里写表达式,然后ctrl+DDDDDDDDDDDDDD…
//现在你只需要打开AE-按住shift画一个正圆-保存项目-关闭AE就好了

实现
1·确定角速度公式和角度公式(之后直接写在形状图层的旋转属性里)
角速度公式为1-cosX肯定是不行的
先给它加点参数成为a*(c-b*cosX),注意c>b
//方便之后化简调参
为了确定每个参数对角度变化的影响
把它还原成角度公式a*(c*X-b*sinX)
这个角度公式图像持续向上,符合每个圆持续向一个方向旋转的效果

但该函数周期固定,不便控制,于是引入参数f
将X变为fX
角度公式更改为a*(c*fX-b*sinfX)
角速度公式改为 a*f*(c-b*cosfX),f表示频率
/*凭啥f就表示频率呢,我们先把频率定义为单位时间内转过的圈数
没有f时,X从0增加到单位时间时,刚好转一圈
加上f后,X从0增加到单位时间时,函数中sin()括号里的数实际增加至f倍的单位时间,则因变量增加至f倍,也就是转了f圈
既然单位时间内转了f圈,就认为f表示频率*/
//你想懂?我这下面有些好康的


2·化简消参,使每周期转一圈
f表示频率,则2π/f表示周期
角度公式a*(c*fX-b*sinfX)
//JavaScript里Math.sin()括号里使用弧度值,所以这里周期为2π/f
X=0时,角度为0
X=2π/f时,角度为2π*a*c
则2π*a*c-0=360
//角度公式返回值应为角度制,所以为360°
所以只要满足a*c=180/π,该效果就可以实现
//接下来所有计算都基于a*c=180/π的条件下,即实现每周期转一圈的前提下
我们回到角速度公式a*f*(c-b*cosfX)
探究如何进行速度控制

思路一/*理解简单但不好*/
a*c=180/π代入角速度公式a*f*(c-b*cosfX)得V=f*180/π-a*f*b*cosfX,减号后面是变化量,则可得出
Vmax=f*180/π+a*f*b,Vmin=f*180/π-a*f*b
发现V主要由f控制,而V最大变化差由a*b控制
则可以为控制器图层/*名叫“控制器”的图层,一般用空对象*/添加两个滑块控制,以控制f和a*b,为形状图层的旋转属性输入:
f =3/*自己连接一下滑块控制好吗*/;
ab =60/*只会复制是不行的*/;
X = time;
X*f*180/Math.PI-ab*Math.sin(X*f)
//函数部分:acfx - ab sinfx
//这个方法坏就坏在谁知道a*b什么意思啊,过于抽象

思路二/*控制Vmax/Vmin*/
根据角速度公式a*f*(c-b*cosfX)得出
Vmax=a*f*(c+b),Vmin=a*f*(c-b)
就可以看出Vmax/Vmin=(c+b)/(c-b)=1+2b/(c-b)=1+2/(c/b-1)
于是Vmax/Vmin只与c/b有关,则说明可以用一个参数代替c/b,但c/b的参数含义不便理解,于是选择用k代替Vmax/Vmin
参数k的含义即最低点速度/最高点速度,可得
c=(k+1)/2,b=(k-1)/2进而化简角度公式/*交给表达式做吧*/
同上,输入:
f = 3 ;k = 50 ;X = time;
c = (k+1)/2 ; b = (k-1)/2 ; a=180/Math.PI/c ;
a*( X*f*c-b*Math.sin(X*f))
//函数部分:a(cfx -b sinfx)
//你甚至可以把k改为负数


3·不透明度
在最高点使不透明度为100,最低点为0,恰好最高点也是速度最低点,则采用映射
映射分线性映射linear和非线性映射ease,这里用linear
/*linear(映射源,映射源min,映射源max,对象min,对象max)为线性映射,ease为非线性映射,两者参数一致*/
映射即一个量跟着另一个量变化,这里是不透明度跟随角速度变化,则在图层不透明度属性里输入:
linear(
transform.rotation.speed/*获取旋转角度实时变化速率*/,Vmin,Vmax,100,0)
//后来我发现把Vmin和Vmax调换位置并不影响效果,至今不理解
//把100和0位置互换是因为速度最低时不透明度最高
再把上面的公式拿点下来
Vmin=a*f*(c-b),c=(k+1)/2,b=(k-1)/2 可得 Vmin=a*f,则在linear表达式的上方添加:
f = 3 ; k = 50 ;
c = (k+1)/2 ; a = 180/Math.PI/c ;
Vmin = a * f ; Vmax = k * Vmin ;

4·动画延迟
/*valueAtTime的方法你肯定会*/
把代码中的X = time; 改为X = time + s * .001 * index ;
/*time返回时间线所处的时间值,单位:秒;
0.001使调节精度增加;
index返回图层序号,使每个图层延迟量不同;
s * .001 * index 即自变量的延迟量*/
不要忘了为s添加滑块控制
//valueAtTime用于拖尾动画很方便


总结
如果你喜欢的话还可以用表达式控制每个圆的大小、颜色、形状 //过于基础就不讲
一开始做这个动画的参数有f、a、b、c,后来在不断调参的过程中发现参数间的某种联系,就分析代码,最终提炼成两个参数:f和k,于是写下这个表达式基础教程
AE初学,大佬轻喷
//下面这个表达式动画是我最近一个视频里用到的思路,更基础一点,不知道需不需要出教程


代码/*与上文有一点出入*/
旋转:
f=thisComp.layer("控制器").effect("频率")("滑块");
k=thisComp.layer("控制器").effect("最大值/最小值 速度")("滑块");
s=index*.001*thisComp.layer("控制器").effect("偏移")("滑块");
Vmin=1;Vmax=k;c=(k+1)/2;b=(k-1)/2;
//Vmin/af = c - b,Vmax/af = c + b
a=360/(2*c*Math.PI);
//a=360/(2*c*PI),使每一个周期旋转360°
a*(-b*Math.sin((time+s)*f)+(time+s)*f*c)
//函数部分:a(-b sinfx + cfx);导数:af(c - b cosfx)
//V=0.5*af*(k+1-(k-1)cosfx),由导数化简所得
不透明度:
f=thisComp.layer("控制器").effect("频率")("滑块");
k=thisComp.layer("控制器").effect("最大值/最小值 速度")("滑块");
pi=Math.PI;
Vmin=f*360/(k*pi+pi);Vmax=k*Vmin;
//V = 0.5*af*(k+1-(k-1)cosfx),速度公式
//Vmin = af
linear(transform.rotation.speed,Vmin,Vmax,100,0)