複数のレイヤーを円状(放射状)に配置しましょう。
カードみたいなものを丸く、放射状に、くるっと並べたいみたいなこと多いですよね。
観覧車のチュートリアルが有名ですが、並べた状態で回転とかうまくヌルや親子、エクスプレッションを使って作っていますでしょうか。これを発展させてみました。
ではプログラミングするために、どんな仕掛けにしたいかを言葉にしてみます。
- 観覧車のようにレイヤーを配置したい
- よくある親子付けでなくコントロールレイヤーで一括管理したい
- 円のサイズは調整したい
- 全体を回転させたい
- 位置だけ回転でレイヤー天地は固定できてもありがたい
すんなり言い表せました。エクスプレッションもシンプルにできると嬉しいですが、やってみましょう。
言葉を式に変換していく
コントローラーを準備(序)
ではまずコントローラー用のヌルを置きます。これを中心に円状に配置するようにしたいです。「circle_Control」とリネームします。
これで円のサイズを調整したいので、スライダー制御エフェクトを「circlrサイズ」という名前で追加しておきます。
レイヤー準備のルールとコントローラー(破)
円状に配置するには、例えば1周360°を、配置するレイヤーで割って角度を求める必要がありますね。
…配置するレイヤーの数?スクリプトなら選択しているレイヤー数を検知できますが、エクスプレッションではタイムライン上の配置から考えることになりそうです。
結論、配置するレイヤーは「circle_START」と「circle_END」というヌルレイヤーの間に挟まれているレイヤーとルールを設けます。これならエクスプレッションでも全部で何レイヤー配置するのか指定できるので、360°/レイヤー数で角度が計算できます。
また、全体を回転させられるようちょっと追加します。
コントローラーに「全体回転」という角度制御エフェクトを追加し、観覧車全体を回せる準備をします。
配置用レイヤーの位置のエクスプレッション
そして基本となる配置部分です。
配置レイヤー数がわかるようになったので、360/レイヤー数で角度を求めたら、中心からの距離は「circleサイズ」で指定するので、これを位置に変換してやります。
当然、ラジアンに変換→degreesToRadians()して、Math.sin()でXの位置、Math.cosでYの位置が取り出せますので、位置のエクスプレッションはこんな感じになりました。
var ctrl=thisComp.layer("circle_Control")
var center=ctrl.transform.position
var circleSize=ctrl.effect("circleサイズ")(1);
var qty=thisComp.layer("circle_END").index-thisComp.layer("circle_START").index-1;
var now=index-thisComp.layer("circle_START").index;
var mxSp=360;
var aida=mxSp/qty;
var thisAngle=degreesToRadians((now-1)*-aida+ctrl.effect("全体回転")(1)+90);
var x=circleSize*Math.cos(thisAngle);
var y=-circleSize*Math.sin(thisAngle);
center+[x,y,0]+value;
ここまでで配置はできました。
レイヤーを個別に回転させるエクスプレッションとコントローラー(急)
さて、コントローラーの「全体回転」で観覧車のように回転はできましたが、個別にも回転させたいですよね?
コントローラーに「Z回転」という角度制御を追加しましょう。
そして配置するレイヤーの角度にエクスプレッションです。
thisComp.layer("circle_Control").effect("Z回転")(1);
これでそれぞれ回転しますわ。
角度をブラッシュアップとコントローラー(急2)
レイヤーの天地が固定されていて、柔軟性に欠けますね。
まずは自分の位置に応じて放射状に向いて欲しいこともあるので、手を加えていきます。
今度は自分の位置がわかってるので、ここから逆に角度を求めてみます。
コントローラーに「角度をキープ」チェックボックス制御エフェクトを追加し、天地の固定と放射状に向く角度を切り替えられるようにします。
放射状に向かすには中心からそのレイヤーのX,Y座標に相当する角度がわかればいいですね。
X,Y座標からラジアンを求めるにはMath.atan2(y,x)でいけます。Y,Xの順に記入するので注意。アークタンジェントと読むらしいです。数学者はこれどうやって思いつくんや。
遠回りしますが、さっきのdegreesToRadians()の逆、ラジアンを角度に変換する、radiansToDegrees()も使ってみます。
var ctrl=thisComp.layer("circle_Control");
var center=ctrl.transform.position;
var a=center-position;
var angle=Math.atan2(a[1],a[0]);
var plusAngle=ctrl.effect("Z回転")(1);
var autoRt=(thisComp.layer("circle_Control").effect("角度をキープ")(1)==1)?rotation:radiansToDegrees(angle)+plusAngle-90;
value+autoRt+plusAngle;
頭が右向いてしまうので、直感的な放射状の角度にするためにautoRtのところで左に90°戻しています。力技です。
もうちょっとこだわりたい
円弧の角度も調整可能に、とコントローラー(シン)
並べるレイヤーをまんまるじゃなくとも、ババ抜きするときのカードみたいに90°に広げることも想定したいです。
コントローラーに「広げる角度」という角度制御エフェクトを追加し、位置のエクスプレッションを変えます。
これは簡単です。
mxSp=360;
だったところを
ctrl.effect(“広げる角度”)(1);
に変えるだけです。
var ctrl=thisComp.layer("circle_Control")
var center=ctrl.transform.position
var circleSize=ctrl.effect("circleサイズ")(1);
var qty=thisComp.layer("circle_END").index-thisComp.layer("circle_START").index-1;
var now=index-thisComp.layer("circle_START").index;
var mxSp=ctrl.effect("広げる角度")(1);
var aida=mxSp/qty;
var thisAngle=degreesToRadians((now-1)*-aida+ctrl.effect("全体回転")(1)+90);
var x=circleSize*Math.cos(thisAngle);
var y=-circleSize*Math.sin(thisAngle);
center+[x,y,0]+value;
今回覚えるエクスプレッション
今回新しく学べるエクスプレッションは
Math.sin(); //サイン
Math.cos(); //コサイン
Math.atan2(y,x); //アークタンジェントの一種
degreesToRadians(); //度をラジアンに変換
radiansToDegrees(); //ラジアンを度に変換
三角関数と同じく、サインはY座標、コサインがX座標を計算でき、アークタンジェントはタンジェントの逆。
JavaScriptにあるMath.atan2はアークタンジェントの続編で、通常のアークタンジェント(Math.atan)はタンジェントを渡すとラジアンを返してくれるのですが、アークタンジェント2の方は引数が2個必要で、Y座標とX座標を渡すとラジアンを返してくれます。
タンジェントがわかってればMath.atan(タンジェント)、位置がわかっていればMath.atan2(y,x)でいけるので使いました。覚えなくていいと思います。
degreesToRadians()とradiansToDegrees()はそのまんまです。度をラジアンに、ラジアンを度に変換する際に使えます。
効率化完了
言葉にするのは簡単でしたが…中身がえぐかったですね。
ヌルレイヤーに親子付けをする方法が一般的かと思いますが、円のサイズなど、より細かく制御したいときに使えるアイディアかと思います。
ストップウォッチのあるプロパティはキーフレームが打てますので、集まる、回転する、めくれるといったアニメーションを追い込める便利な機能一式にもなりましたし、めちゃくちゃ頭の体操になりました。
もうちょっとブラッシュアップしたいアイディアもあるので、これをスクリプト化する記事にて紹介できたらと思います。
この記事へのコメントはありません。