SOP Workshop @TouchDesigner Study Weekend vol.010

TouchDesigner Study Weekend vol.010 で開催された、TouchDesigner SOP中級者向けワークショップの記事です。

プロジェクトファイルはこちら -> toe

SOPの基本要素

/project1/POINTS_VERTICES_PRIMITIVES を参照

SOP を理解する上で避けては通れないのが、PointPrimitiveVertex というデータ構造です。

Point
3Dの位置情報を持った
Vertex
Point が、どういうふうに接続されて Primitive を構成しているか、という情報
Primitive
ポリゴンやメッシュ、ベジェやNURBSで構成された曲線/曲面、円や球などのシンプルなプリミティブ、
メタボールやパーティクル等、ポイントのあつまり + それらがどういう風にレンダリングされるべきかの情報を持たせた単位

これらの情報は、オペレータービューを選択した状態で p キー、または右クリックメニューから、Display Options でビジュアライズできます。

ジオメトリを数値指定で作る

/project1/MAKE_BASIC_GEOM1 を参照

script1 のDATの中は以下のようになっています。

def onCook(scriptOp):
	scriptOp.clear()

	new_point = scriptOp.appendPoint()
	new_point.P = (0.5, 0.5, 0.5)

急にPythonが出てきて申し訳ないのですが、オペレーターのパラメタで説明するよりもシンプルに説明できそうだったので取り上げているだけで、皆さんは今これをいじる必要はありません! とにかく scriptOp.appendPoint() の部分がポイントを追加している部分です。接続されている Info CHOPnum_points にも 1 と出ています。オペレーターを中ボタンクリックをして出てくるインフォメーションでもポイントは1と表示されているはずです。

では次に、script2 のDATを見てみましょう

def onCook(scriptOp):
	scriptOp.clear()

	new_point1 = scriptOp.appendPoint()
	new_point1.P = (0, 0, 0)

	new_point2 = scriptOp.appendPoint()
	new_point2.P = (0.5, 0, 0)

	new_point3 = scriptOp.appendPoint()
	new_point3.P = (0.5, 0.5, 0)

今度は scriptOp.appendPoint() が3回出てきました。なので、ポイントは3つ生成されています。最初のほうで Point は3Dの位置座標を持った点 というふうに紹介しましたので、とくに難しい事はなく、scriptOp.appendPoint() を呼んだ分だけポイントが生成されることになります。

次、script3 のDATです。

def onCook(scriptOp):
	scriptOp.clear()

	new_point1 = scriptOp.appendPoint()
	new_point1.P = (0, 0, 0)

	new_point2 = scriptOp.appendPoint()
	new_point2.P = (0.5, 0, 0)

	new_point3 = scriptOp.appendPoint()
	new_point3.P = (0.5, 0.5, 0)

	poly = scriptOp.appendPoly(3, closed=False, addPoints=False)
	poly[0].point = new_point1
	poly[1].point = new_point2
	poly[2].point = new_point3

さきほどの script2 のDATに比べると、後半部分の scriptOp.appendPoly(3, closed=False, addPoints=False) 以下の部分が追加されています。SOPのビューワーで見てもわかるように、ポイントをつなぐ線が追加されているので、そこ以降の操作で、点同士を繋いで線にする という処理をしています。

実際には、scriptOp.appendPoly(3, closed=False, addPoints=False) で、頂点数が3つの Poly プリミティブを作成して、その下に続く poly[0].point = new_point1 で、頂点がどのように接続されるべきかを指定しています。

つまり、SOPのデータ構造は、

という流れのまとまりになっています。

↑ と同様の処理を Add SOP で作った例が /project1/MAKE_BASIC_GEOM2 にあります。頂点の数が十数個までの場合だと Add SOP を使ったほうが便利です。

プリミティブの種類

/project1/PRIMITIVE_TYPES を参照

プリミテイブと一口に言っても、用途に応じていくつかのタイプにわかれてます。

Primitive
Sphere SOP, Circle SOP, Tube SOP などには、原点、半径、高さなど最低限のパラメタしか持っていない単純な形状があります。それぞれのSOPの Primitive Type から Primitive を選ぶと作れますが、ここだけの話何に使えるかはかなり謎でたまに選ばれちゃっててハマるぐらいなので、逆に Primitive が指定されていないかをチェックするようにしましょう
Polygon
ほとんどのケースでは Polygon を使う事になるはずです。これは、点を3つごと、三角形のポリゴンになるように接続した形です。GPUの中でジオメトリは最終的に三角形のポリゴンに変換されて描画されるので、描画効率の点でアドバンテージがあります。
Mesh
Polygon と似ていますが、Meshの場合は点を4つごと結んだ四角形ポリゴンを扱います。Polygon と比べて違う点は、四角形を敷き詰めたような形状になるため、ジオメトリに2次元の画像を貼るテクスチャ処理と相性がいい点です。また、Carve SOP など、ジオメトリのuv座標系を考慮して動作するオペレーターでは Polygon では動作しないものがあります。
NURBS, Bezier
点や面を直線的に繋ぐのではなく、点や面をコントロール要素として、数学的に算出されたカーブでなめらかな表面を描画します。描画的には綺麗なのですが、やや直感的でない所があったり、計算負荷の高いケースがあったりするので慣れが必要です。
Metaball
Metaball SOP を使って作成されます。磁力的な何かや表面張力のような質感のジオメトリが作れます。
Particle
Particle SOPConvert SOP などで作成されます。粒子のシミュレーションや、ポイントクラウドの描画などで使われます。

また、プリミティブに関する詳しい情報は Primitive - Derivative にもまとまっています。

まとめ

という訳で、SOPの基本の概念についてをすこし説明してきました。とくにプリミティブのタイプの違いについては、僕が一番最初に学習した時ハマった部分でもあります。経験からいくと、とりあえずハマった時のワークアラウンドとしては、ジオメトリ操作系のSOPで何かうまくいかないなと思ったら

  1. 中ボタンクリックでインフォメーションウィンドウを表示 → 凝視
  2. とりあえず入力を Convert SOPConvert to > Polygon にしてみる (入力にPolygonしかとれないSOPがチョイチョイある)
  3. UV座標系が必要なものであれば Convert SOPConvert to > MeshNURBS にしてみる
  4. ものすごい簡単なネットワークを新しく作って、複雑度を最小化しながらテストする
  5. 詳しい人に聞く
  6. バグレポートを出す

あたりでしょうか…

あんまり基礎の部分を長々とやっていても面白くないと思うので、ほどほどにして、早速実践のほうに移っていこうと思います

プロシージャルモデリング基礎1

まずはやってみよう

セクションの最初に、簡単なサンプルを使ってプロシージャルモデリングエッセンスをお伝えできればと思います。

CHOPのパラメーターのリンクの仕方などは大丈夫… ですよね…? → 微妙な方はこちら

/project1/PROCEDURAL_MODELING1 を参照

「大きさが変わっても床の上に居座るキューブ」です。Noise CHOP でキューブのサイズを動かしていますが、ここでの本質はそこではなく、キューブのサイズが変わると、変わった分だけキューブの中心座標を動かして必ず底面が設置するようにパラメーターを調整するエクスプレッション です。

実際には全然難しい事はなく、キューブの高さ * 0.5Center の Y座標に入れればいいだけなので、↓ のようになります。

念のため、動画も貼っておきます。自分でやったのが思い通りに動くとメチャクチャ楽しいので、みなさんも作ってみてください!

練習問題1

現状だと一個問題があって、Box SOPScale の値が1でないと狙った通りの挙動になりません。
エクスプレッションを改良して、Scale の値が1でない状態でもボックスが接地できるようにしてみてください!

正解は /project1/PROCEDURAL_MODELING1/exercises1

プロシージャルって何?

簡単な例題をやってみました。ところでプロシージャルですが、字面からの意味ですと「手続き型の」という約になるようです。。手続き型… わからん…

「プロシージャ」というのは文字ベースな言語で言う所の、「関数呼出し」にあたると思っています。「ブラックボックス化可能な」「思考的に抽象化可能な」と言い替えてもいいかもしれません。

なので、個人的な肌感覚だとさき程の例は実は「プロシージャルモデリング」ではなく、「パラメトリックモデリング」の一種なのではないかと思います。では、プロシージャルモデリングとはどういう事なのでしょうか?

/project1/PROCEDURAL_MODELING2 を参照

さきほどからの変更点は Box SOP の後の Transform SOP にあります。

Transform SOPty-me.inputs[0].min.y が指定されています。これは、「1番目に入力されているSOPの最小のyの値に -1 を掛けたもの」という意味になります。

要するに、さきほどはキューブの大きさから求めていたY軸のオフセットを、「入力されたジオメトリ全体のポイントのうち、一番下にあるポイント」を基準にオフセットを決める という風になりました。これによって、どんなSOPを入れても床を基準にしたオフセットがかかるようになる → 床に接地した状態になるようになります。

本当にそうなるか、色々なSOPを接続して試してみてください!

まとめ

このセクションでは、「プロシージャルモデリング」と、「パラメトリックモデリング」について紹介しました。両方を比べてみるとプロシージャルモデリングのほうがなんか強そうだという印象を持たれたかもしれませんが、実際の所は両者に明確な違いはないように思います。

というのも、さきほどの例にもあった「床に接地するようにオフセットをかけるTransform SOP」のような処理を一度通した後ならば、パラメトリック的な手法でさらに複数の処理をかけるといったことが簡単にできるからです。

言い換えると、ある処理をするにあたっての必須の要件を満たすように前処理をする、ノーマライズするといった事がプロシージャルにモデリングをする事の出発点になるかもしれません。前処理をしたあとであればより自由で簡単にさまざまな手法でモデルを操作できます。

なので、何かジオメトリを操作する時、なるべく入力のジオメトリを変更しても同じような結果にできないか を意識してネットワークを組んでいると、煮詰った時簡単に違う入力に差し替えて試してみる事ができます。非常にオススメです 👍

プロシージャルモデリング基礎2

色々なアプローチ

練習問題2

/project1/PROCEDURAL_MODELING3 を参照

「幅、高さが1ユニットの、XY平面に広がる四角形」を、できるだけ色々なアプローチで書いてみましょう!
こちらでもいくつか作ってみました。 /project1/PROCEDURAL_MODELING3/exercises1 にあります

練習問題3

/project1/PROCEDURAL_MODELING4 を参照

同様にして、「中心に穴のあいた、ドーナッツのような円」を、できるだけ色々なアプローチで書いてみましょう!
これも、いくつか作ってみました。 /project1/PROCEDURAL_MODELING4/exercises1 にあります

まとめ

どうだったでしょうか?SOPを使ったモデリングでは、同じような形状を作るのにも色々なアプローチがあります。

それぞれのオペレーター自体には違った機能があるが、結果として同じような事ができるものがあります。ニッパーやペンチといった工具のようなものとして考えてしまってもいいかもしれません。違う工具を使っても同じ結果にたどり着く事はできます。違うのは、その処理に対して最適になるように設計して作られているかどうかです。

そして、仮に最適でない筋道を辿ることになっても、その後に続けたいエフェクトやアニメーションの処理によっては最適化されたオペレーターを使わないほうが結果的に最良の手になる時もあります。

これは語学におけるボキャブラリーにも似たような事が言えると思います。言い回しのバリエーションが増えるとより直接的な言い方、より遠回しで優雅な言い方など、豊富な表現ができるようになります。

Help > Operator Snippets には、さまざまなオペレーターの簡単な使い方がわかりやすくリストされています。オペレーターの使い方のボキャブラリーを増やすために、時間がある時にじっくりと観察してみるといいかもです 👍👍

頻出SOPの解説

このセクションでは、よく使うSOPのオペレーターをいくつか紹介していきたいと思います。

Group SOP

/project1/EDIT_GEOMETRY1 を参照

TouchDesignerのSOPでは、レイヤー的な仕組みがないため Merge SOP などを使って一個のジオメトリにしてしまうと後から任意のポイントやプリミティブを編集するのが難しくなってしまいます。Group SOP はそういったケースのために、Point, Vertex, Primitive に対してグループを設定するオペレーターです。

一度グループに指定すると、各SOPの Group テキストボックスの中でターゲットとなるグループが選択できるようになります。特に各頂点の移動は、動かしたい頂点を一旦ポイントグループに追加してから Transform SOP で移動させる、といった方法でないと(多分) 移動できないです。

また、Group テキストボックスにはプリミティブのIDを入れることで、グループを作成しないでも同様の効果が得られるものがあります

Convert SOP

/project1/EDIT_GEOMETRY2 を参照

Convert SOP はプリミティブのタイプを相互変換します。なのですが、経験上あまりちゃんとは動かない時が多いので

あたりの時だけ使っています。困った時にとりあえずかましてみる、といった使い方が多いです

Facet SOP

/project1/EDIT_GEOMETRY3 を参照

Facet SOP は頂点の分割、結合をしたり、法線の再計算をしたりします。ポリゴンそれぞれのスケールを変化させたい時や、法線の方向を調整してフラットシェーディングにしたい時などに使います。

SOPを使ったシーンの構築

/project1/CREATE_SOP_SCENE1 を参照

では、実際にこれまでやってきたSOPのノウハウをどういう風にして使っているかをハンズオン形式で解説したいと思います!

流れとしては、

  1. ソースとなるジオメトリを作る -> A
  2. ソースのジオメトリと同じポイント数の円を作る -> B
  3. AとBのポイントを Add SOPDelete Geometry, Keep Points でポイントだけにする
  4. Add SOP に入れて、ポリゴンのラインプリミティブを作る
  5. Resample SOP で分割して1ラインあたり3点になるようにする
  6. 新しく追加したポイントを Group SOPGroup by Range でグループ化する
  7. グループに対して Transform SOP で位置を調整して、Convert SOP で NURBS カーブに変換する

という感じになります。ラインに中点を追加してオフセット → NURBSに変換 のあたりが一番のポイントで、線のたるみのようなディテールが入ると急に「何かよくわからないけど物理的なもの」といった印象になります

インスタンシング

最後に、インスタンシングの幅を広げるTIPSを紹介したいと思います。

TouchDesignerは標準の機能でかなり簡単にGPUインスタンシングができますが、実はSOPとVertex Shader だけでもだいぶ似たことができます。

さらにはSOPレベルでジオメトリを前処理することで、ただ数を増やすだけでなく、インスタンスごとに違うキャラクターになるようにジオメトリを変形することも可能です

通常のインスタンシング

/project1/INSTANCING1 を参照

こちらは通常のインスタンシングです。特に変わった事はなく、Y軸方向のスケールをそれぞれ Noise CHOP からコントロールしています

静的インスタンシング

/project1/INSTANCING2 を参照

こちらはテクスチャの色情報を使って Vertex Shader 上でデフォームをしようというものです。なのですが、SOPレベルでUVの持ち方を工夫するだけで、Copy SOP で増やしたジオメトリに対して全く同じシェーダーでアニメーションをつけることができます。

SOPレベルのアトリビュートを使ったGPUデフォーム

/project1/INSTANCING3 を参照

さらに、Point SOP で定義したカスタムアトリビュートは GLSL MAT のシェーダーの中で使うことができます。これによって Copy SOP に入力するジオメトリの特定の部分にだけ影響を与えたり、任意のパラメーターを渡したりすることができます

おわりに

今回はSOPを中心に紹介してきましたが、なるべくSOPだけを使って… という風に考えてサンプルを作っていると、普段どれだけCHOPやTOPと連携させてSOPを使っていたかというのが切実に実感できました。。。

例えばオーディオビジュアルやモーショングラフィックを作る時だと、CHOPはエモーショナルな部分、SOPは形、シルエット、TOPは細かなディテール、というふうな使い方をすることが多いと思います。

ですが、TouchDesignerの一番のアドバンテージは、各種オペレータータイプをガシガシ変換しながら制作をしていける所だと思っています。なので、あえて今自分が苦手だなと感じるオペレーターも頑張って使い方を覚えることで他のオペレータでの作業も全体的にレベルが上がっていくのではないかと思います。

また、SOPに関して言うと TouchDesigner よりも Houdini のほうが圧倒的に学習のリソースが多いです。このワークショップに参加してSOPをもっと掘り下げたい!という人がいればHoudiniのほうも手を出してみるととてもいいと思います!

Tkanks! 🙌🙌🙌