LoginSignup
13
12

More than 5 years have passed since last update.

TouchDesignerでGeometryShader

Last updated at Posted at 2018-03-01

TouchDesignerではジオメトリシェーダもサポートされています。使ってみましょう!

スクリーンショット 2018-02-27 17.04.29.png

準備

とりあえず適当にSphereを出します。SphereのPrimitive TypeはPolygonにしておきます。

スクリーンショット 2018-02-27 17.14.08.png

VertexShaderとFragmentShader

次にGLSL MATGeo COMPにマテリアルとして設定します。その後、GLSLで記述したシェーダーを格納するText DATを3つ作り、それぞれVertex、Geometry、Fragmentと名前を変更してGLSL MATのパラメーターに紐付けます。

スクリーンショット 2018-02-27 17.32.08.png

ここまで出来たら、バーテックスシェーダとフラグメントシェーダを記述していきましょう。(Phong MATなどからOutputしたもので全然OKですが、ジオメトリシェーダがメインなので最小限にしています。)

Vertex
out int cameraIndex;

void main(){
    cameraIndex = TDCameraIndex();
    gl_Position = TDDeform(P);
}
Fragment
out vec4 fragColor;

void main(){
    fragColor = vec4(1.0);
}

GeometryShaderを記述する

昔のパイプラインでは、頂点はCPU側で用意するものであり、GPU側でその数を増やしたり減らしたりすることはできませんでした。そこで、この頂点を増減する機能をGPU上で実現するシェーダーステージが組み込まれました。それがジオメトリシェーダになります。頂点の増減によって、実質的にプリミティブを操作することができます。

Geometry
layout (triangles) in;
layout (triangle_strip, max_vertices = 3) out;

in int[] cameraIndex;

void main(){
    vec3 P0 = gl_in[0].gl_Position.xyz;
    vec3 P1 = gl_in[1].gl_Position.xyz;
    vec3 P2 = gl_in[2].gl_Position.xyz;

    gl_Position = uTDMats[cameraIndex[0]].worldCamProj * vec4(P0, 1.0);
    EmitVertex();

    gl_Position = uTDMats[cameraIndex[1]].worldCamProj * vec4(P1, 1.0);
    EmitVertex();

    gl_Position = uTDMats[cameraIndex[2]].worldCamProj * vec4(P2, 1.0);
    EmitVertex();
}

冒頭、1行目のlayout(〜) in;の箇所ではジオメトリシェーダに入ってくるプリミティブを、2行目layout(〜) out;では出力するプリミティブを指定します。そして、gl_in[i].gl_Positionで入力されたプリミティブのPosition情報を取り出しています。

パイプラインの中でジオメトリシェーダのステージは、バーテックスシェーダとフラグメントシェーダの間に位置しています。そのため、バーテックスシェーダでは座標変換(TDではTDWorldToProj())をせずに、そのままジオメトリシェーダへPosition情報を送ります。最後に、gl_Positionへ座標変換行列をかけたPosition情報をセットし、EmitVertex()で頂点を次のステージへと送り出します。上記では、そのままPositionの情報を受け流しただけなので見た目には変化が起きていません。

スクリーンショット 2018-03-01 17.17.02.png

GeometryShaderでポリゴンに分割して動かす

では、今回はHello Worldとしてポリゴンに分割し法線方向に動かしてみます。

Geometry
layout (triangles) in;
layout (triangle_strip, max_vertices = 3) out;

uniform float time;
uniform float dispScale;

in int[] cameraIndex;

void main(){

    vec3 P0 = gl_in[0].gl_Position.xyz;
    vec3 P1 = gl_in[1].gl_Position.xyz;
    vec3 P2 = gl_in[2].gl_Position.xyz;

    vec3 d0 = P0 - P1;
    vec3 d1 = P2 - P1;

    for(int i = 0; i < 3; i++){
        vec4 P = gl_in[i].gl_Position;
        vec3 N = normalize(cross(d1, d0));

        float disp = 2.0 + sin(time * 5.0) * dispScale;     
        P += vec4(P.xyz + N * disp, 1.0);

        gl_Position = uTDMats[cameraIndex[i]].worldCamProj * P;
        EmitVertex();
    }
}

スクリーンショット 2018-03-01 12.55.00.png

ポリゴンが分割された状態で動くようになりました。これで表現の幅を広げていけそうですね!

参考

シェーダの基礎的な知識は「ゲーム制作者になるための3Dグラフィックス技術」を一読されるのがおすすめです。TouchDesigner特有のUniformに関しては、公式Wikiの「Write a GLSL Material」をご覧ください。

13
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
12