AEJoy —— 表达式之自动对焦【JS】

625 阅读2分钟

效果图

使用从相机到目标的距离来建立焦距,导致层在离轴时失焦

098.gif

使用从 相机到目标层的距离 到相机的 z 轴上的投影,保持层在焦平面上 099.gif

想法

这里的想法很简单。我们希望能够在场景中使用一个对象(图层,Null 等)来控制相机的焦距。假设我们已经启用了相机的景深,并将光圈设置为一个会导致(不在焦平面上的)物体会失焦的值。我们希望能够在场景中移动目标物体,并让摄像机始终聚焦于它。

设计

乍一看,这样做的方法似乎只是计算相机和目标物体之间的距离,并使用它作为焦点距离。我们可以使用这样的表达式(甚至建立了一种处理可能性 —— 摄像机或目标是子层):

target = thisComp.layer("target");
length(target.toWorld(target.anchorPoint) - toWorld([0,0,0])) 

不幸的是,这并不能做到这一点,正如你在上方上部的动图中所看到的。只要目标物体停留在摄像机的 z 轴上,它就可以工作。但是,它对离轴目标不起作用,原因是相机有焦平面,而不是焦球面。你可以在下图中看到这个问题:

image.png

使用合成的俯视图,我们可以看到当目标层离开相机的 z 轴时,它就不在焦平面了。我们需要一个表达式来计算 从摄像机到目标的距离 在摄像机 z 轴上的投影。

那么,我们如何进行这样的计算呢? 我们可以用一点三角学来完成它,但幸运的是,After Effects 有一个内置的向量操作,dot(),它会为我们解决棘手的工作。我们只需要给它两个向量 —— 从摄像机到目标的向量一个单位向量(长度为 1 的向量)它指向摄像机的 z 轴

当我们将这个计算结果应用到相机的焦距时,目标层将始终在焦平面上。你可以在上方下部的动图中看到改进后的效果。下图再次显示了我们的合成的俯视图,这一次焦平面在正确的距离。

image.png

表达式代码

target = thisComp.layer("target");

/// @note 
/// 以防目标层是子层级,所以使用 toWorld() 和锚点
/// 相机没有锚点,所以其位置在 [0, 0, 0]
v1 = target.toWorld(target.anchorPoint) - toWorld([0,0,0]);
v2 = toWorldVec([0,0,1]); ///< 指向相机 Z 轴的单位向量
dot(v1,v2)