valueAtTime的用法,Dan Ebberts 在其 MotionScript 网站上提供了示例,之前的文章复盘了简单的用法,这里再说说稍微复杂的用法。
一、
前面对valueAtTime的用法里,只是对后面的层有延迟,效果是“引导层”和后面的层同一个位置出发,然后“引导层”停下来的时候,后面的层会追上“引导层”,并且和“引导层”重叠。那么,怎样实现让所有层保持固定的距离,并且当“引导层”停下来时候,后面的层也停下来?
Dan Ebberts提供了下面表达式:
strt = 0; //start time of template motion end = 4.0; //end time of template motion t = thisComp.layer("template"); offset = (t.effect("offset")("Slider")/100)*(index -1); travel = linear(t.effect("travel")("Slider")/100,strt,end); t.position.valueAtTime(travel - offset)
步骤是:
1、建立一个null(空对象),命名为template ;
2、给null打关键帧,打出需要的运动轨迹,可以是3D空间的运动 ;
3、给template添加两个slider control ,并分别命名为offset ,和travel ;
4、新建图像层,比如五角星,给Position(位置)添加上面的表达式 ,并复制数层(复制层数多少根据需要);
5、空对象template中的两个slider control,其中offset控制的是形状层之间相隔的距离,数字越大,形状之间间隙越大,而travel则控制的是所有形状层的运动。
travel的值应该设定在0~100之间,给0~100打上关键帧,travel的变化驱动形状层组成的“长龙”的运动,其路径就是template的路径。
通过给travel打关键帧,可以控制“长龙”前进、后退、停止等。
再来分析表达式:
strt = 0;
end = 4.0;
t = thisComp.layer("template");
定义到之前建的空对象null。写表达式常用的方法,引入一个变量来定义图层位置,让后面的表达式更简洁,也更不容易出错。
offset = (t.effect("offset")("Slider")/100)*(index -1);
t.effect("offset")("Slider")定位到的是空对象“template”下添加的effect(效果)“Slider”下面的“offect”,这个数字除以100,添加分母见效其值的范围。
travel = linear(t.effect("travel")("Slider")/100,strt,end);
linear(t, tMin, tMax, value1, value2)只有3个参数值时候lineat(t, value1, value2), 是将tMin默认为0,将tMax默认为1 。
也就是t在0~1之间变化时候,返回值在value1~value2之间进行线性插值运算。
在这个表达式里,t.effect("travel")("Slider")定位到的是空对象“template”下添加的effect(效果)“Slider”下面的“travel”,除以100,其值在0~1之间。
此处linear的表达式,是当Slider control下的travel在0~100之间变化时,其返回值在0~4之间线性变化。
t.position.valueAtTime(travel - offset)
t.position是定位到空对象“template”的位置,valueAtTime调用不同时间的位置值。
我们可以从时间的维度来理解这个表达式:
先不引入offset,直接写thisComp.layer("template").position.valueAtTime.travel,我们已经知道travel就是0~4,那么这行表达式其实调用的就是template从0到4秒的位置,那么,要制造“影分身”、“长龙”,其实就是调用不同时间的形状层,就可以。
引入offset,让其他层的星星和“引导层”的星星逐层产生偏移,因为是时间线上的偏移,偏移的时间不宜过大,所以数字要小,这也是之前offset那行表达式为什么要除以100的原因。
这个例子为valueAtTime的理解提供了一个很好的范例,值得研究。
二、
如何让形状层在运动的过程中保持垂直于运动路径?
给形状层的Orientation添加如下表达式:
strt = 0; //start time of template motion end = 4.0; //end time of template motion t = thisComp.layer("template"); offset = (t.effect("offset")("Slider")/100)*(index -1); travel = linear(t.effect("travel")("Slider")/100,strt,end); if (travel <= offset){ vect = t.position.velocityAtTime(0); }else{ vect = t.position.velocityAtTime(travel - offset); } lookAt(position, position + vect)
三、
如何让形状层不仅能够跟随null的运动路径,还能跟随null的旋转?
给null的Orientation属性的z轴key帧。
将null的Orient Along Path打开(自动跟随路径方向)
将之前给图层Orientation属性的表达式改为:
strt = 0; //start time of template motion end = 4.0; //end time of template motion t = thisComp.layer("template"); offset = (t.effect("offset")("Slider")/100)*(index -1); travel = linear(t.effect("travel")("Slider")/100,strt,end); u = t.toWorldVec([1,0,0],travel - offset); v = t.toWorldVec([0,1,0],travel - offset); w = t.toWorldVec([0,0,1],travel - offset); sinb = clamp(w[0],-1,1); b = Math.asin(sinb/thisComp.pixelAspect); cosb = Math.cos(b); if (Math.abs(cosb) > .0005){ c = -Math.atan2(v[0],u[0]); a = -Math.atan2(w[1],w[2]); }else{ a = Math.atan2(u[1],v[1]); c = 0; } [radiansToDegrees(a),radiansToDegrees(b),radiansToDegrees(c)]
Good!