第10回: ジオメトリインスタンスとGLSL
本日のtoeファイル ← ダウンロードしておいてください
今日は、ちょっと突っ込んだOpenGLのグラフィックのトピックをいつか紹介したいと思います。
ちょっととっつきにくいかもしれませんが、順を追って見ていけば結構単純です!
ジオメトリインスタンス
OpenGLの機能のひとつで、ジオメトリのコピーをGPUに処理させることで、とても大量のオブジェクトのコピーをリアルタイムで描画することができるものです。インスタンシングとも言ったりします。
わかりやすい例だとこのへん → three.js webgl - instancing test (single triangle)
TouchDesignerだとある程度オブジェクト数を出さないといけない場合、SOPなどでやるとすぐ限界がきてしまうので、物量感が欲しい場合には必須のテクニックになります。
とはいえ、基本はすごく簡単です。
基本のセットアップ
↑ の動画は、ジオメトリインスタンスを表示させるまでの最短の手順です。
使うのは、適当なSOP、SOP to CHOP、 Geometry COMP のみで、SOP to CHOP でCHOPに変換した頂点データをGeometry COMP に渡して描画してもらう、という流れです。
Geometry COMP の Instance > Instance のトルグをONにして、Instance CHOP/DAT/SOP パラメータに使いたいCHOPを設定します。
その後 TX, TY, TZ などのパラメータに、インスタンシングをする時に使いたいチャンネル名を渡します。

一旦設定してしまえば、SOPレベルで位置や頂点数などを変更すればそれをもとにインスタンシングされたコピーにも反映されます。
SOPレベルのアニメーション
↑ では、SOP to CHOP につないでいたジオメトリに Noise SOP をかけることでインスタンシングのソースにアニメーションをかけています。

色の情報も含めてインスタンシングするには、 SOP to CHOP の Attribute Scope、Rename Scope を編集します。
Attribute Scope では、CHOP側に立ち上げたいSOPアトリビュートを指定します。
例えば、SOPを中クリックして出てくるインフォーメーションの中の Cd[4] が色情報を表わすアトリビュートなのですが、それを立ち上げたい場合、Attribute Scope には Cd を。Rename Scope には cr cg cb ca 又はもっと簡潔に c[rgba] を追加します。
そうすると、SOP to CHOP のチャンネルの中に新たに追加したアトリビュートが見れるようになるはずです。
CHOPレベルのアニメーション1
もうすこし複雑なアニメーションにもチャレンジしてみましょう。
CHOPのオペレーターとインタンシングを組み合わせると興味深いアニメーションを簡単に試すことができます。
↓ の動画では、グリッド上に配置したインスタンスを、Speed CHOP で値を変更する事で全体を動かし、さらにその動きのスピードを調整できるようにしています。
また、動かしたままだとすぐに画面の外側にいってしまうので、 Limit CHOP を使って特定の範囲の中で折り返すようにしています。
Limit CHOP で折り返すようにした上で、インスタンスの初期位置を決定している Grid SOP を十分に大きくすると空間全体に一様に広がりつつループ的なアニメーションをするシーンが作れます。
CHOPレベルのアニメーション2
↓ の動画では、さきほど作ったシーンに対してさらにCHOPでエフェクトを加えています。
位置のアニメーションを加えたCHOPにさらに Noise CHOP を接続して、細かいレベルのアニメーションを作り、それを Math CHOP を使って Combile CHOPs > Add で 加えることで、大きな動き + 小さな動き というふうな動きのレイヤーを重ねることができます。
また、小さな動きのほうを Rename CHOP を使って c[rgb] にチャンネル名を変更し、Marge CHOP でまとめたものをインスタンスのソースに使うことで、シーン側のインスタンスのほうにも着色することができます。
GLSLを使ってジオメトリにエフェクトをかける
GLSLとは?
GLSLは、OpenGL Shading Language の略で、C言語によく似た構文でGPUの内部で処理されるプログラムを書くことができます。ひらたく言うと、メチャ高速な3D頂点データ、カラーデータ専用のプログラミング言語 です
TouchDesignerでは、今回紹介する GLSL MAT を使って独自のカスタムマテリアルを作るほか、GLSL TOP を使ってテクスチャに対してエフェクトを作ることができますが、TOPのほうはまた次の機会にしようと思います
まずは Geometry COMP を用意します。その後 GLSL MAT を作り、Geometry COMP にアタッチします。
GLSL MAT を作ると Text DAT が複数作られます。

それぞれ、Vertex Shader (頂点データ用のシェーダー)、Pixel Shader(カラーデータ用のシェーダー)、エーラーログ等が表示されるDAT です。
GLSL MAT を作った時には、 Vertex Shaderは ↓ のようになっているはずです。
// Example Vertex Shader
void main()
{
vec4 worldSpacePos = TDDeform(P);
gl_Position = TDWorldToProj(worldSpacePos);
}
それを、こう ↓ 書き変えてみましょう。TDDeform のカッコの中が変更されています。
// Example Vertex Shader
void main()
{
vec4 worldSpacePos = TDDeform(P + vec3(1, 0, 0)); // !!!
gl_Position = TDWorldToProj(worldSpacePos);
}
これは、入力されたジオメトリの情報を、X方向に1ユニット動かせ という処理のシェーダーとして動きます。
また、Pixel Shaderのほうは 最終的に変数 fragColor に入っている色で描画されることになっているので、
// Example Pixel Shader
// uniform vec4 exampleUniform;
out vec4 fragColor;
void main()
{
TDCheckDiscard();
vec4 color = vec4(1.0);
TDAlphaTest(color.a);
fragColor = TDOutputSwizzle(color);
}
となっているのを、
// Example Pixel Shader
// uniform vec4 exampleUniform;
out vec4 fragColor;
void main()
{
TDCheckDiscard();
vec4 color = vec4(1.0);
color.rgb = vec3(1, 0, 0); // !!!
TDAlphaTest(color.a);
fragColor = TDOutputSwizzle(color);
}
として、変数 color を途中で変更してしまうか、
// Example Pixel Shader
// uniform vec4 exampleUniform;
out vec4 fragColor;
void main()
{
TDCheckDiscard();
vec4 color = vec4(1.0);
TDAlphaTest(color.a);
fragColor = TDOutputSwizzle(color);
fragColor.rgb = vec3(0, 1, 0); // !!!
}
として最後の最後で fragColor を書き換えれば任意の色に変更できます。
Phong MATをGLSL MATに変換する
TouchDesignerの強力な機能として、既存の Phone MAT や PBR MAT を GLSL MAT に変換できる、というものがありますので紹介します。
さきほど説明した GLSL MAT だと、たしかにシェーダーは書けるようになるのだが、あまりにもプリミティブな所からのスタートになってしまうのでGLSLのプログラミングを相当勉強しないといい感じのレンダリング結果は出ません。
ですが、Output Shader 機能を使うと途中までパラメーターを調整していい感じにしたマテリアルを GLSL MAT として書き出し、Phone MAT などだけでは実現できなかった事を、自らカスタムすることによって独自のマテリアルを作ることができます。
Phone MAT を調整していい感じになった所で、 RGB > Output Shader... のボタンを押すと、その時点でのパラメタ変更が適応された GLSL MAT に変換されます。
変換されて出てきたシェーダーコードは結構分量が多くなっているのですが、TDDeform(P) のあたりが頂点情報を扱っている、という所は変わらないのでさきほどの GLSL MAT の例と同じくオフセット等を変更することができます
テクスチャによってジオメトリを変形させるシェーダー
折角GLSLを使っているのに右に1移動させてばっかでもしょうがないので、テクスチャの色情報を使って頂点を動かしてみましょう。
GLSL MAT でテクスチャを扱うには2ステップあります。
1. GLSL MAT のパラメーターを編集する
Sampler 1 > Sampler Name, TOP を編集します。
TOP には、使いたいTOPをアサインします。今回だと Noise SOP を指定しました。
Sampler Name には、GLSLコード側でどういう名前にするかを指定します。とりあえず uNoise にしました。
2. GLSLコードを編集する
動画の中で最終的にできたコードはこちらです
uniform sampler2D uNoise;
void main()
{
vec4 c = texture(uNoise, uv[0].xy);
vec4 worldSpacePos = TDDeform(P + c.xyz);
gl_Position = TDWorldToProj(worldSpacePos);
}
まず、GLSLコード側で、 GLSL MAT で指定したパラメタを使うぞという意思を表明します。 uniform sampler2D uNoise; という部分がそれです。その宣言以降、 uNoise という名前でテクスチャの情報にアクセスすることができるようになります。
そして、GLSLの texture() 関数で、どのテクスチャのどの部分の色をもらってくるかを指定して、テクスチャの色情報をひっぱってきます。どの部分かに関しては、ほとんどの場合、uv[0].xy を指定していればOKです。
uv[0] は、P と同じように、TouchDeisnger側で用意してくれている変数で、SOPのアトリビュートから自動的にマッピングされています。詳細はこちら → Write a GLSL Material - Derivative
vec4 c = texture(uNoise, uv[0].xy); として、色情報を uv[0] をキーにして取得したら、それをまた TDDeform(P + c.xyz) として頂点の位置を動かすパラメタとして使います。これでテクスチャを使った頂点アニメーションができました
TOP側の調整
シェーダーができたら、TOP側でテクスチャを変更してどういうアニメーションにするかを調整できます。
Noise TOP であれば Monochrome を Off にすることでカラーノイズになるので、xyzの軸に対して動くようになりますし、Common > Pixel Format を 16-bit float(RGBA) にすることで、0-1以上の値でも動いてくれるようになります