2015-09-15

グラフエディターを使わずにエクスプレッションのみでイージングする

[2023-04-19 追記: 複数キーフレームに対応したイージングのパターンも追加しました]
[2023-04-13 追記: 最近のCC版では動作しなくなっていたので修正(if文の中へ戻り値を格納)、thisPropertyをvalに初期代入]

[2015-09-15 追記: eの説明とライセンスの表記が不適切だったので修正しました]

初投稿です。普段は自分のサイトのほうでいろいろ書いているのですが、たまにはこちらにと思い立った次第です。

通常キーフレームアニメーションに緩急をつけるにはグラフエディターでハンドルを操作して行いますが、エクスプレッションを用いるとわざわざグラフエディターを開くことなく簡単にキー間を補間(Easing)することが可能になります。
有機的な動きをつくる際に役に立つかと思われます。
※ちなみにコードの中のハイフン(-)の後ろに半角スペースがあると、AEでペーストしたときにうまく認識してくれないようです。



Introduction

まずこの記事の概要および注意点は以下の通りです。
  • 動画では2つしか紹介していませんが、本記事で解説するのは「EaseInOut」「EaseOutExpo」「EaseInExpo」「Step(階段)」の4項目です。
    動きの正確な名称が不明だったので、とりあえずjQueryのEasing Pluginから名称をお借りしました。
  • この手法はグラフエディターでの編集が面倒な時や、グラフエディターではEasingしにくいプロパティにオススメです。
  • nearestKey(time)を用いると任意数のキーフレームを補間できますが、今回はとりあえず2つの適切に時間と値が離れているキーフレームがあることを前提にしています(後述の階段グラフ以外)。
    時間と値は近すぎると適切に補間できないことがあります。
  • 動作はCS5.5で確認しています。基本的な数学の関数しか使っていないので、おそらく他のバージョンでも動作すると思われます。
  • 位置のプロパティなどに直接適用するとレイヤー数によっては重くなるので、その場合はスライダー制御などを経由させたほうが良いかもしれません。
一応明記しておくと、ライセンスはCC0です(最初はPDかと思ったのですが、いろいろややこしい事情があるようなので、こちらで)。全体的に荒削りなので、自分ならもっとスマートにできる!というコメント等大歓迎です。

1. EaseInOut

以下のような画像の動きです。リニアなグラフは元のパラメーターで、曲線がエクスプレッション適用後のグラフです。
pic001_easeInOut
この動きを実現するのは極めて簡単で、2つのキーフレームのパラメーターを取得して、AE標準のease()で補間するだけで終了です。
ease()の詳しい解説は省きますが考え方としては線形補間:linear()に近く、ある値の変化を、関連して変化する数(関数)として補間して返すという点では一緒です。
実際にエクスプレッションとして書き起こすと

val = thisProperty; /* ここでキーフレーム済みプロパティを指定 */
t1 = val.key(1).time;
t2 = val.key(2).time;
ease(time, t1, t2, val.key(1), val.key(2));

となります。一行目のvalは右辺が空欄になっていますが、当然そのままでは動きませんので、キーフレームが2つ打たれているプロパティをセミコロンの前に指定してください。
※2023-04-13 初期値を thisProperty にしました。動かしたいプロパティにそのままエクスプレッションを打つだけで基本動くようになりました。
自分自身をピックウィップで指定するのもOKです。

※グラフの表示は2種類あって、エクスプレッション用のグラフは「=」アイコン隣のグラフボタンを押すことで表示できます。
ちなみに、スライダー制御を指定するときは、
effects("スライダー制御エフェクト名")("スライダー")
ではなく、プロパティが1つしかないのでインデックスで
effects("スライダー制御エフェクト名")(1)
と指定すればバージョン間や異なる言語間でのやりとりが楽になるのでおすすめです。

2. EaseOutExpo

同様の動きはExpoの他QuartとかCubicとかQuintなどありますが、概形としては概ね同じですね。
(ちなみに記事を書いていて今QuintではなくExpoだと気づいたので動画の録画部分は修正が間に合っていません……)
pic002_easeOutExpo
最初に大きく変化して、その後緩やかに第二キーフレームの値に近づいていくという動きです。エクスプレッションでは、

val = thisProperty; /* ここでキーフレーム済みプロパティを指定 */
p1 = val.key(1);
p2 = val.key(2);
t1 = val.key(1).time;
t2 = val.key(2).time;

rate = 2; //thresholdによる自動調整を微調整可能
threshold = 1/(t2 -t1 + 1)*10 *rate;
damper = threshold; // 4 ~ 8 くらいが妥当, threshold代入で自動調整

t = (time -t1)*damper;
output = (p2 -p1) / Math.exp(t);

if (time <= t1)
{
p1;
}
else if (time >= t2)
{
p2;
}
else
{
output*-1 + p2;
}
//threshold
//↑のコメントアウトを解除すると一時的に確認可能


となります。先程のパターンと同様、valの右辺に適切なプロパティを指定します。

Expoでは少し記述が長くなっていますが、Exponential Function(自然対数の底であるeのべき乗)を元のパラメーターに合成することでこのような動きを実現しています。
コメント文の通り、damperによって曲線の曲がり具合(減衰率)を調整することが可能で、直接ユーザーが整数値を代入することも可能ですが、変数thresholdを代入すれば2つのキーフレーム値に応じて自動で調整されます。エクスプレッション用グラフを表示させた状態で動画のようにキーフレームをドラッグすれば、自動で調整される様子が一目瞭然です。

その自動調整についても、rateの値をいじることでさらに微調整を加えることもできます。
値を大きくするとより早く変化し、小さくすると最終値への到達が遅くなります。
ただし、rateもdamperも1以上の値を設定してください。1~0でも設定はできますが、値によっては最終値に漸近しなくなります。

最後の//thresholdの//を消せば現在のしきい値を確認することもできます。

3. EaseInExpo

2.の逆で、後から急に変化する動きです。
pic003_easeInExpo
エクスプレッションの記述内容としてはOutExpoと似ていて、所々逆転している感じです。

val = thisProperty; /* ここでキーフレーム済みプロパティを指定 */
p1 = val.key(1);
p2 = val.key(2);
t1 = val.key(1).time;
t2 = val.key(2).time;

rate = 2; //thresholdによる自動調整を微調整可能
threshold = 1/(t2 -t1 + 1)*10 *rate;
damper = threshold; // 4 ~ 8 くらいが妥当, threshold代入で自動調整

t = (time -t2)*damper;
output = (p2 -p1) / Math.exp(-t);

if (time <= t1)
{
p1;
}
else if (time >= t2)
{
p2;
}
else
{
output + p1;
}
//threshold
//↑のコメントアウトを解除すると一時的に確認可能


使う場合はvalの右辺にキーフレームが打たれたプロパティを追加します。
2.と同じくratedamperの値を調整することで、曲線の調整が可能です。

4. 階段状(Step)

階段関数(ステップ関数)というものがありますが、キーフレーム間を補間せずにカクカクした動きになります。
テキストレイヤーのソーステキストにキーフレームを打った状態、といえばわかりやすいかと思います。
pic004_stepFunc
このエクスプレッションは3つ以上のキーフレームでも使えます
普通であれば階段状にするにはグラフエディターから、キーフレームを停止に変換するボタンを押す必要があり面倒ですが、エクスプレッションを使えば一発です。

階段状にする手法は2つあって、タイミングを考慮せず本当にただ階段状にするだけなら
effect("Const")(1).nearestKey(time);
……と書くだけで終わります。が、これはキーフレーム間の半分の時間から変化してしまうので扱いづらいです。
下のコードであればキーフレームの打たれた位置から変化するので、ボタンを押したときと同じ動きを再現できます。

val = thisProperty; // ここでキーフレーム済みプロパティを指定
near = val.nearestKey(time);
if (time >= near.time)
{
i = near.index;
}
else
{
i = Math.max(near.index-1, 1);
}
val.key(i);

記事を書いている途中で思いついたので、もう少しスマートな方法があるかもしれません(動作はきちんと確認しています)。
概要としてはnearestKey()によって直近のキーフレームを取得し、現在時間との比較から直前のキーフレームの値を維持するようになっています。また、Math.max()によって参照するキーフレームのIndexが0になる(=エラーが発生する)ことを防いでいます。

応用

(2023-04-19 追記)
さらに応用することで、緩急をつけるアニメーションを自動でつけることも可能です。
キーフレーム数が多いとイージングも大変ですが、下記Expressionを適用することで、
パラメーターを入れていくだけでキーフレームの前後間を自動でイージングさせることができます。
(この例では 2. の 急 → 緩 になる動きをつけています)

val = thisProperty; // ここでキーフレーム済みプロパティを指定
near = val.nearestKey(time);
if (time >= near.time)
{
i = near.index;
}
else
{
i = Math.max(near.index-1, 1);
}

i_after = Math.min(i+1, val.numKeys);

p1 = val.key(i);
p2 = val.key(i_after);
t1 = val.key(i).time;
t2 = val.key(i_after).time;

rate = 2; //thresholdによる自動調整を微調整可能
threshold = 1/(t2 -t1 + 1)*10 *rate;
damper = threshold; // 4 ~ 8 くらいが妥当, threshold代入で自動調整

t = (time -t1)*damper;
output = (p2 -p1) / Math.exp(t);

if (time = t2)
{
p2;
}
else
{
output*-1 + p2;
}
//threshold
//↑のコメントアウトを解除すると一時的に確認可能



- – - – - -

今回は4つのパターンのみの紹介でしたが、三角関数との合成で振動する動きを実現するなどの余地はあるので、興味のある方はぜひ挑戦してみてください。
機会があったらその辺も含めてまた記事を書くかもしれません。



タグ : , , , [タグを追加する]


この記事の投稿者について:ひよこ(カラクリ)@AEP
普段はサイトの方でいろいろ覚え書きを書いています。

フィードバック

1 Star2 Stars3 Stars4 Stars5 Stars
(評価回数:5 , 平均:3.40)
Loading...Loading...

コメントをどうぞ!




特集