Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
51
Help us understand the problem. What is going on with this article?
@sanokazuya0306

TouchDesignerでのPython入門(基礎編)

More than 3 years have passed since last update.

この記事について

TouchDesignerやってるけどPythonほとんど書いたことない私さのかずや(Twitter:@sanokazuya0306)が理解を深めるためにつくった、TouchDesignerでPython書けるようになりたい人用のメモ。
ほぼ公式の英語チュートリアルの翻訳。

ていうか全部書き終わってからお触り本の後ろの方にまとまっている事に気づいてしまいました。もっと知りたい人はこっち買って!

TouchDesignerでのPythonで得られる幸せ

TouchDesignerは工夫してコード繋げばいい感じの絵を出してくれるけど、変数の扱いとかがめちゃ面倒だったり、コード書く系のジェネやってる人とかはいろいろと不便を感じがち。
そういうときはPython使えると大体解決するっぽい。なので書けるに越したことはなさそう。
公式のチュートリアルもあるのですが、例によって読みにくいので噛み砕きながら日本語で残しておきます。

翻訳シリーズご興味ある方はこちらもどうぞ
TouchDesignerでGLSL入門

ちなみに

この基礎編では、下記公式のチュートリアルを順を追って日本語で紹介していきます。
Introduction to Python Tutorial - TouchDesigner 088 Wiki

ただ正直、公式のチュートリアルがあんまイケてないのでとりあえずTouchDesigner上でPython動かしてみようぜーくらいで、大した内容がありません。
実際どう使ったらエエねん!というのは応用編で紹介します。あらかじめ!

Python入力

公式チュートリアルのInputting Pythonの部分。

TextportでPythonする

TouchDesignerでPythonを試す一番簡単な方法はTextportを使う方法。
スクリーンショット 2017-11-25 19.46.01.png
メニュー → Dialogs → Textport and DATs でTextportを開く。

スクリーンショット 2017-11-25 19.47.14.png
そうするとこんな感じの画面が出てくる。なんかごちゃごちゃ出てるときは右上のClearを押すと消える。

スクリーンショット 2017-11-25 20.03.26.png
試しにhelp(absTime)と入れると、td ModuleというTouchDesignerのどこでも使える変数(ここではabsTime)についての説明が見られる。td ModuleにあるものならabsTimeじゃなくてもなんでもいけるっぽい。

余談

TouchDesigner099で使える言語はPythonとTScriptの2種類ある。TScriptはC++用?のスクリプト言語。ターミナルで使うっぽい入力方式だけどよくわからない。Wikipedia公式のリファレンス読んで!
TouchDesignerは最初TScriptで作られていたらしい。それがどこかのタイミングでPythonベースに作り変えられ、TScript記述モードはいまも名残で残っている様子。いまの主流はPython。

スクリーンショット 2017-11-25 19.49.12.png
左上にPythonマークが表示されているときはPythonモード。これをクリックすると下に切り替わる。

スクリーンショット 2017-11-25 19.49.16.png
これが表示されているときはTScriptモード。物好きなアナタは試してみてはいかがでしょう。今回は使わないのでもう1度押してPythonモードに戻しておく。

DAT ScriptでPythonする

複数行のスクリプトを使うときは、Text DATなどのDATを使う。

スクリーンショット_2017-11-25_22_37_32.png
とりあえずText DATを適当に置く。右上にPythonマークが出てたらPython入力モード。上の余談と同様にTScriptモードにすることもできる。

スクリーンショット_2017-11-25_22_40_55.png
DATの中をいじるため、右下のViewer Active Flagを押す。
Viewer Active Flagのオンオフは選択状態でキーボードのAを押すことでも変更できる。

とりあえずこんな感じでいれてみよう。

for i in range(1,5):
    print(i)

1以上5未満の範囲でprint(i)を繰り返す、というPython文。
なんで5は含まへんの?と思って調べてみたら、0から数えて5つめまで(4)ということっぽい。詳しくはこのあたりをご参照。
【Python入門】range関数で繰り返し処理をする方法とは? | プロスタ
ちなみに1行目にはスペースやタブを入れてはならず、2行目以降のインデントはタブ1つか半角スペース4つでないといけないらしい。

これをText DATの中にコピペ。

スクリーンショット 2017-11-25 22.44.10.png
右クリックしてRun Script、もしくは⌘+R。
一見何も起きないが、メニュー→Dialogs→Textports and DATsからさっきのTextportをもう一度開くと…

スクリーンショット 2017-11-25 22.45.44.png
Textportのなかで実行されていることがわかる。おめでとう。

Moduleをimportする

Pythonを使えることのありがたみの1つは、Pythonで導入できるModuleを使えること。TouchDesignerは最初から、一般的なModuleやNumPyなどの科学計算モジュールなどが入っているらしい。
プログラミング慣れしている方ならおなじみだと思いますが、Moduleとは、みんなが使える「定義や文が入ったファイル」。例えば四則演算以外のややこしめの計算とかも簡単にできたり。詳しくはこのへん。
6. モジュール (module) — Python 3.6.3 ドキュメント

例えばさっきのText DATにこんな感じで入れてみる。

import math
print(math.sin(4))

mathというModuleをimport(使いますよという宣言)して、mathの中のsin計算をするsinという関数(math.sin()と書く)を引っ張って、そこに4をいれてますよ、というプログラム。
そして⌘+R。

スクリーンショット 2017-11-25 23.03.07.png
sin(4)の計算をしてくれてますね。ちなみに()の中は度ではなくラジアン(4[rad]=4*180/π[度]≒229[度])なのでご注意。

なお、新規Moduleの追加やModuleのバージョン変更は結構面倒くさいっぽいのでここでは省略。TouchDesigner099はPython3.5で動いているっぽく、PreferenceのPython 64-bit Module PathでPath指定すればいけるっぽいが、試してません(MacのPython Moduleがどこにあるのかわからんかった)。誰か必要なら試して!

DATからInternal Moduleをつくる

これはかなり便利っぽいテク。Paletteで出せるものにもけっこう使われているので知っておいて損はなし。

Text DATを2つつくり、1つの名前をmy_utilsにし、下記を入力。

my_utils
def my_adder(x,y):
    return 10*x+y

もう1つをtest_importとし、下記を入力。

test_import
import my_utils
a = my_utils.my_adder(1,5)
print(a)

上のmy_utils内のmy_adder(x,y)は、10*x+yを計算する関数。
それを下でmy_utils.my_adder(x,y)で呼び出して、x,yを代入、print。
つまり、my_utilsがInternal Moduleとなって、別のDATで活用できる。 便利か〜

スクリーンショット 2017-11-26 0.16.19.png
この状態でtext2をRun(⌘+R)。

スクリーンショット 2017-11-25 23.48.59.png
また計算してくれるんですね〜、すばらしい

Component Module

上記のように同じ階層にあるとInternal Moduleをちゃんと読み込んでくれるが、別の階層にあると読み込んでくれない。
スクリーンショット 2017-11-26 0.02.23.png
別の階層にあるとこんな感じで怒られる。

しかし1ヶ所、共通でModuleを読み込んでくれる場所がある。
それがlocal/Modules
スクリーンショット_2017-11-26_0_02_23.png
localの中に入って

スクリーンショット_2017-11-26_0_04_31.png
Container COMPを置き、modulesに名前を変えて、ここの中にmy_utilsを置く。ここにあるModuleをComponent Modulesと呼ぶっぽい。 

スクリーンショット 2017-11-26 0.18.00.png
ここに置いていると同様に計算ができる。美しい…

mod (Modules On Demand)

TouchDesignerでしばしば見るmodについて。modはimportの欠点を補完するためのもの。
というのも、便利なimportだが、2つの欠点がある。

  • Moduleの名前は単語でないといけないため、特定の階層を指定したくても相対パスが使えない。
  • import文がウザいため、パラメータ表現に向いていない。

(ごめんなさい、正直なんでパラメータ表現にimport文が邪魔なのかよく分かってません、先生おしえて!)

これらを解決するために、TouchDesignerにはmodという関数(?)がある。これを使うとimport文が不要になり、相対パスが使えるようになる。どういうことかというと…

test_import
a = mod.my_utils.my_adder(1,3)
print(a)

importが必要なModule名の最初にmodをつけるだけで、上記のように置き換えることができるようになる。

test_import
a = mod('my_utils').my_adder(1,3)
print(a)

さらに、(' ')で囲んでやれば相対パスが指定できる。

test_import
a = mod('/project1/my_utils').my_adder(1,3)
print(a)

もちろん、絶対パスも指定できる。 便利か〜

Operatorで操作する

Working with OPs in Pythonの内容。
TouchDesigner独特の関数(?)による指定の仕方に慣れる回。

基本アクセス

よく使うものにmerootがある。

  • me: いま計算しているやつ。Operatorの中で使うときはそのOperator自身を指す。
  • root: ルート階層(一番上)のComponentを指す。

それからop( )というのを使うと各Operatorの情報にアクセスできる。詳しくはこちら。
OP Class - TouchDesigner 088 Wiki

スクリーンショット 2017-11-26 0.54.49.png
たとえば、Wave COMPとConstant COMPを出し、Constant COMPのname0の左にある+を押し、青いボタンを押し、op('wave1')と入力する。

スクリーンショット 2017-11-26 0.47.49.png
そうするとこうなる。op('wave1')はwave1の絶対パスを表示してくれる。
厳密に言うと絶対パスを指定しているわけではなく、wave1というオブジェクトを指定していて、便宜上そのパスを表示しているだけなのだけど、オブジェクト指向の説明はややこしいので省略します。

もちろんこの書き方はDATの中などでも使えて、n = op('wave1')のように変数に入れたりもできる。

スクリーンショット 2017-11-26 0.58.17.png
me.parent()と入れると親階層を指定したりもできる。

スクリーンショット 2017-11-26 1.42.29.png
COMPであればmeを使って、me.op('子ノードの名前')['チャンネル名']でCOMP内の子ノードの数値を取ってこれたりもする。

スクリーンショット 2017-11-26 1.44.46.png
COMPじゃなくても、op('COMPの名前').op('COMPの子ノードの名前')['チャンネル名']とやれば下の階層の数値を引っ張り出せる。

n = op('/project1')
m = n.ops('text*')
for a in m:
    print(a.name)

Project以下のOperatorで、'text*'に当てはまるものを抽出し、その名前をprintする。
Text DATにこれを入力すると…

スクリーンショット 2017-11-26 1.28.29.png
こうなる。

print('i am ', me)
print('child of ', me.parent())
print('grandchild of ', me.parent(2))

print('root children:')
k = root.children
for r in k:
    print(r)

me.parent()root.childrenをそれぞれ使ったもの。
これをいれると…

スクリーンショット 2017-11-26 1.31.57.png
こんな感じで表示してくれる。これで一通りわかるはず。

コマンド早見表

TouchDesigner Operaotr&Python Scriptまとめ
こちらにもすでにある程度まとめられていますが…
公式ページのコマンド/表現一覧は、コマンド一覧はあまりにコマンドライン的操作すぎるので省略。必要そうな表現一覧だけ記載。

目的 Pythonコード
同じOPのパラメータを取得 me.par.tx / me.par.value0
別のOPのパラメータを取得 op('sphere1').par.tx / op('constant1').par.value0
OP(例:constant1)の出力(chan1)を取得 op('constant1')['chan1']
OPの親 .parent()
OPの親の親 / 親×n .parent(2) / .parent(n)
table1の1,1を取得 op('table1')[1,1]
OPの名前 .name
OPの数値 .digits
ランダム数値を生成 tdu.rand(me.digits) ※()内はランダムシード
要素(container1の子ノード)の数を数えたいとき len(op('container1').children)
要素(switch1)のinput/outputの数を数えたいとき len(op('switch1').inputs) / len(op('switch1').outputs)
Info CHOPの内容はop().xxで引っ張り出せる op('moviein1').width
時間(フレーム単位) absTime.frame / me.time.frame
時間(秒単位) absTime.seconds / me.time.seconds

などなど…お触り本の一番後ろの方にもあるのでご参照あれ。

以上これまで

以上で公式リファレンスの内容は大体終わりなんですが、これでみなさんPythonマスターですね!!

とはいえ

そう、みなさんお気づきの通り、
結局変数どうやって扱ったらええの?if文とかfor文的なやつとかどうやって書くの?とかが公式リファレンスには全くありません。
公式リファレンスの説明冗長すぎひん?これまでの要素説明するのにこんな解説量いる?
基本自分でやれやというスパルタ感なので、我々プログラミングわからへんからTouchDesignerやってんねん勢にはちょっとまだまだハードル高くて泣ける。

なので具体的にどう書けばifとはforとかできんの?あとCHOPとか使いたいねんけど?というのは応用編でまとめたいと思います。
翌日のアドカレをおたのしみに〜

51
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
51
Help us understand the problem. What is going on with this article?