【エクスプレッション】3Dレイヤーを2Dレイヤーの位置に合わせる

条件によって使い勝手が違う3種類作りました。

3Dレイヤーの位置に適用し、エクスプレッション内の”ホワイト 平面 1″を適宜、対象2Dレイヤー名に変えればOKです。
*親子にも対応していますが、3Dレイヤーのほうの親は先祖全て3Dでないとズレたりします。

activeCamera版

if( thisLayer.inPoint <= time && time <= thisLayer.outPoint){
	lyr = thisComp.layer("ホワイト 平面 1");
	cam = thisComp.activeCamera;
	cmpCrd = lyr.toComp(lyr.anchorPoint);
	rstCrd = cam.toWorld([cmpCrd[0]-thisComp.width/2,cmpCrd[1]-thisComp.height/2,cam.zoom]);
	if( thisLayer.hasParent ){ thisLayer.parent.fromWorld(rstCrd);}
	else{rstCrd;}
}else{value;}

コンポ上にカメラが無くても使えます。
ただし、3Dレイヤーの始点終点以外の時間では、エクスプレッション前の値となることに注意してください。

最初と最後の1行ずつを消すと、始点終点以外の時間でも値を保てますが、もしもコンポ上に『カメラも無く、2Dレイヤーしかない時間帯』があるとエラーが出ます。

カメラ版

lyr = thisComp.layer("ホワイト 平面 1");
cam = thisComp.layer("カメラ 1");
cmpCrd = lyr.toComp(lyr.anchorPoint);
rstCrd = cam.toWorld([cmpCrd[0]-thisComp.width/2,cmpCrd[1]-thisComp.height/2,cam.zoom]);
if( thisLayer.hasParent ){ thisLayer.parent.fromWorld(rstCrd);}
else{rstCrd;}

特定のカメラを指定するバージョンです。
エクスプレッション内の”カメラ 1″を適宜、対象カメラ名に変更してください。

activeCamera版と違って3Dレイヤーインアウト時間外でも値を保ちますが、カメラのインアウト時間外では見た目位置がズレることに注意してください。

ヌル版

lyr = thisComp.layer("ホワイト 平面 1");
cam = thisComp.layer("ヌル 1");
cmpCrd = lyr.toComp(lyr.anchorPoint);
rstCrd = cam.toWorld([cmpCrd[0]-thisComp.width/2,cmpCrd[1]-thisComp.height/2,-cam.position[2]]);
if( thisLayer.hasParent ){ thisLayer.parent.fromWorld(rstCrd);}
else{rstCrd;}

コンポ上にカメラが無く、デフォルトカメラを動かす予定もない場合のバージョンです。
ヌルを作り、ヌルのZ位置を-2666.6667にしてから適用してください。
エクスプレッション内の”ヌル 1″は作ったヌルの名前に変更します。

デフォルトカメラは設定を変えていなければ50mmカメラとなり、動かさなければXYがコンポの真ん中、Zが-2666.6667となるので、そこにヌルを置いてカメラに見立てています。

使いどころ

色々と使えるかなと思いますが、例えばカメラが動きまくるシーンで、レイヤーを「2Dの見た目で配置したいな」といったときに使えるんでは、と思います。

解説

エクスプレッション内でやっている作業は「2D位置から3D位置を割り出す」ということです。
「コンポ座標からワールド座標にする」ってことですね。

座標系にはワールド座標、コンポ座標、レイヤー座標というのがあります。ワールド座標は1マス1ピクセル、XYZの方向も変わらない座標です。レイヤー座標はレイヤーの左上が原点[0,0,0]の、レイヤーが回転すれば方向も変わるし、大きさが変われば1マスが1ピクセルでなくなる相対的な座標です。
そしてコンポ座標なんですが、”カメラさえなければ”ワールド座標の2D版という解釈で問題ないんですが、カメラがある場合はちょっと解釈を変えねばです。

カメラを動かしても2Dレイヤーは動きません。これは逆に「カメラの動きに2Dレイヤーが逐一追従している」とも言えます。それでは、カメラのどこらへんを基準に追従しているのでしょうか?
これは、カスタムビューとかにしてカメラを選択すると出てくる四角錐の面(投影面)の左上なんですね。
つまり、2D座標はカメラ投影面の左上を原点[0,0,0]とした相対的な座標です。
投影面を1つの平面レイヤーとしてとらえて言い変えると、コンポ座標はカメラ投影面レイヤーのレイヤー座標と言えます。

コンポ座標がレイヤー座標だと分かったならば、toWorldメソッド(正式名称はおそらくtoWorldFromLayer)が使えそうですが、もう一工夫必要です。なぜなら、カメラ投影面はレイヤーとしては実際には存在してないので、toWorldが使えないからです(事前に投影面ピッタリの平面を作っておき、カメラに追従させて不透明度をゼロにすればできないこともなさそうですが、用意が面倒ですね)。

そこで使うのがカメラ自身です。投影面の左上とカメラ自身の位置関係のズレは[コンポ設定の横幅の半分,縦幅の半分,ズーム値]で変化がありません。なので、投影面座標とカメラ座標の変換は簡単に割り出せます。
そして、カメラはレイヤーとして存在しているので(あるいはactiveCameraでデフォルトカメラも得られるので)toWorldメソッドが使えます!

cam.toWorld([cmpCrd[0]-thisComp.width/2,cmpCrd[1]-thisComp.height/2,-cam.position[2]]);
〇〇.toWorld(レイヤー座標)で、「〇〇レイヤーのレイヤー座標をワールド座標にする」という意味です。
そしてカッコ内は「2D座標=コンポ座標=投影面座標をずらしてカメラレイヤー座標に変換したもの」です。
なので上記は2D座標をカメラレイヤー座標に変換し、それをtoWorldでワールド座標に変換したもの、となります。

この投影面座標とカメラ座標の相互変換は(おそらく)toComp系メソッドでも内部的に使われている処理なので、覚えておくと案外どこかで役に立つかもしれません。

■activeCameraについて
本処理とは関係ないのですが、activeCameraに癖があるので書いておきます。
activeCameraは一番上の目玉マークが付いているカメラを表し、カメラが無いときは(3Dレイヤーが1つでもある時間帯は)デフォルトカメラを表します。つまり基本的にはビューワー右下の『アクティブカメラ』と同じものを指します。

が、タイムラインの「カメラも無く2Dレイヤーしかない」時間帯はactiveCameraがエラーとなります(スクリプトだとnull)。エクスプレッションだと、AEの仕様でほっとくと全タイムラインがキャッシュ用レンダリングされてしまうので、もしもそのような時間帯があればその時点でエラーが出てしまいます。

これを解消するには、try{thisComp.activeCamera}catch(e){処理}といった具合にtry文を使うか、ここで紹介しているエクスプレッションのように「適用するのが3Dレイヤーで確定しているから、インアウト時間内であれば問題ないので、それ以外はエクスプレッション前の値にする」といった処理が必要です。



よかったらシェアしてね!
  • URLをコピーしました!