カメラのフォーカスを常に指定のレイヤーに合わせるExpression

カメラの被写界深度をオンにして動かしたりするとき、うまくフォーカスを合わせるのが面倒だったりしますね。
また、動作自体も重いので数コマずつ進めながら数値を直していくのも非常に面倒です。

そこで、フォーカス距離を指定のヌルレイヤーなどに自動的に合わせる(オートフォーカス)エクスプレッションを書こうと思ったのですが、ヘルプにありました。

Adobe After Effects CS4 * 例:カメラのフォーカルプレーンを別のレイヤーに一致させる

これを使えば解決、で終わりなんですがそれじゃあんまりなのでちょっとこのエクスプレッションについて調べてみました。

・・と思ったらこのエクスプレッションの解説まであったので、これをほとんどそのままですが見てみることにします。。

Dan Ebberts’s Expressioneering Design Guide

まず最初のアプローチですが、lenghを使ってターゲットレイヤからカメラ原点までの距離を出してそのままフォーカス距離の値に代入するというもの。

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

1行目はスクリプト簡略化のためターゲットレイヤを代入しているだけ。
toWorldはレイヤー上の値をコンポ3D空間のグローバルな値に変換するものです。
一つ前の記事で、3D空間にあるオブジェクトをコンポ上で見える位置に変換するのにtoCompを使いましたが、その逆がtoWorldになります。詳しくはこちら

この段階でほぼ問題はないのですが、フォーカスが当たるのは単純にカメラからの距離(つまり曲面)ではなく、カメラから平行な面になるため
以下のようにターゲットレイヤがカメラの正面からずれている場合、フォーカスの距離にもズレが生じます。

dof_pic01

そこでこのズレを直すため、三角法を使います。
さいわいAEのエクスプレッションではdot()関数でベクトルを扱うことが出来ますので、

①カメラからターゲットレイヤまでのベクトル
②カメラのZ軸に伸びる単位ベクトル

このふたつのベクトルの標準内積から①のZ軸方向の長さを求め、これをフォーカス距離に設定することで常にターゲットレイヤにフォーカスが当たるようになります。

target = thisComp.layer("target");
V1 = target.toWorld(target.anchorPoint) - toWorld([0,0,0]);
V2 = toWorldVec([0,0,1]);
dot(V1,V2);
//1行目"target"の中にはターゲットに指定したいレイヤー名を入力

サンプルで作ってみた動画はこちら

この値をwiggleで振ったりしても面白い映像が作れるかもしれませんね。