TouchDesigner プリセットを作る


TouchDesigner Advent Calendar 2018 16日目の記事です。よろしくお願いします。

はじめに

リアルタイムで生成されるビジュアルのパラメータを変えて調整したり、気に入ったパラメータを保存したりすると思います。保存したものをプリセットとして使えたらいいなと思いつつ、Palette > Derivative > Techniques > presets が好いのかなと見てみるもあまりピンと来なかったので、自分で作ってみました。

サンプルファイル

githubにアップしましたので必要に応じて参照してください。
https://github.com/chimanaco/touchdesigner-advent-calendar-2018

ベースとして使用しているUI

UIのベースはPalette > Derivative > UI > galに入っているものです。これまでPalette > Derivative > UI > TUIK内にあるものを使ってUIを作っていたのですが、中身を少し弄ろうとするとTscriptで実装されていてよく分かんないからPythonで実装されているgalにしとけとDiscordでアドバイスを頂きました。使ってみると確かにTUIKと比較して自分のやりたい用途としては使いやすかったです。

サンプルの構造

今回作ったプリセットの仕組みとしては0-9の各ボタンをクリックすると保存されているプリセットの値が反映され、UIで値を変更した後にSaveボタンをクリックすると現在のUIの値が保存されるというものです。これらの値を使ってRamp Topをアニメーションさせています。

VJツールのように何種類かビジュアルを用意するとして、UI_privateにそのビジュアル固有のプリセットを入れておいて、各ビジュアルごとにパラメータの名前や値の範囲などを個別に設定していくのを想定しています。UI_allのほうは各ビジュアル共通の内容を保持しているもので、現状プリセットを選択するラジオボタンが入っていて、UI_privateの中身を一緒に表示しています。

プリセットのアップデート

table_all_valuesに全てのプリセットのデータが入っていて、preset_saveの中のchopexec_saveからプリセットのアップデートをしています。
1列目が各プリセットの名前で、名前が一致した時にindexに該当する値を追加、または更新をします。
新しいプリセットが追加されたら新しい行(row)を追加するようになっています。

null_current = op('null_current_values')
chopto_current = op('chopto_current_values')
null_index = op('null_index')
table_all = op('../table_all_values')

def offToOn(channel, sampleIndex, val, prev):
    # get index to update
    presetIndex = int(null_index[0] + 1)
    # get a list channels
    chans = null_current.chans()
    # reset index
    index = 0

    for c in chans:
        done = False

        for i in range(table_all.numRows):
            table_name = table_all[i, 0]
            # check if a row for this value exists
            if(c.name == table_name):
                table_name.val = chopto_current[index, 0]
                updateValue(c, index, presetIndex)
                done = True
                break
        # if a row for this value doesn't exist
        if(done == False):
            table_all.appendRow([c.name])   
            updateValue(c, index, presetIndex)
            done = True
        index += 1  
    return

def updateValue(chan, index, presetIndex):
    # update value 
    param = table_all[index, presetIndex]
    param.val = chan

プリセットにテーブルを使うのはおなじみMatthew Raganさんの記事を参考にしています。
TouchDesigner | FB HelpGroup | Presets | Matthew Ragan

UIのアップデート

プリセット番号をクリックした時に、chopexec_switchで一度プリセットからの値を反映させた後、op('text_reset_switch').run(delayFrames = 60)で60フレーム後にUIから値を変更できる状態に戻します。

constant_switch = op('constant_switch')
def onValueChange(channel, sampleIndex, val, prev):
    constant_switch.par.value0 = 1
    op('text_reset_switch').run(delayFrames = 60)
    return
constant = op('constant_switch')
constant.par.value0 = 0

UI_private内の各CHOP Executeたちはそれぞれすぐ右側にあるUIのValueを直接アップデートしています。UIから変更した時にもプリセットから変更したときにもUI上の値が変更されてほしいのでこのようにしています。

改善したい点

  • jsonとかにexportしてtable DATに読み込めないですかね?
  • Pythonでcontainer内から外のtable DATを参照しているのと、CHOP Executeから各UIのValueを直接アップデートしているのをどうにかしたい(単純にネットワークとコードをきれいにしたい)。

最後に

プリセットこんな風にやってるよーという方おられたら、ご教示頂ければ幸いです。
ありがとうございました。