【TouchDesigner】tdPyenvManagerでPythonパッケージを管理する
TouchDesigner 2025がリリースされ、新機能の一つとしてtdPyenvManagerというPythonの外部パッケージを管理する機能が追加されました。tdPyEnvMangerではvenvまたはCondaでパッケージ管理をすることができます。
ちなみに、以前は外部でインストールしたパッケージをPreferencesでの設定やsys.path.appendでパッケージ探索パスに追加してTouchDesignerで利用できるようにしていました。詳しい方法は以下の記事にまとまっています。
使い方
以下の記事を参考にtdPyenvManagerでvenvを使用して外部パッケージを管理してみます。
まず、PaletteからTools > tdPyEnvManagerをNetwork Editorにドラッグ&ドロップしてtdPyenvManager COMPを作成します。

パラメータダイアログでActiveをオンにして有効化し、Create vEnvのPulseを押してvenv仮想環境を作成します。作成が完了すると、{親ディレクトリ名}_vEnv(例えば/Foo/Bar.toeの場合Foo_vEnv)というディレクトリが作成されます。Macの場合はこれに加えてTDPyEnvManagerContext.jsonというファイルも作成されます。
Open CLIのPulseを押すと仮想環境が有効になっている状態でターミナルが起動するので、ここでpipコマンドで外部パッケージをインストールします。
pip install zmq
TouchDesignerのTextportを開き、以下のコマンドでパッケージがインストールできているか確認します。
import zmq
TouchDesignerプロジェクトをGitなどのバージョン管理システムで管理する場合、外部パッケージ本体は管理対象に含めず、インストールしたパッケージの情報だけをrequirements.txtに出力して管理します。tdPyEnvManagerではパラメータダイアログのExport requirements.txtでrequirements.txtを作成することができます。バージョン管理システムから新たにプロジェクトを作成した場合、パラメータダイアログのCreate From requirements.txtでvenv環境を作成して必要なパッケージをインストールできます。
Create vEnvで作成された*_vEnvディレクトリ内には外部パッケージ本体はGit管理しないようにする.gitignoreファイルがあらかじめ含まれています。Macの場合はTDPyEnvManagerContext.jsonもバージョン管理対象外にして問題なさそうです。
使用例
例として以前検証したQRコード作成をtdPyEnvManagerを使って試してみます。
このときはvenvで仮想環境を作成してpyqrcodeとpypngをインストールし、venvのパッケージインストールパスをsys.path.appendでパッケージ探索パスに追加して利用できるようにしていました。
今回は先ほど紹介した手順でtdPyEnvManagerをセットアップして、ターミナルで以下のようにpyqrcodeとpypngをインストールします。
pip install pyqrcode pypng
Script TOPではsys.path.apppendは不要になるので、以下のスクリプトでQRコードを作成できることができました。
import pyqrcode
import numpy as np
import cv2
import io
def onSetupParameters(scriptOp):
page = scriptOp.appendCustomPage('QR Code')
p = page.appendInt('Scale', label='QR Code Scale')
p[0].normMin = 1
p[0].normMax = 20
p[0].default = 5
p = page.appendStr('Data', label='QR Code Data')
p[0].default = 'Hello, World!'
def onPulse(par):
return
def onCook(scriptOp):
scale = scriptOp.par.Scale.val
data = scriptOp.par.Data.val
qrcode = pyqrcode.create(data)
buffer = io.BytesIO()
qrcode.png(buffer, scale=scale)
array = np.frombuffer(buffer.getvalue(), dtype=np.uint8)
image = cv2.imdecode(array, cv2.IMREAD_COLOR)
image = np.flipud(image).copy() # copyがないとTDがクラッシュする
scriptOp.copyNumpyArray(image)

Discussion