「只要功夫深 不用关键帧」将不定期更新一些AE表达式和脚本的奇技淫巧,希望能给大家带来一些启发。
上周有朋友遇到这么个问题:
对一段文字,不管文字长度如何变化,想让背景到文字的边距始终保持不变,在 AE 里该如何实现?
要做到边距固定,当然首先要获得整句文本的宽高,幸运的是,AE 为我们提供了一个表达式来干这个:
sourceRectAtTime();
用法也很简单:
textLayer.sourceRectAtTime();
返回这句文本的 [top, left, width, height],即我们需要的是:
textLayer.sourceRectAtTime().width; textLayer.sourceRectAtTime().height;
用一个简单例子看看具体怎么应用:
首先新建一个文本图层 A ,打一段文字
再新建形状图层 B 对它画一个矩形作为背景,先大概对齐好,将文本图层设为它的父级,这样文本移动的时候它也能跟着动了。
![f559921f7af88cb3692d4b4ef6b1cb44.png](https://img-blog.csdnimg.cn/img_convert/f559921f7af88cb3692d4b4ef6b1cb44.png)
点开该形状图层中这个矩形的「大小」按住alt键(windows下为alt,mac下为option)单击小秒表图标开启表达式,然后把表达式链接到
文本图层 A,在生成的表达式后加上 .sourceRectAtTime().width ,将它复制给一个变量 ww ,再如法炮制将文本高度赋予 hh,即
var ww=thisComp.layer("文本图层").sourceRectAtTime().width;
var hh=thisComp.layer("文本图层").sourceRectAtTime().height;
此时如果我们直接将宽高赋值给矩形
value=[ww,hh];
将会得到一个四周贴着文字的矩形
![670388c2ea690f50cb8a5ee9c7c42888.png](https://img-blog.csdnimg.cn/img_convert/670388c2ea690f50cb8a5ee9c7c42888.png)
假设我们定背景到文字的上下边距为 m,左右边距为 n,我们只需
value=[2*n+ww,2*m+hh];
或者用滑块来控制
//获取文本宽高
var ww=thisComp.layer("文本图层").sourceRectAtTime().width;
var hh=thisComp.layer("文本图层").sourceRectAtTime().height;
//设置边距
var vBorder=effect("上下边距")("ADBE Slider Control-0001");
var hBorder=effect("左右边距")("ADBE Slider Control-0001");
[ww+hBorder,hh+vBorder];
![36adc4a41f60cc24f4bcf99cd28ef28f.png](https://img-blog.csdnimg.cn/img_convert/36adc4a41f60cc24f4bcf99cd28ef28f.png)
这样改变文字内容,背景就跟着变化了。当然,换成描边或者其他形式也OK,看你脑洞了。
知乎视频www.zhihu.com利用这个表达式我们还可以做很多效果,比如模拟命令行文字的输入光标:
![0704cc1302a0e2ab8d49718395097752.png](https://img-blog.csdnimg.cn/img_convert/0704cc1302a0e2ab8d49718395097752.png)
如果只需要一个固定的光标跟在文字后边我们可以直接在文本图层的「源文本」属性里添加表达式
value+"_";
但如果想更真实的模拟出光标闪烁,就得另外想想办法。我们可以利用前面的思路,用形状图层画一个光标(这个方案的另一个好处是光斑形状我们不用局限于字体,可以随意绘制),然后我们在这个形状组的「变换」属性中添加表达式,这次我们要用到文本的宽、到合成左边的距离:
//获取文本的宽、到合成左边的距离
var ww=thisComp.layer("文本图层").sourceRectAtTime().width;
var left=thisComp.layer("文本图层").sourceRectAtTime().left;
value=[left+ww,value[1]]
然后再调整一下图层的位置,这样就给文字贴上了一个尾巴。而因为是个独立的图层,我们可以单独对它的不透明度做动画,点开它的「不透明度」属性,添加表达式
50*(1+Math.sin(time*20));//20是闪烁的频率,值越高闪烁越快
好,说完了文字外边的东西,我们再来聊聊文字本身,注意前面的例子都涉及到文字内容的变化,最直接的做法就是用关键帧去改变内容,那如果我们想让一句长文逐字出现,类似打字机的效果,该怎么做比较好呢?
最简单的方法是在「效果和预设」里搜索「打字机」,然后应用到对应的文本图层。
![4dd9fe8229f9305c5fd3850aa982f67e.png](https://img-blog.csdnimg.cn/img_convert/4dd9fe8229f9305c5fd3850aa982f67e.png)
想要控制文字出现的速度,只需按下快捷键「U」,控制「起始」属性的两个关键帧就好。这预设其实就是「源文本」属性旁边的「动画」子菜单里的属性的简单应用,限于篇幅这里就不展开了。
但是,如果想在这个动画上再叠加之前的光标动画,你会发现光标根本就不动,一直停靠在最后——因为 sourceRectAtTime() 只检测进行「源文本」动画前的文字所占尺寸和位置,动画之后的他可不管。所以我们还需要换种方法:
首先我们给文本图层打上两个图层标记(快捷键【 windows:alt + *】,【mac:Option + *】),然后为「源文本」插入表达式:
var texts = text.sourceText.value;//获取整句话内容
var stTime = thisLayer.marker.key(1).time;//获取两个marker的时间
var endTime = thisLayer.marker.key(2).time;
var timeDiv = (endTime - stTime)/texts.length;//将两个marker之间的时间按字符数均分
var deltaTime = time-stTime;//设定初始时间,流逝……
var curStr = Math.floor(deltaTime/timeDiv);//当前应出现几个字
var textsNow="";
if(time>=stTime && time<=endTime)
{
textsNow= texts.substr(0,curStr);//若当前时间在两个marker之间,文字逐个出现
}else if(time>endTime){//若时间超过marker2.则保留整句不动
textsNow=texts;
}else{
textsNow="";
}
value=textsNow;
移动这两个标记,文字会在两个标记之间逐字出现。到这里我们还原了「打字机」动画,再加上之前的光标~完美:
知乎视频www.zhihu.com最后附上工程文件(AE CC 2019)
链接: https://pan.baidu.com/s/1kJstilWgwb-63Lhb-FtGAg 提取码: skwx