本文不堆砌UI截图,不重复官方文档,而是从底层算法、表达式引擎、色彩科学、脚本自动化及3D渲染管线入手,系统拆解After Effects在六大核心场景中的“代码级”控制方案。所有示例均可在AE CC 2024+环境中直接运行,适合进阶开发者与TD(技术总监)参考。
AE的Mask本质是二次贝塞尔曲线闭合路径,其参数方程为:
B(t) = (1-t)²P₀ + 2t(1-t)P₁ + t²P₂, t∈[0,1]通过maskShape属性可读写路径顶点。利用表达式实现动态自适应遮罩——根据图层亮度自动收缩/扩张:
// 应用于Mask Path的表达式(需启用"表达式控制")
const targetLayer = thisComp.layer("背景");
const samplePoint = targetLayer.transform.position;
const brightness = targetLayer.sampleImage(samplePoint, [0.5,0.5], true, 1).r;
const scaleFactor = linear(brightness, 0, 1, 0.8, 1.2);
const originalPath = thisProperty.value;
const newVerts = originalPath.vertices.map(p => p * scaleFactor);
createPath(newVerts, originalPath.inTangents, originalPath.outTangents, originalPath.isClosed);传统Track Matte需依赖上层图层,但在批量处理时可用Set Matte效果 + 表达式动态指定蒙版层:
// 效果:"Set Matte" -> "Matte Layer" 属性
const matteName = thisComp.layer("索引控制").effect("Slider")("滑块").value;
thisComp.layer(matteName).index;配合layer.index实现自动匹配序号,避免手动拖拽。
虽然AE原生不支持逐像素脚本,但可通过Adjustment Layer + 自定义HSL + 阈值表达式模拟:
// 在"颜色阈值"效果的"阈值"属性上写入:
const src = thisComp.layer("原始").sampleImage(transform.position, [0.1,0.1]);
const gray = 0.299*src.r + 0.587*src.g + 0.114*src.b;
if (gray > 0.5) 1 else 0; // 生成硬边遮罩注意:
sampleImage性能开销大,仅用于静态帧或预渲染。
AE的Apply Color LUT效果本质是三维立方体插值(Trilinear或Tetrahedral)。我们可以用表达式生成动态LUT(无需外部文件):
// 在"色彩平衡"效果中,对每个通道应用分段函数
// 红色通道修正曲线(S型)
const x = thisComp.layer("原始").sampleImage(transform.position, [0,0]).r;
const a = 0.2; // 暗部压缩
const b = 0.8; // 亮部扩展
const y = (x - a) / (b - a);
clamp(y, 0, 1);通过ExtendScript脚本批量设置项目色彩空间:
// .jsx脚本,运行于ExtendScript
app.project.colorDepth = 32; // 浮点
app.project.workingSpace = "ACES - ACEScg";
app.project.linearizeWorkingSpace = true;
// 遍历所有合成,开启线性化
for (var i = 1; i <= app.project.numItems; i++) {
var item = app.project.item(i);
if (item instanceof CompItem) {
item.linearBlending = true;
}
}在抠像后常出现边缘色溢,利用色相/饱和度效果的Colorize属性,用表达式计算补色:
// 色相补偿:取抠像主色(如绿幕)的色相反向
const keyColor = [0.33, 1, 0.5]; // HSV 绿色
const compHue = (keyColor[0] + 0.5) % 1.0;
[compHue, 0.8, 0.6] // 输出给"色相/饱和度"的"色相偏移"Keylight不是简单阈值,而是统计色度空间中的高斯分布。其内部计算:
Screen Color选取中心点C₀通过表达式直接控制Screen Gain和Screen Balance实现动态自适应:
// 在Keylight的"Screen Gain"属性上
const avgLum = thisComp.layer("背景").sampleImage([960,540], [100,100]).r;
linear(avgLum, 0.2, 0.8, 80, 120);标准Despill算法:将像素沿补色方向收缩。AE内置的Advanced Spill Suppressor可使用表达式切换算法模式:
// 自定义溢出抑制——在"颜色校正"->"色阶"中操作
const src = sampleImage(transform.position, [0.5,0.5]);
const green = src.g;
const red = src.r;
// 若绿色通道过度主导,则压制G并补偿R
if (green > 0.6 && green > red) {
const spill = (green - 0.6) * 0.8;
[src.r + spill*0.3, src.g - spill, src.b + spill*0.1]
} else src;利用Compound Blur + Matte Choker配合表达式实现边缘羽化动态映射:
// Matte Choker的"Choke"属性根据画面噪点自动调节
const noise = thisComp.layer("噪点参考").effect("噪点H")("滑块");
linear(noise, 0, 10, 0.5, 2.0);不用第三方插件,纯表达式实现阻尼弹簧效果:
// 应用于位置属性
const target = thisComp.layer("控制空对象").transform.position;
const freq = 3.0; // 频率
const decay = 0.85; // 阻尼
const t = time - inPoint;
const offset = target.valueAtTime(inPoint) - target.valueAtTime(time);
const amp = length(offset);
const phase = Math.atan2(offset[1], offset[0]);
const x = amp * Math.sin(freq * t * 2*Math.PI) * Math.exp(-decay * t);
[ target[0] + x * Math.cos(phase), target[1] + x * Math.sin(phase) ]使用ExtendScript创建数据驱动的图形阵列:
// 生成N个圆形,位置分布在斐波那契螺旋上
var comp = app.project.activeItem;
if (comp && comp instanceof CompItem) {
var num = 50;
for (var i = 0; i < num; i++) {
var shape = comp.layers.addShape();
var group = shape.property("ADBE Root Vectors Group").addProperty("ADBE Vector Group");
var ellipse = group.property("ADBE Vectors Group").addProperty("ADBE Vector Shape - Ellipse");
var pos = group.property("ADBE Vector Transform Group").property("ADBE Vector Transform Position");
var phi = Math.PI * (1 + Math.sqrt(5)) * i;
var radius = 5 * Math.sqrt(i);
pos.setValue([400 + radius * Math.cos(phi), 300 + radius * Math.sin(phi)]);
// 随机颜色
var fill = group.property("ADBE Vectors Group").addProperty("ADBE Vector Fill");
fill.property("ADBE Vector Fill Color").setValue([Math.random(), Math.random(), Math.random()]);
}
}通过eval()或JSON.parse()结合footage读取外部数据:
// 文本图层的"源文本"属性
var data = footage("data.json").sourceData;
var index = Math.floor(time / 0.5) % data.length;
"当前数值: " + data[index].value + "\n状态: " + data[index].status;需将JSON文件拖入项目并设置为"导入为" -> "JSON对象"。
AE内置3D摄像机追踪产生点云和摄像机参数。通过表达式可将追踪点绑定到自定义Null:
// 在Null的"位置"属性上
const trackPoint = thisComp.layer("3D追踪点").transform.position;
const cam = thisComp.activeCamera;
// 将追踪点从世界坐标转为屏幕坐标(用于2D叠加)
cam.fromWorld(trackPoint);利用摄像机的焦点距离和光圈属性,与场景中物体的Z位置联动:
// 光圈大小 = 根据目标物体距离自动调整
const targetZ = thisComp.layer("焦点物体").transform.position[2];
const camZ = thisComp.activeCamera.transform.position[2];
const dist = Math.abs(targetZ - camZ);
linear(dist, 0, 500, 1.4, 16); // 光圈值f-stop使用Cast Shadows和Light Transmission,通过表达式控制阴影密度与光源角度:
// 平行光"强度"属性根据合成中所有3D图层的平均亮度自动调整
var total = 0, count = 0;
for (var i = 1; i <= thisComp.numLayers; i++) {
var l = thisComp.layer(i);
if (l.hasTrackMatte) continue;
var samp = l.sampleImage([0.5,0.5], [0.1,0.1]);
total += (samp.r + samp.g + samp.b)/3;
count++;
}
(total / count) * 200; // 映射到光照强度利用Audio Waveform效果提取振幅,驱动画面缩放或转场:
// 缩放属性的表达式
const audio = thisComp.layer("背景音乐").effect("Both Channels")("Slider");
const amp = audio.valueAtTime(time) * 100;
const base = 100;
base + amp * 0.5;通过Color Stabilizer效果的参考帧功能,结合表达式锁定白平衡:
// 色温偏移量自动匹配参考帧
const ref = thisComp.layer("色卡参考").sampleImage([0.5,0.5], [0.1,0.1]);
const current = thisComp.layer("当前片段").sampleImage([0.5,0.5], [0.1,0.1]);
const deltaR = ref.r - current.r;
const deltaB = ref.b - current.b;
[deltaR*10, 0, deltaB*10] // 输出给"颜色平衡"的偏移量自动化输出不同分辨率、码率的版本:
// 添加渲染队列并设置输出模块
var comp = app.project.activeItem;
var rend = app.project.renderQueue.add(comp);
var outMod = rend.outputModule(1);
outMod.applyTemplate("H.264 - 1080p 30fps");
outMod.file = new File("~/Desktop/output_" + comp.name + ".mp4");
// 设置起始帧
rend.timeSpanStart = 0;
rend.timeSpanDuration = comp.duration * comp.frameRate;
app.project.renderQueue.render();对于重度sampleImage调用,使用逐帧缓存技巧(利用time与posterizeTime):
posterizeTime(1 / 10); // 每秒只计算10次,降低CPU负载
sampleImage(transform.position, [0.5,0.5]);编写脚本自动生成代理文件、替换素材、更新表达式路径:
// 自动替换所有缺失素材
var items = app.project.items;
for (var i = 1; i <= items.length; i++) {
if (items[i] instanceof FootageItem && !items[i].exists) {
var newPath = items[i].name.replace("_RAW", "_PROXY");
items[i].replace(new File(newPath));
}
}在表达式中使用try-catch并输出到控制台(通过console.log):
try {
// 可能出错的运算
var result = 1 / (time - 5);
result;
} catch (e) {
console.log("Error at time " + time + ": " + e.message);
0; // 安全默认值
}上述代码并非炫技,而是将AE从“黑箱软件”转化为可编程渲染引擎的必经之路。遮罩的贝塞尔动态缩放、调色的LUT插值、抠像的色度空间变换、MG动画的物理仿真、3D摄像机的坐标映射、Vlog的自动化工作流——其本质都是数学与数据流。
当你能用表达式替代手动关键帧,用脚本管理数百个合成,用色彩科学保证跨平台一致性时,AE就不再是“软件”,而是一套实时视觉计算框架。腾讯云上的视频处理服务(如VOD、MPS)虽能进行转码和滤镜,但精细化的创意控制仍依赖AE这类前端工具。将本文的代码模板化、封装为AE插件或脚本面板,可极大提升团队协作效率,这也是未来云端+本地混合制作的发展方向。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。