LoginSignup
2
2

More than 1 year has passed since last update.

[TouchDesigner] Dependency Objectsを使ってPython内の数値をネットワーク側に同期する

Posted at

はじめに

私は展示系インスタレーションなどのシステム開発をTouchDesignerで行うことがありますが、状態管理や外部との通信等のためにPythonを書くことが多いです。

(以前は Table DAT に必要な情報を全部入れていたのですが、システムが複雑になると管理がしんどくなってしまいました。)

そんな中、Python Class内の変数を、ネットワーク側のoperatorにも反映したくなることが多く発生します。

この場合、例えば Evaluate DAT などでClass内の変数を引っ張ってくることができますが、これだけだと、変数の値が変更されたときに、ネットワーク側でcookが走らず、値が同期できなくなってしまいます。(なんて不便だ…)

これまでは、下記みたいにPython側に直接オペレータを変更する処理を書いていましたが、

op('text1').text = self.property

これだとノードが繋がらないため、あとでネットワークを見返した時に

  • このoperatorが一体どこのスクリプトで変更されているか?

がわかりにくく、確認に時間がかかってしまいます。

数個だけなら良いですが、大量に発生すると、メンテナンスする場合にとても大変です。

解決策

すばり、 Dependency Objects というものがあります。

Because Python does not inherently have a procedural mechanism, Dependency Objects in TouchDesigner allow python data to cause downstream cooking when that data is changed.

Dependency Objects を使うことで、Python側の数値が変わったときにダウンストリームのcookが走るようになる。と書いてあります。ありがたい。

サンプルプログラム

こちらにアップしました。
https://github.com/genkitoyama/TD_Dependency_sample

使い方

ネットワーク側で参照したい変数に、 tdu.Dependency(初期値) と入れればOKです。これだけ。

例えば、

  • int なら tdu.Dependency(0)
  • string なら tdu.Dependency('')
  • list なら tdu.Dependency(['hoge', 'fuga'])

などなど。

中身の値を get/set するには、 val メンバを使います。

hoge = tdu.Dependency(0)
print(hoge) #type:Dependency val:0
print(hoge.val) #0

hoge.val += 1
print(hoge.val) #1

下図は、サンプルプログラムをキャプチャしたgifです。
ボタンを押すと、Class内の変数がインクリメントされ、Textportに出力されます。

output-palette.gif

右下に Evaluate DAT が2種類あり、Dependencyの使用有無で比較をしています。

  • parent().ValueA (Dependencyを使っていない)

    • ❌ ボタンを押しても数値が増えず、値の同期ができていません。
  • parent().ValueB.val (Dependencyを使っている)

    • ✅ ボタンを押すと数値が増え、値の同期ができています。

callbacks

TouchDesigner2022以降では、新たに callbacks メンバが追加されたので、値が変更された時に、簡単にコールバック関数を設定することができます。

まだあまり触れていないので、これから触ってみようと思います。

注意点

list , dictionary , set などの mutable なオブジェクトに関しては、個々の要素を変更しただけでは、cookが発生しません。
その場合は、 modified() というメソッドを呼ぶ必要があります。

以下、公式からの引用です。

Dictionaries, lists, sets, and other objects with changing contents are called "mutable" objects. If the contents of a mutable object changes, a dependency wrapping it does not automatically register as being modified! You must either use a deeply dependable collection or call the .modified() function manually as in the example below:

op('comp1').Scale.val = [1,2,3]
op('comp1').Scale.val[1] = 15 # changing the contents doesn't update dependency!
op('comp1').Scale.modified() # this call notifies TouchDesigner that the value has changed

おわりに

ぶっちゃけ、きっちりPython書かずとも、ノードベースで実装してしまえば良いのでは?ってなるのですが、

例えば常設のアプリケーションなど、後々のメンテナンスが必要なものにおいては、
なるべくコードベースで実装した方が、メンテナンスやデバッグが楽になるのでは?という気持ちです。

(遥か昔にエイヤで作ったノードまみれのシステムの不具合修正をしようとした時は、なかなかに絶望を感じました、、)

時と場合に応じて、使い分けると良いのかなと思いました。

おまけ

ちなみに、上記デモでは、TDの Comp Extension という機能を使っています。
個人的にはわかりやすいです。

詳しくは下記を参考にしてください。

2
2
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
2
2