AEのエクスプレッションセレクター応用:初心者向け準備編
イントロダクション
AEのテキストアニメーターは、エクスプレッションセレクターを活用することで表現の幅が広がる。
前記事では、テキストアニメーターの基礎について説明した。その応用として、さっそく複雑なテキストアニメーションの作り方を解説したいと思ったのだが、その前に、主にそこで使われる関数などについて、エクスプレッション初心者向けの解説を書いた。
random()・seedRandom()で、ランダム数をつかう
random()
random()によるランダム数の使い方について説明する。(英語が読めるなら、公式のレファレンスを参照したほうがいい。)素朴に使うことは簡単で、random()とさえ書けば0から1の間のランダム数を返してくれる。ただし、0から1の間のランダム数をそのまま使うことは少なく、何らかの計算を加えたり、最大値・最小値を指定したりしてから使うことが多い。
例として、何かしらシェイプレイヤーを作って、その不透明度のプロパティーに以下のエクスプレッションを入力してみよう。(例1とする。)
value = random();
/* value=と;はなくてもいい。
;は正式な書き方としてつける人がいるが、value=まで書く人は少数派だと思う。*/

入力すると、シェイプが見えなくなると思うが、実はうっすらと表示されている。試しに、タイムライン上の再生ヘッド(青いバー)を動かしてみると、不透明度の値が0になったり1になったりしていることがわかる。さきほども言ったように、random()は0から1の間の値を動くが、そのまま使うことは少なく、掛け算などの計算を加えることが多い。
では、random()に100をかけてみよう。
value = random() * 100;
random()は0から1の値を動くから、random() * 100は、0から100の値を動くはずだ。再度、タイムライン上の再生ヘッド(青いバーのこと)を動かしてみると、不透明度の値が実際に0から100の間をランダムに動いていることが分かる。また、シェイプレイヤーがはっきりと点滅していることが分かる。

seedRandom()でrandom()を調節
つぎに、このrandom()の値を制御するseedRandom()という関数について説明する。seedRandom()が役立つのは、例えば、上の例1で作った点滅の挙動が気に入らず、別のランダム数を試してみたいと思ったときだ。先のエクスプレッションにseedRandom()を追記してしてみよう。
seedRandom(123445);
value = random() * 100;
再生して確認してみると、seedRandom()がなかったときと比べて、値の変化の仕方がやや変わっていることがわかる。123445を別の値に書き換えると、さらに挙動が変わる。(ただし、違いは分かりにくいかもしれない。)
このようにrandom()の値を変更する機能に加えて、seedRandomには、もう1つの機能がある。それは、random()が変動しないように固定する機能である。
さきほどまでの例では、random()が時間によってランダムに変化することで、点滅のエフェクトが実現されていた。変化しないようにするために、random()のカッコの中にtrueを追記して、random()を固定してみよう。なお、()中に入れる数などを、引数という。
seedRandom(123445, true);
value = random() * 100;
不透明度の値を見ると、0から100の間の何らかの値になっていて、時間が変わっても、その値は変わらないことがわかる。
random()の最小値・最大値指定
ただ、上の例1では、次のように書くほうが分かりやすいだろう。randomでは、最大値を指定できる。
seedRandom(123445, true);
value = random(100);
//value = random() * 100;と同じ
random()は最小値も指定できる。不透明度を50から100の間で動かしたいと思ったときは、以下のようにかける。
seedRandom(123445, true);
value = random(50, 100);
random()の最小値・最大値指定で、配列を使う
random()では、配列を最小値・最大値に使うことができる。2つ目の例として、何かしらシェイプレイヤーを作って、その位置をX座標は860-1060の間を、Y座標は440-640の間を動いてほしいとする。このとき、位置のエクスプレッションに以下を入力すればよい。
value = random([860, 440], [1060, 640]);
//数字の対応に注意![860, 1060], [440, 640]ではない。


値をリマップするlinear()
※randomの引数設定で済むことがわかったので、このセクションは読み飛ばして大丈夫です。
linear()による値にリマップについて説明する。(これも、英語が読めるなら、公式のレファレンスを参照したほうがいい。)
例えば、さきほどrandom()が0~1の値を動くと説明した。random()を用いて、あるシェイプのX座標を860~1060の間でランダムに動かしたいとする。もちろん、これは以下のような四則演算で実現することができる。
value = random() * 200 + 860;
random()は0~1の値を動き、それに200をかけたrandom() * 200は、0~200の値を動く。そこに860を足すわけだから、底上げされたrandom() * 200 + 860は、860~1060の間を動く。このように値の計算を加えて、値のとる範囲を変えることを「リマップする」という。
しかし、これはあまり直感的ではない。とくに、範囲を変更したいとき、たとえば、100~1060の間を動くように変更したいと思ったときなどは、再度数式を考える必要があり、少しだけめんどうだ。
ここで、linear()を用いれば、わりと直感的に値をリマップできる。
value = linear(random(), 0, 1, 860, 1060);
※修正:value=random(860, 1060)って書いたほうが速いです!!
このコードでは、0から1の間の値が、860から1060の間に来るようなやり方で、random()をリマップしている。図に書くと、このような感じである。

なお、元の範囲が0から1の間をとるときは、次のように省略できる。
value = linear(random(), 860, 1060);
//value = linear(random(), 0, 1, 860, 1060);と同じ
値を参照・同期する
別のプロパティの値をエクスプレッションで参照する方法を説明する。これも例を用いて説明する。おおむね、次のようなセットアップを行う。
赤円と青円を作る
この2つの円の位置を右クリックして、「次元を分割」する
赤円のX位置にキーフレームを打って、動きを加える
両円のY位置を違う値にする(見やすさのため)


このセットアップにおいて、動いている赤円のX位置に、今は静止している青円のX位置を同期させたいとしよう。そのためには、「親とリンク」機能を使えば、エクスプレッションが自動入力されて便利である。タイムライン上で「親とリンク」機能を表示するには、「レイヤー名」と書いているあたり(以下画像の黄色線あたり)を右クリック > 「列を表示」 >「親とリンク」を選択する。

そうすると、ぐるぐるマークが各プロパティの横に表示される。青円のX位置の横にあるぐるぐるマークをドラッグして、赤円の「X位置」という文字あたりでドロップする。

再生すると、赤い円と青い円のX座標が同期されていることがわかる。

このドラッグアンドドロップの操作によって、青い円のX位置に、以下のエクスプレッションが自動で入力されている。

thisComp.layer("赤い円").transform.xPosition
これは見てわかる通り、そんなに複雑な構文ではない。同コンプ内にある(thisComp)赤い円レイヤー(layer("赤い円"))のトランスフォーム(transform)プロパティーにあるX位置(xPosition)を参照している。
このエクスプレッションの前半部「thisComp.layer("赤い円")」は分かりやすいだろう。同じコンプのabcdというレイヤーを参照したいなら、「thisComp.layer("abcd")」と書けばいい。
なお、同じコンプ内だけでなく、特定の名前のコンプのレイヤーを参照することもできる。aiueoという名前をコンプのexampleという名前のレイヤーを参照したいなら「comp("aiuoe").layer("example")」という書き方ができる。
一方、後半部の「transform.xPosition」は推測しにくいかもしれない。
後半部の書き方を知るための簡単な方法を教える。まず、参照したいプロパティを開き、ストップウォッチマークをaltキーを押しながらクリックする。そうすると、エクスプレッションが表示されるので、コピーして取っておく。最後に、エクスプレッションをオフにするために、再度altキーを押しながらストップウォッチマークをクリックする。
例の場合では、赤円のX位置を開き、そのストップウォッチマークをaltキーを押しながらクリックする。そうすると、エクスプレッション「transform.xPosition」が表示されるので、コピーして取っておく。最後に、エクスプレッションをオフにするために、再度altキーを押しながらストップウォッチマークをクリックする。

値をズラして同期するvalueAtTime()
上の例では、値を完全に同期する方法を説明したが、valueAtTime()を用いれば、この同期をズラすことができる。
上の例では、動く赤円のX位置に、青円のX位置を同期させた。そこで、赤円のX位置に、青色の円のX位置を、1秒遅れて同期させたいとしよう。そのためには、上の青色のX位置のエクスプレッションに、以下のように追記する。
thisComp.layer("赤い円").transform.xPosition.valueAtTime(time-1)
.valueAtTime(time-1)を後ろに追記した。()のなかにある変数timeは現在の再生時間で、そこから1を引くことで1秒前の時間を得ている。このエクスプレッションでは、「赤い円」のX位置の1秒前の値を参照している。

1秒ではなく1フレームをズラして同期したいなら、以下のように、1をframesToTime(1)に書きかえればよい。framesToTimeは、名前の通り、フレーム数を秒数に変換する関数だ。30fpsなら、1フレームを秒単位に変換したframesToTime(1)は、0.0333…になる。
thisComp.layer("赤い円").transform.xPosition.valueAtTime(time-framesToTime(1))
ifによる条件分岐・変数の使用
ifによる条件分岐
ifによる条件分岐・変数の使用について説明する。以下は、「赤い円」という名前のシェイプレイヤーを作って、その不透明度を、1秒以前は100%、1秒以降は0%にしたいときのエクスプレッションである。(もちろん、エクスプレッションを書くよりもキーフレームをうつほうが速いのだが。)

if(time < 1){
value = 100; // ;とvalue=は省略可能。
}else{
value = 0;
}
このエクスプレッションは次のように読める。timeが1秒未満なら、不透明度の値に100を代入するが、そうでない場合(timeが1秒以上の場合)には、不透明度に0を代入する。
変数の使用
つぎに、この透明になる秒数(今は"1")を、スライダーなどで、もっと楽に操作できるようにしたいとする。そのために、まず、そのシェイプレイヤーに、「スライダー制御」というエフェクトを追加してみよう。

このスライダーの値で、赤い円が透明になる秒数を制御したい。このスライダーの値は、「thisComp.layer("赤い円").effect("スライダー制御")(1)」と表せる。(なぜこうなるか分からない人は、さきほどの「値を同期する」セクションを読み返してほしい。)
なお、今回は同レイヤー内の参照だから、thisLayerを使って、「thisLayer("赤い円").effect("スライダー制御")(1)」のように書いても問題はない。
これを先ほどの不透明度のエクスプレッションに使ってみよう。
if(time < thisLayer("赤い円").effect("スライダー制御")(1)){
value = 100;
}else{
value = 0;
}
これでも動くが、ifステートメントの中身が見にくい。変数を用いて、見やすくしてみよう。
const sliderAtai = thisLayer("赤い円").effect("スライダー制御")(1);
if(time < slideAtai){
value = 100;
}else{
value = 0;
}
sliderAtaiという変数を新しく作って、thisLayer("赤い円").effect("スライダー制御")(1)を代入している。それをifステートメントの中で使って、見やすくしている。
sliderAtaiの前にあるconstという文字は、今後はsliderAtaiに新たに代入したいりして上書きしませんよという命令であり、変数を間違って上書きしてしまわないようにするのに便利だ。(もし代入しようとしてしまうと、エラーが返ってくる。)多くの場合constを使えばいいが、再代入する予定がある場合には、letを使う(詳しくは調べてほしい。)
const sliderAtai = thisLayer("赤い円").effect("スライダー制御")(1);
if(time < slideAtai){
100;
}else{
0;
}
結論
random、seedRandom、linear、値の参照、valaeAtTime(とframesToTime)、ifステートメント、変数の宣言について解説した。次の記事では、これらの関数をエクスプレッションセレクターで使いつつ、複雑なテキストアニメーションを組んでいく。