見出し画像

C++でオリジナルのオペレーターを作る

Touchdesignerでは既存のオペレータではできない処理を行いたい場合、Script CHOPやScript SOPなどのオペレータにPythonで書く、という手段以外にもC++で独自オペレーターを作ることができます。今回はその方法を忘備録的に書いていきます。

C++でオペレーターを作るメリット/デメリット

C++オペレーターを開発するのはメリットもデメリットもあります。メリットから書いていきますね。

まずは処理速度。TouchDesignerでScriptで記述した場合の10倍程度速いそうです。また、C++のライブラリを利用可能なのも嬉しいところかもしれません。dllになっているため、配布や再利用がしやすいのもポイントです。

デメリットとしてはVisual Studioなどの開発環境が別途必要になること。また、winとmacは別でコンパイルする必要があるので、OSを跨いだ再利用を考慮すると開発環境が2つ必要で若干面倒です。あとはデバッグのしづらさがあります。ビルドしてdllを作った上でTouchDesignerに組み込むのでScript OPのような対話形式で進めていくことができません。また、コンパイルが通っても正しく処理が記述されていないと頻繁にTouchDesignerごとクラッシュします

どんな時にC++で作るべき?

まずはC++でしか存在しないライブラリやC++のインターフェースしかない外部機器を利用する場合はほぼ必須だと行って良いでしょう(勿論、そもそもTouchDesignerでは利用しない、という選択肢も検討してください)。

また、速度的メリットも確実に得られるため、高速化の際にも検討しても良いでしょう。

開発環境構築

色んな開発方法があるかと思いますが、satoruhigaの制作したTouchdesigner Plugin-Templateを使うのがとても簡単だと思います。

利用方法などはYoutubeにアップしてくれているのでそちらをチェックしてください。

Windowsでの利用方法(Visual Studio2017)

Macでの利用方法(XCode)

注意点としてはVisual StudioのcmakeがVisual Studio 2017向けに作られている点です。手順通りにセットアップするとx64 Debugしか設定がないのでx64 Releaseの設定を追加する必要があります。

自分の場合、x64 Debugの設定をコピーしてフラグのみReleaseに変更して使っています。


C++のオペレーター開発時の注意点

先ほども書きましたがC++でビルドしたdllは意図しない書き込みをしようとした場合、割と簡単にクラッシュしてTouchDesignerごと落ちます。入力のオペレータやパスが設定されていない状態を考慮した処理を書いていく必要があります。

特にオペレーターのポインタ取得のAPI自体が成功失敗を返さない場合も多いので要素数やチャンネル数などをチェックして正しく取れていない場合に書き込み処理をしないように記述しましょう。

チートシート

あまり本家のwikiに書き方が載ってないので書いておきますが、基本はScript系オペレータでできることはほぼできて、一方でC++だから触れる!みたいなAPIは無さそうです。

Intの追加

OP_NumericParameter np;
np.name = "Intvalue";
np.label = "Int Value";
np.defaultValues[0] = 100;
OP_ParAppendResult res = manager->appendInt(np);
assert(res == OP_ParAppendResult::Success);

Intの呼び出し

int val = inputs->getParInt("Intvalue");

Floatの追加

OP_NumericParameter np;
np.name = "Floatvalue";
np.label = "Float Value";
np.defaultValues[0] = 1.0;
OP_ParAppendResult res = manager->appendFloat(np);
assert(res == OP_ParAppendResult::Success);

Floatの呼び出し

int val = inputs->getParDouble("Floatvalue");

XYZの追加

OP_NumericParameter np;
np.name = "Threevalues";
np.label = "Three Values";
np.defaultValues[0] = 1.0;
np.defaultValues[1] = 2.0;
np.defaultValues[2] = 3.0;
OP_ParAppendResult res = manager->appendXYZ(np);
assert(res == OP_ParAppendResult::Success);

XYZの呼び出し

// パターン1
double x, y, z;
inputs->getParDouble3("Threevalues", x, y, z);

// パターン2 
x = inputs->getParDouble("Threevalues", 0);
y = inputs->getParDouble("Threevalues", 1);
z = inputs->getParDouble("Threevalues", 2);

CHOPの追加

	OP_StringParameter np;
	np.name = "Selectedchop";
	np.label = "Selected CHOP";
	OP_ParAppendResult res = manager->appendCHOP(np);
	assert(res == OP_ParAppendResult::Success);

CHOPの呼び出し

const OP_CHOPInput *selectedCHOP;
selectedCHOP= inputs->getCHOP(inputs->getParString("Selectedchop"));

CHOPやTOPなどを取るGUIはStringでパスの文字情報しか持っていないので注意。


この記事が気に入ったらサポートをしてみませんか?