【エクスプレッション】徹底解説!toCompメソッド

toCompをはじめとする座標変換メソッドは大変便利なのですが、使い方を間違えると「来てほしいところにレイヤーがこない」といったことが起こるので解説します。

いったいなぜ座標変換メソッドがあるのか?

例えば、レイヤーを親子にしたとき、子レイヤーの位置などのパラメータが謎の数値に変わって困ったことはありませんか?そのようなときに使えるのが座標変換メソッドです。

AEには3つ座標があります。1つはご存じ、世界を直線的なXYZで表した『ワールド座標』です。

2つ目は『レイヤー座標』。これは、各レイヤーが独自に持っている座標です。レイヤーの左上を原点[0,0]とします。レイヤーがスケールや回転すれば追従する座標空間のため、空間自体が横に伸びたり斜めになったりします。なので「レイヤー座標空間での“1マス”は水平垂直でもないし、1ピクセルでもない」こともあります。

3つ目は『コンポ座標』です。「ただのワールド座標の2D版じゃないの?」と思いますが、カメラがあった場合を考えてみて下さい。カメラが動くと3Dレイヤーは動きますが、2Dレイヤーはカメラに追従するようにして、動きません。厳密に言えば、この「カメラから見た2D座標」がコンポ座標なんです。
ワールド座標の2D版(つまりワールド座標のZが0の座標)だと、カメラが動くとレイヤーが実はペラペラの紙であったように動いてしまいますが、コンポ座標だとそうならない、という違いです。

座標変換メソッドは、これらの3つの座標をかんたんに行き来できる便利機能です。

「じゃあ、そもそもなんで全部ワールド座標で表さないの?」という疑問がわくかと思います。これについては、まあその、あんまり筆者もわかってないんですが、コンピュータ的に、あるいはソフトを作っている人的に座標を分けたほうが計算が速いし都合がいいのと、デザイナー的にも、例えば「親子にして親をちょっと回転させたから、子の位置をスライダーで動かすと親の角度に合わせて斜めに移動する」ほうが直観的に分かりやすい、ということかもです。

間違えやすい点

座標変換が狙った位置に来ないたいがいの原因は、レイヤー.toComp(××)の“レイヤー”を入れていないことです。

これは、toCompがただの関数ではなく、レイヤーが持つメソッドであることが起因しています。エクスプレッションの便利機能はたいがい関数とかメソッドとか呼ばれますが、関数とメソッドの違いは何なんでしょうか?実はメソッドは関数の一部で、特定のプロパティが持っている関数です。この場合は、toComp()はレイヤーというプロパティが持っている関数、ということです。

関数は単純に、なんちゃら(××)と書いて実行できる機能です。
対してメソッドは〇〇.なんちゃら(××)という形で、〇〇という”メソッドの持ち主”から書かないと実行されません。

しかしエクスプレッションは省略をけっこう許してくれるため、 レイヤー.toComp(××) と書かないで toComp(××) と書いても案外実行できてしまいます。

が、省略した場合はそのエクスプレッションが書かれているレイヤー自身が .toComp(××) の前に補完されてしまいます。

そしてtoCompの書き方は『レイヤー.toComp(そのレイヤー座標)=コンポ座標 』です。

その結果、例えば「レイヤーAの位置はコンポ位置だから、その位置エクスプレッションに、toComp(レイヤーBのレイヤー座標)と書いて変換しよう」とすると、エクスプレッションが勝手に保管して『レイヤーA.toComp( レイヤーBのレイヤー座標 )』 となります。すると、やっていることは「レイヤーBのレイヤー座標なのに、レイヤーAの座標空間をもとにコンポ座標に直す」という意味わからんこととなり、変な場所に行ってしまうのです。

だから、この場合は レイヤーA の位置エクスプレッションに『 レイヤーB.toComp( レイヤーBのレイヤー座標 ) 』と書かねばならない、toCompの前は省略できない、ということです。

レイヤーが持つメソッドなのに、結果は『なんらかの計算をして変化したレイヤー』ではなく『座標』というのがわかりにくい原因かもですね…。

以下、具体的な操作方法一覧です。
動画内のヌルはコンポ座標、あるいはワールド座標を表します。

グリッドがレイヤー座標を表し、グリッドに追従している棒はレイヤー座標Zを表します(棒をレイヤーの子にすることで実現)。

toComp

ヌルに適用。レイヤーとグリッド&Z棒を操作。ヌルが追従している。

■概要:レイヤー座標からコンポ座標を得られる。
正式名称はおそらく toCompCoord fromLayerCoord。

■記述方法:レイヤー.toComp(そのレイヤー座標)=コンポ座標

■注意点:
結果は2次元座標。
3Dスイッチを押すとZにも値が入るが、カメラのズーム値に関連した謎の値が入るので使わない。2Dレイヤー.toComp()の場合はZにゼロが入るので、”カメラを使わないならば”問題ない。

たいがいはこのメソッドを適用するレイヤーの座標を使わないので、レイヤー.toComp()のレイヤーは省略できない。
記述方法上、『toCompの前に書くレイヤーと同じレイヤー座標が()に入っているか』に注意すればよい。

実は3Dレイヤーのレイヤー座標を入れてもよい(fromCompToSurfaceの逆)。
実は3Dレイヤーの『3次元レイヤー座標』を入れてもよい(3Dレイヤーの手前や奥に進んだ値をコンポ位置に変換)。

■具体例:
親子になった子のコンポ位置を得る。
親子レイヤーとはまた別のヌルなどの『位置』に以下のエクスプレッションを記述。
子レイヤー.toComp(そのレイヤーのanchorPoint);
あるいは
親レイヤー.toComp(子レイヤーのposition);

2D3D使用可能注意点
2Dレイヤー.toComp(2Dレイヤー座標)
3Dレイヤー.toComp(3Dレイヤー座標)
2Dレイヤー.toComp(3Dレイヤー座標)×実質、Zを切り捨てた座標が入るため、
2Dレイヤー.toComp(2Dレイヤー座標)となり、
意図通りにならない。
3Dレイヤー.toComp(2Dレイヤー座標)実質、Zにゼロが入った
3Dレイヤー.toComp(3Dレイヤー座標)であるため。

fromComp

レイヤー内のグリッドに適用。ヌルを操作。グリッドが追従している。

■概要:コンポ座標からレイヤー座標を得られる。
正式名称はおそらく fromCompCoord toLayerCoord。

■記述方法:求めたいレイヤー座標のレイヤー.fromComp(コンポ座標)=レイヤー座標

■注意点:
結果は2次元座標。
2Dレイヤー.fromComp(2Dコンポ座標)という形で使う。
3Dワールド座標を入れてもよいが、Zがゼロ以外だったりカメラがあるとズレる。

たいがいは”求めたいレイヤー座標の レイヤー”に適用するので、前半は省略可能なことが多い。
省略しない場合、toCompとは違い fromCompの前には『求めたい結果と同じ座標空間を持つレイヤー』を入れることに注意すればよい。

■具体例:
エフェクトをヌルでコントロールする。
エフェクトの座標プロパティにエクスプレッションで以下を記述。
fromComp(ヌルの位置);

ヌルが何かの子になると、ヌルの位置プロパティがコンポ座標ではなく親のレイヤー座標となってしまうため、toCompで使った例文を併用して“fromCompに必ずコンポ位置を渡すようにする”親子対策をしてある記述をよく見かける。
fromComp(ヌル.toComp(ヌルのanchorPoint));

fromCompToSurface

レイヤー内のグリッドに適用。ヌルを操作。グリッドが追従している。

■コンポ座標から見て、レイヤー表面に当たっている箇所のレイヤー座標を得られる。
正式名称はおそらく fromCompCoord toLayerSurface’sLayerCoord。

■記述方法:求めたいレイヤー表面があるレイヤー.fromCompToSurface(コンポ座標)=レイヤー表面のレイヤー座標

■注意点:
結果は2次元座標。

fromCompとの違いは『3D対応になる』こと。斜めになっている3Dレイヤーに適用しても、コンポ位置から見たレイヤー表面のレイヤー座標を得られる。
2Dレイヤー.fromCompToSurface(2Dコンポ座標)でもよいが、3Dレイヤー.fromCompToSurface(2Dコンポ座標)でもOK。
3Dワールド座標を入れてもよいが、Zがゼロ以外だったりカメラがあるとズレる。

toWorld

ヌルに適用。レイヤーの回転を操作。ヌルが追従している。

■レイヤー座標からワールド座標が得られる。
正式名称はおそらく toWorldCoord fromLayerCoord。

■記述方法:レイヤー.toWorld(そのレイヤー座標)=ワールド座標

■注意点:
結果が3D座標となるので3Dスイッチを入れる。

実はレイヤー座標は3次元のレイヤー座標でも可能。

2D3D使用可能注意点
2Dレイヤー.toWorld(2Dレイヤー座標)Zがゼロ以外、カメラがあるとズレる。
toCompで済む使い方なのでtoWorldである意味が特にない。
3Dレイヤー.toWorld(3Dレイヤー座標)
2Dレイヤー.toWorld(3Dレイヤー座標)×実質、Zを切り捨てた座標が入るため、
2Dレイヤー.toComp(2Dレイヤー座標)となり、
意図通りにならない。
3Dレイヤー.toWorld(2Dレイヤー座標)実質、Zにゼロが入った
3Dレイヤー.toComp(3Dレイヤー座標)であるため。

fromWorld

レイヤー内のグリッドとZ棒に適用。ヌルを操作。グリッドとZ棒が追従している。

■概要:ワールド座標からレイヤー座標の3次元版が得られる。
正式名称はおそらく fromLayerCoord toWorldCoord。

■記述方法:求めたいレイヤー3D座標があるレイヤー.fromWorld(ワールド座標) = レイヤー座標の3次元版

■注意点:
3Dレイヤー.fromWorld(3Dワールド座標)で使う。
2Dレイヤー.fromWorld(3Dワールド座標)でもよいが、Zがゼロ以外だったりカメラがあるとズレる。

結果はレイヤー3D座標であるため、入力するワールド座標がレイヤー表面にないとズレていくことに注意。
入力するワールド座標をレイヤー表面から平行に離せば、正確なレイヤー3D座標を得ることができる。

toCompVec, fromCompVec, toWorldVec, fromWorldVec について

それぞれ、座標ではなくベクトルを求められるメソッドとのことで、確かに方向を表すベクトル自体は得られます。しかし、「大きさが正確に得られないな…」という印象でして、詳しく検証していません。

主にスケール部分にバグがあるんではないか?という情報があり、その対処法も載っているページがありますのでご紹介しておきます。
Un bug dans Layer Space Transforms (toCompVec ou toWorldVec)

いつ、何が何座標になるのか?

普通のレイヤー:2Dならコンポ座標。3Dならワールド座標。

親子レイヤー:子の位置が親レイヤーのレイヤー座標となる。
その親をまた親子にしたところで、孫がまた別の値になるわけではなく、親レイヤーのレイヤー座標のまま。
*検証をするうち、レイヤー座標にもZ軸が存在することがわかりました。3Dレイヤー同士を親子にしたときの子レイヤーの座標がそれです。これはtoWorldなどに使えます。

マスク:レイヤー座標。

アンカーポイント:常にレイヤー自身のレイヤー座標。
つまり実は、親子レイヤーについては、子レイヤーの位置と親レイヤーのアンカーポイントは空間を共有している。親レイヤーのマスクも、親レイヤーのエフェクトも同様(エフェクトについては後述で条件付き)。なのでこれらは実は変換が必要ない!

シェイプレイヤー内のプロパティ(パス点など):シェイプグループトランスフォームがデフォルトであればレイヤー座標。が、デフォルトでなければそこからさらに変換が必要。しかし座標変換メソッドでは追えない。
パス点ではない、独自に位置移動やらができてしまうプロパティ(長方形パスのサイズや位置)はまたさらにそれも加味する必要がある。

エフェクト:基本的にはレイヤー座標。
しかし、コラップスすると常にコンポ座標となり、原点も動かない。つまり、3Dにしようがカメラがあろうがエフェクトが動かない。シェイプレイヤーとテキストは常にコラップス状態なので、エフェクトは常にコンポ座標となる。
以下、これを便宜的に『エフェクト座標』と呼ぶ。
*『CC Partice World』の座標のように、一部、独自規格の座標系もあります。

シェイプレイヤーとテキスト、コラップスされたプリコンレイヤーについて:
シェイプやテキストの左上が原点というわけではない。内部的にはコンポサイズと同じサイズのレイヤー扱いとなる。位置とアンカーポイントを[0,0]にすれば、画面の左上が原点となるので、シェイプやテキストが原点からどれだけ離れているのかが確認できる。「位置やアンカーポイントパラメータを変えれば原点は移動する」という点で、上記のエフェクト座標ともまた違うことに注意。
シェイプやテキストがどんなにでかくなっても(つまりレイヤーサイズを超えても)描画できるように、内部的にはコラップスされたプリコンレイヤーと同じ処理なのだろうと思います。なのでwidthとheightで測ってもコンポと同じサイズにしかならず、その実質プリコンにある座標を得るためにsourceRectAtTimeがあるのでしょう。

sourceRectAtTime:シェイプレイヤーにどんなにシェイプグループトランスフォームがかかっていても、得られるのはレイヤー座標。

sampleImage:入力する座標はどうやら上記の『エフェクト座標』のよう。

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