正文
在上图的基础上加入一个坐标轴,这样便于观察规律。
在动画执行过程中,网格上的点会沿着一个方向缩放,我们称缩放的轴为缩放轴,图中的缩放轴是y轴。同时还需要在缩放轴上指定一个缩放中心点。在动画的第二个阶段,所有点会沿着一个方向移动,我们称这个轴为移动轴,图中的移动轴是x轴。
在动画的第一个阶段中,网格上的点只在缩放轴上移动。我们假设一个点在移动轴上的位置为movLoc,那么我们可以使用公式0.5 * 0.98 * cos(3.14 * movLoc + 3.14) + 0.5 + 0.01;计算出第一阶段结束时,该点需要向缩放中心点缩放的量。为什么是这个公式呢,我给大家贴一张图就清楚了。是不是和上面的边缘曲线有点像。图我是用Mac自带的Grapher绘制的。在调试曲线的过程中Grapher的确非常好用。公式里的0.98和0.01是相关的两个量,控制左边窄口的大小。0.01 = (1 - 0.98) / 2。动画第一阶段主要的工作就是根据当前动画的进度百分比,控制点到达最终缩放量的进度即可。
第二阶段主要就是移动轴上的移动,我们可以根据最远移动距离和当前的动画进度计算出当前点在移动轴上的位置。然后根据当前的位置计算出缩放轴上需要的缩放量。最远距离可以通过吸入点和另一侧的边界计算出来。
了解完原理我们来看Shader代码吧。Swift代码比较简单,只是生成了一个撑满屏幕的nxm网格,稍候再说。
VertexIn和VertexOut很普通,包含顶点位置和纹理坐标。Uniforms里包含了动画相关的信息,当前动画经过的时间animationElapsedTime,动画总时间animationTotalTime,吸入点gatherPoint。
struct VertexIn
{
packed_float3 position;
packed_float2 texcoord;
};
struct VertexOut
{
float4 position [[position]];
float2 texcoord;
};
struct Uniforms
{
float animationElapsedTime;
float animationTotalTime;
packed_float3 gatherPoint;
};
动画的实现都在Vertex Shader里。步骤如下。
-
计算并规范动画进度,得到动画进度animationPercent。
-
VertexOut outVertex;
VertexIn inVertex = vertexIn[vid];
float animationPercent = uniforms.animationElapsedTime / uniforms.animationTotalTime;
animationPercent = animationPercent > 1.0