
0️⃣はじめに
CGデザイナーの川村(@tsumiki_room)です。
今回はCavalryのスタディを題材に、同じ動きをTouchDesignerで再現してみました。
単に見た目を模倣するのではなく、Cavalryの考え方を取り入れた実装のほうが、構造をシンプルに保ちやすく、結果として扱いやすくなることがわかりました。
本記事では、その違いを具体的なプロジェクトを交えて整理します。
プロジェクトファイルのダウンロードはこちら
→20251224_TouchDesigner_TimeOffset
1️⃣Cavalryとは
Cavalryは、モーショングラフィックス制作を目的としたノードベースのソフトウェアで、近年注目を集めているツールのひとつです。
TouchDesignerのようにデータフローを自分で組み立てるツールとは異なり、モーションに関する振る舞いがあらかじめ抽象化された形で用意されているため、比較的スピーディーに開発を進めることができます。
Cavalryそのものの説明は岩木くんのこのブログがおすすめなので気になる方はそちらを参照してください。
→Cavalryってどんなツール?After Effectsとの違い – 特徴編
2️⃣今回題材としたCavalryのスタディ
以下は、元となったTristan Jung氏のスタディです。
プロジェクトは
→Procedural Glitch
からダウンロードできます。
見た目の印象を説明すると…
- グリッド状にレイアウトされた複数のボックスで構成されている
- ボックスはまず Y方向に移動 しながら、同時に 縦方向に大きくスケール する
- 縦横比は要素ごとにランダムだが、全体として Y方向が長くなる傾向 がある
- モーションの開始タイミングは 外側の要素から順に始まり、中心が最後 になる
- Y方向の移動が終わると、各ボックスは 直ちにX方向に同様の移動とスケール を行う
- 移動後、ボックスの縦横比は 1:1 に揃う
- その際の Uniform Scale は要素ごとにランダム に設定されている
- 一連の動きは 逆再生するような形で元の状態に戻る
3️⃣まずはそのままTouchDesignerで再現してみる
見たままTouchDesignerで再現してみました
どのようになっているのか簡単に説明します
プロジェクトの中にあるCase1というBaseCOMPを確認してください
以下のようにノードが組まれています
上からコントロール用のCHOP群、ポジションの制御、スケールの制御、色の制御といった順に組まれていて、最後にポイントをCopy POPにしてレンダリングしています

一番上にあるControlというところにパラメータを集約してあります
Fieldというスライダを0~1まで上げ下げするとアニメーションが走る仕様になっています

では、順を追って何をしているのか解説します
1. 各アニメーションでのPositionをAttribute化しておく

- field1では中央から外に向かって円形のグラデーション状に数値が広がっていくようにしてあり、Radiusを大きくしていくことで中心から外に向かって数値が増えていきます
- random1では最終的に変化しきった時のポジションを作って”endP”というAttributeに格納しておきます
- Mathcombine1では初期位置を”startP”として、”endP”で作ったポジションのY成分のみの“midP”というAttributeも作っておき、いったん初ポジションを”startP”に戻しておきます
2. アニメーションの進行度を指定する

- rerange1では初期ポジションをfield1で作った“weight”というAttributeが0~0.5のときに“startP”から“midP”へ位置が移動するように、“startWeight”という0~1へ変化するAttributeを作ります
- rerange2では“midP”から“endP”へ移動するための”endWeight”を作ります
- rerange3は最終的に等倍スケールに変化するためにあらかじめ”endWeight2”というAttributeを作っておきます
3.mix関数を使いポジションにアニメーションをつける

mathcombine2ではmix関数を使って各アニメーションをつないでいます
“startP”から“midP”を“startWeight“の0~1の数値でつなぎ、
“midP”から“endP”を”endWeight”でつないでいます
4.各段階のスケールをランダムで作っておく

- attribute1では“Pscale”というAttributeを作っておきます
- random2,random3,random4では
それぞれ”PscaleA”,””PscaleB”,””PscaleC”というAttributeでランダムな数値を入れています
”PscaleA”はY移動時のスケールなのでタテに長く、
”PscaleB”はX移動時のスケールなのでヨコに長く、
”PscaleC”は最終的に等倍にしたいのでXYともに同じ数値になるようにしています
5.スケールにアニメーションカーブを設定する

lookupchan1で”endWeight”と”endWeight”を指定したアニメーションカーブで動作するようにします
6..mix関数を使いスケールにアニメーションをつける

PscaleA→PscaleB→PscaleC
の順番でアニメーションをつなげます
ポジション同様、スケールもmix関数を使ってアニメーションが遷移するようにします
7.カラーを設定する

random5で”rand”というAttributeを作り、lookuptex1を使ってTOPで作った色を着ける
8.レンダリングする

copy1でポイントをRectangleに置き換えてレンダリングしたら完成です
4️⃣複雑になりすぎていないか?
前章までで見てきたように、見た目としては目的の動きを再現できているものの、実装全体としてはやや過度に複雑な作り方になっていることに、多くの人がうすうす気づいたのではないかと思います。
「動いてはいるが、理解しやすく再現しやすい実装か?」と考えると、少し首をかしげる部分があります。
なぜ複雑になったのか?
複雑になった原因は、オブジェクトごとの時間差やモーションの進行といった時間に関する問題を、Attributeを使った条件分岐で解決しようとした点にあります。
その結果、フェーズ管理や分岐が増え、フローが段階的に肥大化していきました。
複雑化のデメリット
- 把握にコストがかかる
- 後から見返した際に「どこで何が起きているのか」を理解しづらくなります。
これは他人だけでなく、自分自身にとっても同様で、少し時間が空くだけで把握し直す必要が出てきます。
- 後から見返した際に「どこで何が起きているのか」を理解しづらくなります。
- アイデアを考える段階で再現性が低い
- 今回のように高度で複雑なフローは、「この表現を作ろう」と考えた瞬間に自然と選択肢に上がってくるものではありません。
ツールの手癖や普段の思考プロセスから外れた構造は、発想の起点として使いづらく、結果として新しいアイデアを生みにくくなります。
- 今回のように高度で複雑なフローは、「この表現を作ろう」と考えた瞬間に自然と選択肢に上がってくるものではありません。
- 他のアイデアと組み合わせにくい
- 構造が特定の表現に強く依存している場合、別の表現やルールを組み合わせようとすると、大きな組み替えが必要になります。
結果として、このような実装は「動くこと」や「再現できること」は満たしていても、次の制作でも自然に使いたいフローにはなりにくい、という状態になります。表現として成立している一方で、制作の起点や土台としては扱いづらい、という違和感が残りました。
こうした点を踏まえると、今回の実装で問題だったのは複雑さそのものではなく、複雑さを引き受けるレイヤーを誤っていた可能性にあるのではないか、という考えに至りました。
そこで次に、Cavalry側のプロジェクトを改めて見返し、この動きがどのような設計で成立しているのかを確認してみることにしました。
5️⃣Cavalryのプロジェクトを見返して気づいたこと

このCavalryプロジェクトは、見た目としては複雑に見えるモーションに対して、構造自体はシンプルです。その肝となっているのが
Stagger(Offset in Time)です。
Staggerとは
Staggerは、Cavalryに用意されている機能のひとつで、複数の要素に同じモーションを適用しつつ、要素ごとに再生タイミングをずらすための仕組みです。
各要素の構造やアニメーション自体を変えることなく、ローカルな時間軸をオフセットすることで、全体として複雑な動きを生み出します。
Cavalry公式Staggerについての解説
試しに、Staggerのなしとありのモーションを比較してみます。
Staggerを使うことで同時に動いていた動作がズレて動き出して、複雑なモーションを作り出していることがわかります。
では、このStaggerによる時間のズレを、TouchDesignerではどのように扱えばよいのでしょうか。
CavalryのStagger的な考え方をTouchDesignerに持ち込み、再現する方法を考えてみることにしました。
6️⃣TouchDesignerでStaggerをつくってみた
プロジェクトの中にあるTest_StaggerというBaseCOMPを確認してください
このように再現しました

緑の部分がStagger同様、時間をオフセットしている部分です。
どのようになっているか見ていきましょう。
1.オフセットさせるAttributeを作っておく

Attributeを時間でオフセットする仕組みなので、なによりまずAttributeを用意する必要があります。
今回は
P : ポジション、PointScale : スケール、rot : 回転、Color : 色
の4種類のAttributeを事前に用意して、そこに簡単なアニメーションをつけています。
2.各AttributeをTOPとして取り出す

この部分がStagger的処理をしている部分です。
任意のフレームぶんキャッシュを貯めたいので、オフセットしたいAttributeからTOPで作ります。
POPには現状、各Attributeを異なる時間オフセットで参照する機能が見当たらなかったのでTOPを使っています。
Cache POPというそれらしいものがあるんですが、指定した単一のフレームを保持するような仕様だったため今回の用途とは合いませんでした。

例えばこれは”P”のPOPto TOPです。
このようにAttributeを取り出したい名称で指定して、
Pixel LayoutをOne Rowにします。
3.Feedback TOPでフレームをキャッシュする

Feedback TOPを使って指定した幅のフレームを画像で保持しておきます。
画像の上に行くほど古いフレームになります。

まずFit TOPでフレームぶんの領域をつくります。
解像度はXがAttributeのカウント数、Yが保持するフレーム数です。
保持するフレームの半分+0.5 をTranslate:Yのマイナス方向へ代入することで、画像の最低辺にAttributeの画像いる状態になります。

Feedback TOPで毎フレームAddしていくサイクルを作ります。
毎フレームごとに1pixelずつズレて蓄積させたいのでTransform TOPをはさんでTranslate:Yを1pixelとします。
これで任意の範囲のフレームを蓄積する仕組みができました。
4.Indexごとにオフセットを指定する

どのIndexがどのフレームを取るのか(どのくらいオフセットするのか)を指定します。
今回は正規化したIndexをそのままオフセット量に利用しています。
Remap TOPの上の入力にfeedback結果、下の入力にIndexをつなげるとYすべてがオフセットされた値になるので、あとはFit TOPでもとの解像度に戻しておきます。
5.LookupTex POPでAttributeを置き換える

あとは各Attributeをオフセット後のものと差し替えるだけです。

これは“P”の置き換え処理です。
Lookup Index Attribute U : Index
Output Attribute Scoope : P
としています。
Pはvector3なのでChannel MaskをRGBまでにしておきます。
ほかのAttributeも同様に置き換えると、Stagger的なタイムオフセットができます。
7️⃣あらためて作例を再現してみた
プロジェクトの中にあるCase_StaggerというBaseCOMPを確認してください

Staggerから学んだモーションの考え方を実装することで、Stagger部分を除けばシンプルな構成になりました。
8️⃣まとめ
CavalryのスタディをTouchDesignerで再現する中で、時間の扱い方が実装構造に大きく影響することが明らかになりました。
構造で時間差を解決しようとするとフローは複雑化しますが、時間をパラメータとして扱うことで、同じ動きをより整理された形で実装できます。
今回の検証が、モーション実装における設計判断の参考になれば幸いです。