Python
TouchDesigner

TouchDesignerでのPython入門(応用編)

この記事について

TouchDesignerやってるけどPythonほとんど書いたことない私さのかずや(Twitter:@sanokazuya0306)が理解を深めるためにつくった、TouchDesignerでPython書けるようになりたい人用のメモ。

基礎編はこちら:TouchDesignerでのPython入門(基礎編)

TouchDesignerで本気でPythonやるぞマン各位へ

TouchDesigner野郎にはおなじみ、リファレンス鬼のMatthew Raganパイセンが超詳細なリファレンスまとめてらっしゃいます。
Python in TouchDesigner | Matthew Ragan
これを読めばたぶんマスターできる。すごいなMatthew。
なのでMatthewリファレンスからかいつまんで記します。

応用編について

if文(条件分岐)とかfor文(繰り返し)的な処理の方法と、具体的にif文とfor文使って処理する方法をやっていきます。全然応用じゃねえな!

エディタ設定

本題の前に。TouchDesignerでテキストを扱うためのDATは、実は外部エディタが使える。
Preferences→DATs→Text Editor から設定可能。
スクリーンショット_2017-12-02_17_05_28.png
わたしはAtomです

if文(条件分岐)の基本的な書き方

こちらの一部抜粋。
Python in TouchDesigner | Logic | TouchDesigner | Matthew Ragan

if_example
my_int1 = 5
print('my_int1 is %d' % my_int1)

if my_int1 >= 6:
    print( 'This number is greater than 6')

else:
    print( 'This number is less than 6')

これをRunすると結果はこうなる。

スクリーンショット 2017-12-02 17.12.35.png

for文(繰り返し)の基本的な書き方

こちらがとてもていねい。
Python in TouchDesigner | For Loop | TouchDesigner | Matthew Ragan
↑めっちゃ丁寧に書いててしゅげー

超抜粋。

for_example
loop_count  = 10

print( "This is our first loop" )
for item in range( loop_count ):
    print( item )

結果はこんな感じ。
スクリーンショット 2017-12-02 17.46.44.png

例:画像Nodeを増減させる

Python in TouchDesigner | Op Class | TouchDesigner | Matthew Ragan
こちらからひとつ例を拝借。

op_test
# create a new variable called new_op
# this is also a copy of the operator out 1
new_op = parent().copy( op( 'moviefilein1' ) )

# since we've defind our new op with the variable
# name new_op we can continue to use this name
# our next step will be to give it a name
new_op.name = 'moviefilein_new_op'

# finally we're going to change the location of
# our new operator. In this example we want it
# created at a location in relation to our original
# operator. We start by finding the original operator's
# y position, and then subtract 200
new_op.nodeY = op( 'moviefilein1' ).nodeY - 100

適当に画像をいれてmoviefilein1を用意して、これをRunさせるとこうなる。

1512224140262.gif
綿貫くんが増殖しますね

これを、if文とfor分を使って、増えたり減ったりするようにしてみる。

op_test2
# moviefileinをすべて取得
m = parent().ops('moviefilein*')

# moviefileinの数
check = len(m)

# moviefileinが1個なら
if check == 1:

    # 繰り返し処理(moviefilein2から10まで)
    for i in range(2, 11):

        # コピー元のOPをmoviefilein1にする
        new_op = parent().copy( op( 'moviefilein1' ) )

        # iが5以下のときは1段め
        if i <= 5:
            # つくったnodeの位置を横にずらす
            new_op.nodeX = op( 'moviefilein'+str(i-1) ).nodeX + 150
        # iが6以上のときは2段めへ
        else:
            # つくったnodeの位置を縦にずらし、横にもずらす
            new_op.nodeY = op( 'moviefilein1' ).nodeY - 130
            new_op.nodeX = op( 'moviefilein1' ).nodeX + 150 * (i-6)

# moviefileinが10個なら
if check == 10:

    # 繰り返し処理(moviefilein2から10まで)
    for i in range(2, 11):
        # OPを削除
        op( 'moviefilein'+str(i) ).destroy()

これでRunを繰り返すとこうなる。

1512228693749.gif
綿貫くんがたくさん増えたり減ったりしますね

応用

Constantで数を変えられるようにしてみる。

op_test3
import math
num = int(op('constant1')[0])

# moviefileinをすべて取得
m = parent().ops('moviefilein*')

# moviefileinの数
check = len(m)

# moviefileinが1個なら
if check == 1:

    # 繰り返し処理(moviefilein2からnumまで)
    for i in range(2, num+1):

        # コピーするためのOPをmoviefilein1にする
        new_op = parent().copy( op( 'moviefilein1' ) )

        # 5ずつ縦に並べるためにi-1を5で割って切り捨てた数かける
        new_op.nodeY = op( 'moviefilein1' ).nodeY - 130 * math.floor((i-1)/5)
        # i-1を5で割ったあまりのぶんだけ横にずらす
        new_op.nodeX = op( 'moviefilein1' ).nodeX + 150 * ((i-1)%5)

if check == num:

    # 繰り返し処理(moviefilein2からnumまで)
    for i in range(2, num+1):
        # OPを削除
        op( 'moviefilein'+str(i) ).destroy()

1512277198726.gif
綿貫くんが200個出てきます

buttonで動くようにもできる。
CHOPから動かすときはCHOP Execute DATが便利。

スクリーンショット 2017-12-03 14.03.44.png

COHPにbuttonから出したnullをセット。

chopexec1
# me - this DAT
#
# channel - the Channel object which has changed
# sampleIndex - the index of the changed sample
# val - the numeric value of the changed sample
# prev - the previous sample value
#
# Make sure the corresponding toggle is enabled in the CHOP Execute DAT.

import math
num = int(op('constant1')[0])

# moviefileinをすべて取得
m = parent().ops('moviefilein*')

# moviefileinの数
check = len(m)

def onOffToOn(channel, sampleIndex, val, prev):
    # 繰り返し処理(moviefilein2からnumまで)
    for i in range(2, num+1):

        # コピーするためのOPをmoviefilein1にする
        new_op = parent().copy( op( 'moviefilein1' ) )

        # 5ずつ縦に並べるためにi-1を5で割って切り捨てた数かける
        new_op.nodeY = op( 'moviefilein1' ).nodeY - 130 * math.floor((i-1)/5)
        # i-1を5で割ったあまりのぶんだけ横にずらす
        new_op.nodeX = op( 'moviefilein1' ).nodeX + 150 * ((i-1)%5)

    return

def whileOn(channel, sampleIndex, val, prev):
    return

def onOnToOff(channel, sampleIndex, val, prev):
    # 繰り返し処理(moviefilein2からnumまで)
    for i in range(2, num+1):
        # OPを削除
        op( 'moviefilein'+str(i) ).destroy()
    return

def whileOff(channel, sampleIndex, val, prev):
    return

def onValueChange(channel, sampleIndex, val, prev):
    return

先ほどの個数チェックをボタンのオンオフにセット。chopexec1のパラメータのOff to OnOn to OffをどちらもOnにしておく。

1512277590881.gif
めっちゃラグるけど出せる

ていうか

こんなめんどいことしなくてもReplicator COMPでできたわ
1512230078361.gif

ちなみにReplicator COMPとかOPをたくさん増減させる系は処理が重たくなるのであまり推奨されていないっぽい。
元ファイルを変える必要がないなら、Translateとかで元ファイルは変えずに映像で処理するほうが懸命…?

他の例

2つのCHOPのパラメータ比較してprintする、とかはここにある。
Python in TouchDesigner | Logic - Part 2 | TouchDesigner
これを応用すれば映像の出し変えとかもいろいろできそう。

まとめ

見れば見るほどめっちゃむずない!?と感じてしまったので、Matthewパイセンのガチリファレンスでちゃんと勉強してちょっとずつまとめます。
Python in TouchDesigner | Matthew Ragan

あくまで入門ということで、さらなる活用はみなさんどんどんQiitaに上げて頂けたらよいのでしょうか!きっと喜ぶと思います!おもにぼくが!

それではみなさん埋めてくださったアドカレたのしみにしております!