9
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

映像オペレーション用システムのUI構築

Last updated at Posted at 2022-12-12

この記事はTouchDesigner Advent Calendar 2022の12日目の記事です。

株式会社レイという映像機材を扱う会社でエンジニアをしています。
TouchDesignerで映像オペレーションをする上でのUIを構築することになりました。
これまでちゃんとUIを組んだことが無かったので、今回は学習の共有です。

UI構築の経緯

現在弊社ではスイッチャーやメディアサーバの他にV出しにはRolandのPR-800HD、VJ的にレイヤーで出す時はRosolumeのArenaなどを使ったりします。

PRはシンプルで使いやすいのですが、4KのV出しができません。Arenaはアウトプットの切り出しが簡単でLED出しの時に便利なのですが、TDと併用になると最初からTDで完結できるのでは?と思いました。

また今後TDを使った汎用的な演出や仕組みを開発した時に、それを組み込むベースとなり自分以外のオペレータ(非TDエンジニア)も違和感無く使えるシステムが必要と考え、今回のUI構築となりました。

完成のイメージ

Figmaで何となく完成時のイメージを作りました。
20221130_MokuMoku.png

UIを作る上でのポイント

個人的には以下の3つがポイントと考えました。

  • Panels系COMPの挙動・機能理解
  • CloneとExternalを利用した静的複製
  • ReplicatorCOMPによる動的複製

1. Panels系COMPの挙動・機能理解

1-1. 親子関係を作る上での使い分け

UIを作る時はCOMPのPanels系を階層化するかオペレータの上下のワイヤーを繋げて親子関係を作ります。
スクリーンショット (77).png

シンプルなUIな場合は、Base COMPでオペレータをまとめる時のように階層構造で問題無いです。しかし複雑なUIを作ろうとすると、階層がどんどん深くなってメンテナンス性が最悪になります。

極力ワイヤーで親子にしつつ、細かすぎるパーツや後述の複製が発生する場合は階層化します。
スクリーンショット (79).png
(現在構築途中のNetwork Editor画面)

1-2. 各UIパーツをキレイにレイアウトする

基本的には子のLayoutのModeをFillにして、親のChildrenのAlignを指定すればキレイになります。
スクリーンショット (75).png
子の位置を整頓したい場合
Justify Horizontal/Verticalを指定

パーツとパーツの間に隙間を空けたい場合
SpacingMargin

パーツを正確な比率(7:3など)に整頓したい場合
⇒ 子のModeをAnchorsに設定、対応させたいCOMP同士をReferenceで紐づける
スクリーンショット (80).png

1-3. パーツごとに特定の機能を付与する

アプリケーション「らしい」振る舞いをするには、これらの実装が必要です。

  • ドラッグ&ドロップ
    Drag/DropのDrag/Drop Scriptを設定することで、動画のセットなどができます。
    スクリーンショット (90).png
    詳しくはJoe君がアドベントカレンダー20日目の記事で解説してくれます(丸投げ)

  • 右クリックでメニュー表示
    Info CHOPPanel CHOPを使って操作を検出することで、メニュー表示などができます。

  • MIDIやOSCと紐づける際のTIPS
    MIDIコンとTD上の数値を紐付けた際に、数値だけ何らかの理由で変えた場合コントローラと数値の間に差が生まれてしまい、操作した際にガクッとなってしまいます。これを避けるため、Bind CHOPChannel PickupをOnにすることで、コントローラが同じ値になるまで数値が変化しないようにすることができます。
    スクリーンショット (89).png

1-4. 結局「Widget COMP」って何?

半自動的かつ一括でCOMPのParameterをUI化する時に使います。
PalleteからbasicWidgetsautoUI、さらにUI化したいCustom Componentが設定されたCOMPとUIを表示するためにContainer COMPを用意します。autoUIのUIとCustom COMPのところに上記の2つを紐付けてGenerate UIをPulseすると、UIが生成されます。
スクリーンショット (81).png
便利と言えば便利ですが、現状Widget COMP単体ではContainer COMPと挙動が基本変わらないことと、自分でパーツごとの見た目や機能は制御したいので使いません。

2. CloneとExternalを利用した複製

2-1. Clone機能の基本とOperatorのImmutable化

UIを作る際に、共通して同じ見た目・機能を持ったパーツを複数作ることになるのが通常だと思います。
しかしパーツごとに独立したCOMPにしてしまうと、後から変更を加える時個別に1つずつ変えなければいけなくなってしまいます。この問題を解決するのがCloneという機能です。

Clone先のCOMPのCommonタブにあるEnable CloningをOnにし、Clone元となるCOMPをClone Masterに設定することで、Clone元の変更が一括でClone先に反映されます。またClone元のCOMP内にあるオペレータのClone Immuneフラグを立てることで、そのオペレータのParameterをユニークにすることができます。
スクリーンショット (82).png

2-2. 複製したパーツに異なる見た目・機能を設定する

上記のようにImmuneにすることでCOMP内のParameterをユニークにしても良いのですが、実際の運用上は別の方法を採用しています。CloneにはClone元のCOMP自体のParametersは変更されないという仕様があります。この仕様を生かして、ユニークにしたいParameterをCustom Componentに設定してあげる方が参照先が一元化されて、後から調整しやすいです。
スクリーンショット (83).png
個別化してしまうと結局まとめて変更したい時に面倒ではと思うかもしれませんが、Custom Component自体は共通化されているので、変更したいCOMPを複数選択して1か所変更すれば一括で変えられます。これも先述の親子関係を極力階層で作らない/Custom Componentでユニーク化するという2点のメリットです。

2-3. Operatorのコンポーネント化とExternalによる共通化

作成したUIやパーツを別プロジェクトで使いたい場合があると思います。
その時は使用したいオペレータを右クリックし、Save Component .toxでtoxファイルとして保存します。このtoxを参照させたいオペレータのCommonタブにあるExternal .toxに設定することで、Cloneと同じように元のtoxと共通化されます。
スクリーンショット (84).png
ただtox化した時、toxの変更を参照元に反映させようと思うと一々Saveし直すのが面倒です。その問題を解決するのがSatoru Higaさんの「ExternalToxSaver」です。Gumroadにて3ドルで購入できます。

3. Replicator COMPによる動的複製

3-1. Replicator COMP機能の基本

Replicator COMPのOperator Prefixで複製したいオペレータを指定、Replication MethodBy NumberにしてNumber of Replicantsで数値を設定することで、その数値分だけ指定したオペレータが複製されます。
スクリーンショット (85).png
またReplicator COMPのcallbacksの中でc.outputConnectors[{OUT}].connect({IN})と記述することで複製時に元のオペレータのOUTを特定のオペレータ(例えばSwitch TOPなど)にINにすることが出来ます。

replicator2_callbacks
def onReplicate(comp, allOps, newOps, template, master):

	sw = op('switch1')

	for c in newOps:
		c.outputConnectors[1].connect(sw)
		
		#c.display = True
		#c.render = True
		#c.par.display = 1
		#c.par.clone = comp.par.master
		pass

	return

CHOPの場合はSelect CHOPCHOPs{Operator Prefix}*/out{num}という形で記述することで、callbacksに書かなくともOUTの数値をまとめることが出来ます。
スクリーンショット (86).png

3-2. 特定のOperatorのParameterUIを動的に複製する

Parameter COMPを使えば簡単にオペレータのParameterをUI化することができます。この時、CommonタブのParameterは不要な場合がほとんどだと思います。TIPSとしてはPage Scope^Commonと記述する事で、CommonタブだけをUI化から外すことができます。
スクリーンショット (88).png
ただこの方法だと、UIの見た目がParameter COMPに依存してしまいますし、実際にUI化したいParameterは決まっていることが想定されます(すべての読み込んだ動画にLevel TOPのOpacityのparameterを付けたいなど)。

なので、Cloneを使った複製の時と同様、UI化したいParameterをCustom Componentとして設定し、その値をParameter DATなどで取得、Replicator COMPのTemplate DAT tableの設定とcallbacksの組み合わせによって、UIを生成します。こうすることでCloneを使うにしろReplicatorを使うにしろ、ワークフローとフォーマットが共通化できます。

この辺りは今度追記します。。

3-3. CloneとReplicatorCOMPの使い分け

結論だけ言うと、複製するUIを静的(決まった数・形式)に変更する場合はClone、動的(柔軟に増減する)な場合はReplicatorという使い分けになると思います。

終わりに

UIに関する記事は数多くあり、焼き増しの内容も多かったかと思います。
本来はアルファ版まで出来たものをこの記事のタイミングで公開する予定だったのですが、間に合わず初歩的な内容に終始してしまいました。

また開発途中のシステムとUIが出来た際には、そこから得た知見を共有したいと思います。

参考サイト

9
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?