動作環境
サンプルコード
run("op('text1').run()",delayFrames=60)
このサンプルでは、text1 DATを60フレーム後に実行する動作になります。第1引数で、文字列として実行するスクリプトを与え、第2引数で遅延させるフレーム数を指定します。
1フレーム内で実行する処理を分散する時やタイミングをずらし描画をスタートする時などに便利です。
Relicator COMPで複製したオペレーターを任意のオペレーターのInputに自動的につなげる方法。複製する個数を変える度に、手動でつなげなくて良いので便利。
1は、自分の連番を元にした角の数の多角形を描画する3base1を複製、5layout1は、複製された多角形をグリッド上に配置している。
複製されたオペレーターを自動的につなげるには、2のスクリプトを以下の様に書く。
def onRemoveReplicant(comp, replicant):
replicant.destroy()
return
def onReplicate(comp, allOps, newOps, template, master):
for c in newOps:
#c.display = True
#c.render = True
#c.par.display = 1
#c.par.clone = comp.par.master
c.outputConnectors[0].connect(op('layout1'))
pass
return
13行目で、OPを生成する度に、5layout1に接続している。
https://github.com/arkwknsk/touchdesigner/blob/master/tips/replicator/replicator.toe
2つのChopの波形を1つの波形としてつなげるには、Splice CHOPを使う。
追加する波形を前に入れるか、後に入れるかは、5Directionで変更できる。
Direction | |
---|---|
First to Last | 前に挿入 |
Last to First | 後ろに挿入 |
アニメーションなどの波形を生成するときに、一定時間固定する波形などを足したいときに便利な手法。
1と2で波形を生成。この2つの波形を34Splice CHOPでつなげている。3の場合は、Input2に入ってきた2を先頭に挿入し、その後に1の波形を足している。https://github.com/arkwknsk/touchdesigner/blob/master/tips/splice/splice.toe
Pythonで、OPの名前”base1″の数字やベース名を抽出したり、OPの名前を生成する方法。
OPの名前から数字(連番)をスクリプトから取得することで、繰り返し処理などが効率化できます。
https://github.com/arkwknsk/touchdesigner/tree/master/tips/op-name
d = op('base1').digits
print(d) # 1
ここでは、digits
を使って、base1の連番を抽出しています。
TDF = op.TDModules.mod.TDFunctions
name = TDF.incrementStringDigits('foo',2)
print(name) #foo2
TDの標準ライブラリのincrementStringDigits
を使います。2個目の引数に、くっ付けたい数字を指定します。
b = op('base1').base
print(b) #base
base
を使って、連番前の文字列を抽出します。正規表現を書くより楽です。
Constant CHOPを参照するのと同じ形で値を変えようとするとエラーになるが、書き換えられる方法。
https://github.com/arkwknsk/touchdesigner/tree/master/tips/rewrite-upconstant-chop
import random
op('constant1').par.value0 = random.uniform(0,100)
ここでは、1constant1を2text1のスクリプトから書き換えています。
chop_op.par.value0
の形でアクセスすることで、値を書き換えられます。chop_op[0] = 1234
の形でアクセスするとエラーになります(Read Only)。
最後に、このやり方で実行のタイミングはどうなるかを検証。結論は、同フレーム内で処理されるので安心です。
3text2のスクリプトから1constant1を書き換え、その変更で4chopexec1が実行されるサンプルを実行します。各実行タイミングでFrame数を出力しています。
import random
print( absTime.frame)
print( op('constant1')[0])
op('constant1').par.value0 = random.uniform(0,100)
print( op('constant1')[0])
4chopexec1で最後のFrame数を出力します。
def onValueChange(channel, sampleIndex, val, prev):
print( absTime.frame)
return
3text2のスクリプトから1constant1を書き換え、その変更で4chopexec1が実行されるサンプルを実行します。各実行タイミングでFrame数を出力しています。
実行結果は以下です。
python >>>
29169
9.247329711914062
54.78358840942383
29169
python >>>
2行目で、最初のFrame数を出力。3行目で、古い値が表示されています。4行目で書き換わった値を1constant1から参照して出力しています。ということは、同スクリプト内で書き換えた値を再び参照できるようです。最後に、4chopexec1の実行タイミングのFrame数を出力しています。最初のFrame数と同じなので、同フレーム内で実行されていることを検証できました。
スクリプトの計算結果から、CHOPのノードで処理するときに便利です。また、スクリプトの計算結果を環境変数にして、各ノードの設定を決めるのにも便利です。
スクリプトから、Table DATを更新して、CHOPに流し込む方法もありますが、ノードの数が増えてしまいます。
ローカルPC内もしくはネットワークに接続されたPC間で動くTouchDesignerの複数のプロセスでデータを共有する方法。
TDのプロセスは、シングルスレッドで動作し同期型のため、高負荷の処理に弱く、マルチコアのCPUの性能をフル活用することができません。大まかな機能ごとにプロセスを分けて、同時起動すると、マルチスレッド的で動作し、負荷分散を図ることができます。また、モジュール化を図ったり、複数人の共同作業の分割にお役立ち!
https://github.com/arkwknsk/touchdesigner/tree/master/tips/touchin
TDには、プロセス間でデータを共有できるノードがいくつか用意されています。
また、Pro/Commercialライセンスのみで使えるもっと高度なノードもあります。
今回は、数値・文字列データを送れるDATとCHOPを送受信
送信側に、1Touch Out DATと2Touch Out CHOPを追加します。今回は、absTime.frame
の値を送ります。
毎フレームごとの値を連番(シークエンス)で送れるので、後ほど遅延時間を確認できます。
送信側のTDを起動した状態のままで、別のTDで受信側の.toeファイルを新規作成し、1Touch In DATと2Touch In CHOPを追加します。追加すると、早速、受信側のノードの数字が変わります。
もし、送受信ができない場合は、
Network Address
がlocalhost
になっているかを確認を試してみてください
気になる遅延ですが、DATの方は、デフォルトの設定でローカルPC内で1 frame程度の遅延です。これは、PC自体の処理能力に依存すると思われます。
CHOPの方はデフォルトの設定だと、ローカルPC内でも5 framesのズレが発生します。これは、デフォルトの設定では、通信のドロップのエラー処理のため、キャッシュを貯めているの原因の様です。
Touch In CHOPのparameterをこれぐらいにすると、ローカルPC内でも1 frameのズレ程度にできます。
同じように、異なるプロセスやPCでデータを共有するのに、OSCが一般的に使われますが、Touch In/Outと比べると、
という利点があります。ただし、OSCの場合は、TD以外で開発されたアプリと通信ができるので、ここは大きく違います。あくまでも、TD同士での通信に有効と言えます。
このノード群を使うと、以下のようなことができます。
Pro/Commercialライセンスだと、さらに共有できるノードが用意されています。こちらは、次回に。
「Notch #madewithnotch Advent Calendar 2019」16日目の記事です。
Notchで、ヴィジュアライゼーション的に、大量に数値や文字列を表示する方法を模索。
ClonerやParticleでTextを表示する場合、元になるTextの文字列が固定されてしまい、Particle毎に文字列を変え、異なる文字列を大量に表示することができない。
※本サンプルでは、NDIを使用しているのでTouchDesignerはCommercialライセンス以上が必要になります。ご了承ください。
そこで、TextureをSpriteアニメーションで切り替えるようにし、 Particle毎に表示を変え、疑似的に異なる文字列を表示するようにする。ただし、Notch内部では大量のテキストを処理するのは難しいので、TouchDesignerで数値を処理し、テクスチャーとしてNDIでNotchに送る。それをNotch側でParticleに貼り付けて、大量に表示するという流れ。
https://github.com/arkwknsk/notch/tree/master/20191216_many-text
今回はランダム数値を16個、Notch側に流すことにする。ネットワーク左側でランダム数値を生成する。
次に、生成したランダム数値をText TOPで画像化し、Layout TOPで4 *4 のグリッドで貼り付ける。最終的に、Notch側でこの画像を16等分してTextureとして利用する。
Textureは、二乗の正方形がGPU的にやさしい。ここでは、1024*1024のResolutionにしている。
なぜか、Notch側でPoint RendererにImageとして貼り付けると、左右反転になってしまうので、TouchDesigner側で反転させ、NDI Out TOPで出力する。今回は、同じPC内でNDIを送る。
ここでは、ランダム数値を使っているが、大量のテキストデータやセンサーの数値データなどを送ったりして、演出できる。また、Top自体はどんな映像でも良いので、TouchDesigner側で様々なロジックを組みTextureを生成し、動的にNotch側で表示するという手法も考えられる。
新規のプロジェクトか、プロジェクトを開き、Menu->Devices->VideoIn/Camera/Kinect Setting…を選ぶ。
TouchDesignerからNDIが送信されている場合は、NDI -> Incomingの中に、リスト表示されているので、これを選択する。
こちらが今回のNotchのネットワーク。
Point RendererのPropertiesの中ほどに、”Texture Animation”という項目があります。この中の”Num Frames X”と”Num Frames Y”をTouchDesignerで作成したTextureのGrid数に合わせます。この数値を基に画像が均等にスプライト分割されます。次に、その下の”Texture Start Frame Mode”をRandomに設定します。 分割されたスプライトからランダムに、画像がパーティクル毎に貼り付けられます。(はずです)
あとは、お好きなEmitterやAffectorで演出を付けていくことができます。
NDIのパフォーマンス次第になりますが、さらにパターン数の多いTextureを送り付けて、文字列のパターンを増やすこともできそうです。
hasattr
関数を使う
if hasattr(obj,'val') == True:
print('has')
else:
print('not has')
10/23に開催されたTouchDesignerの黙々会の成果物をアップします。
先日、 cyclo. (Ryoji Ikeda, Alva Noto)のLiveを観てきまして、Line Art系のAudio/VisualなものをTouchDesignerで作れないかなと。
https://github.com/arkwknsk/touchdesigner/tree/master/mokumoku/20191023
MIT Licenseで公開
かなり、ネットワークが汚いですが、お許しを。
audioAnalysis
を使用。ここから、CHOPでごにょごにょと、音から拾ってきた数字をいじるラインアートを大量に出す方法は、比嘉さんのブログで解説されています
http://satoruhiga.com/TDWS2019/day10/
インスタンシングでの位置やスケールを変えれば、いろいろとoFっぽい演出が、TDでもできそうな感じ。
fruit = ['apple','banana','strawberry','banana','apple']
result = list(set(fruit))
set
を使って、重複している値を取り除く。