Exteはパス点をまとめてヌルで操作できます。それを使ってバウンスさせるとき「どの方向にバウンスさせるか」が指定できると便利なので作ってみました。
*Dan Ebberts氏のかの有名なバウンス(オーバーショット)の式を基にしております。
MotionScript.com 『Realistic Bounce and Overshoot』
適用方法
エフェクト『スライダー制御』を3つ作ってamp、freq、decayと名付ける。
エフェクト『角度制御』を1つ作って rot と名付ける。
以下のエクスプレッションを位置(XY分割無し)へ適用。
rot = effect("rot")("ADBE Angle Control-0001");
rad = degreesToRadians(rot-90);
dirVec = [Math.cos(rad),Math.sin(rad)];
amp = effect("amp")("ADBE Slider Control-0001");
freq = effect("freq")("ADBE Slider Control-0001");
decay = effect("decay")("ADBE Slider Control-0001");
if( marker.numKeys === 0 ){ t = time - inPoint;}
else{ t = time - marker.key(1).time;}
if( t >= 0 ){ value + dirVec*amp*Math.sin(t*freq*Math.PI*2)/Math.exp(t*decay);}
else{ value;}
おすすめ数値は30fpsの場合 freq 5 decay 6 ですね。
エフェクトのrotでバウンスする角度を調節できます。
マーカーがあればそこでバウンス、なければレイヤー開始時間でバウンスするようにしてあります。
解説
後半はほぼ元にした式と同じです。延々と続くうねうねしたサイン波を、指数関数的に増えていくグラフで”割る”と、サイン波が指数関数的に”減っていく”といったイメージです。
付け加えたのは前半です。単一値ならば出来上がったグラフそのままでいいんですが、今回は結果を座標にしたいので、「出来上がったグラフ×指定方向へ向かう長さ1の単位ベクトル」にします。単位ベクトルというと難しいようですが非常に簡単で、要するに「斜めにもできる定規の1目盛り」くらいの意味です。「斜めにした定規の1目盛り」をPCに理解させるためにも、[Xに○○進んだとこ、Yに××進んだとこ] という[X,Y]の形になります。
この[X,Y]が何目盛りあるか、が結果となるので、出来上がったグラフを掛けているわけです。
そして、そのままでは原点からになるのでvalueを足しています。
単位ベクトルを出す式は、たいてい「2点をベクトルにして、XとYをそれぞれ斜め線の長さで割って」みたいなことになります。が、今回は2点ではなく方向が(ユーザーの意思によって)決まっているので、回転から座標への式を使って「 [1,0]が?度回転したとき値」を出します。以下、回転から座標の式です。
回転結果X =xcosθ−ysinθ
回転結果Y =xsinθ+ycosθ
文系人間の数学忘れてる度は(筆者を含め)ハンパないので詳しく書きます。
θ (シータ)っていうのが角度で、Math.sin()とかの中に入れるためにはラジアンという単位にせねばです。
なぜθかというと、冗談みたいな話ですが、ギリシア語の中で θという文字がたまたまあって、それの見た目が「〇に線が入ってて角度を表してるっぽくね?」 くらいのものみたいです(所説あり&筆者の予想も含む)。
xcosθ は x × cosθ です。
cosθは cosθで一つの数値です。 cos×θではありません。
「cosθって記号っぽいからこれも答え出さないとだよね?」と思ったりしますが、cosθはθ(つまり角度)が決まれば勝手に決まる数値です。
勝手に決まると書きましたが、昔は実際に計った早見表を見たり、今はPC内でなにやら難しい計算をしてけっこう瞬時に出しているようです。
ここまでくると「そもそもsinθとかcosθって何?」となりますが、「直角三角形の辺と辺との比率」です。「直角三角形のある辺を1としたときに、別の辺は何割か? 」ですね。ある辺と別の辺がそれぞれどこかはsinかcosによります。
この比率は三角形の他要素(大きさとか)に関係なく数値で出ます。記号ではなく数値で出るので、三角関数の定理やらの穴埋めが数値ででき、色々別のこと(辺の長さやら、逆算で角度やら)が分かって便利、ってことです。
さて、では回転式を使って[1,0]を回転させたベクトルを得てみます。
pt = [1,0];
rot = effect("rot")("ADBE Angle Control-0001");
rad = degreesToRadians(rot);
rotX = pt[0] * Math.cos(rad) - pt[1] * Math.sin(rad);
rotY = pt[0] * Math.sin(rad) + pt[1] * Math.cos(rad);
dirVec = [rotX,rotY];
上記が丁寧に書いた式です。pt[1]つまりゼロに掛けているところは結局ゼロになるので、pt[1] *なんちゃら部分は消します。pt[0]も1なので、わざわざ掛けても同じ数値になるだけで必要がないので pt[0] *を消します。
そうすると pt 自体がいらないので消します。
そして、角度エフェクト欄のノブは上がゼロ度なので、[1,0]だと右がゼロ度始まりになってしまうのでrotに―90します。すると以下の式になるというわけです。
rot = effect("rot")("ADBE Angle Control-0001");
rad = degreesToRadians(rot-90);
dirVec = [Math.cos(rad),Math.sin(rad)];
ついでに追加したマーカーありなし分岐ですが、
これはnumKeysでマーカーがあるかないかを判断し、あればマーカー地点を時間ゼロ地点にし、なければインポイントを時間ゼロ地点にしています。
以上です!
Exteでのパス点ヌル操作は、バウンスのみならず色々なアイディアが生まれそうな機能なので、ぜひともご活用ください!