Help us understand the problem. What is going on with this article?

TouchDesignerでGLSL入門

More than 1 year has passed since last update.

この記事

VJでTouchDesigner初心者のわたくし、さのかずや(Twitter:@sanokazuya0306)が、TouchDesignerでGLSLを書く場合どんな感じになるんや、ということを書き記します。
日本語リファレンスがなかったので。ほぼ公式の動画やリファレンスの翻訳+要約です。

GLSLはほとんど書いたことありません。uniformとかvec4とかをかろうじて知ってるくらい。
シェーダープログラミングについて詳しく知りたい方はAyumu Nagamatsu兄さんの記事がとっても勉強になりますので一読をオススメ。
シェーダープログラミングの意義とその実装 | 永松 歩 | Ayumu Nagamatsu

環境はTouchDesigner 099、MacBook Pro Mid 2014を使用。

まずいじる

GLSL in Touch Designer - Lesson 1の内容。
GLSL TOPを立てて、色が変わるだけのFragment Shaderのパラメータをいじれるようにする。

GLSL TOPをつくる

まず適当に、GLSL TOPをつくる。
スクリーンショット 2017-08-26 22.57.29.png
初期設定ではGLSL TOPの中身は真っ白になっている。GLSL TOPに紐付いているText DAT(glsl1_pixel)の中身は下記のようになっているはず。

glsl1_pixel
// Example Pixel Shader

// uniform float exampleUniform;

out vec4 fragColor;
void main()
{
    // vec4 color = texture(sTD2DInputs[0], vUV.st);
    vec4 color = vec4(1.0);
    fragColor = TDOutputSwizzle(color);
}

これは色の設定がvec4 color = vec4(1.0);によって、16進数RGBAの(255,255,255,255)の状態になっているため。vec4 color = vec4(0.5);とかvec4 color = vec4(1.0, 0.0, 0.0, 1.0);とかにすれば色が変わる。

パラメータをアサインしていじれるようにする

myColorという変数を置き、その変数をParametersウィンドウからいじれるようにする。
まずコードを下記のように書き換える。

glsl1_pixel
// Example Pixel Shader

// uniform float exampleUniform;
uniform vec4 myColor;

out vec4 fragColor;
void main()
{
    // vec4 color = texture(sTD2DInputs[0], vUV.st);
    // vec4 color = vec4(1.0);
    vec4 color = myColor;   
    fragColor = TDOutputSwizzle(color);
}

次にParametersのVectors 1のUniform NameにmyColorと記入。
スクリーンショット 2017-08-27 2.13.05.png

そうするとParametersウィンドウからいじれるようになります。

tdtest1.gif

absTime.frameとMultiply TOPを使えば綿貫くんもギラギラします。チャラい!

ダウンロード.gif

小ネタ

スクリーンショット 2017-08-27 3.13.03.png
info DATを使うとShaderのコンパイル状況を確認できます。

スクリーンショット 2017-08-27 3.02.39.png
TOP to CHOPを使うとパラメータが可視化できます。CropをPixel(U,V)にすると便利。

inputを使ってあれこれ

GLSL in Touch Designer - Lesson 2の内容。

GLSL TOPのinputを使う

最初から入っているvec4 color = texture(sTD2DInputs[0], vUV.st);のコメントアウトを外し、vec4 color = myColor;をコメントアウトする。

glsl1_pixel
// Example Pixel Shader

// uniform float exampleUniform;
// uniform vec4 myColor;

out vec4 fragColor;
void main()
{
    vec4 color = texture(sTD2DInputs[0], vUV.st);
    // vec4 color = vec4(1.0);
    // vec4 color = myColor;    
    fragColor = TDOutputSwizzle(color);
}

そして何でもいいのでGLSL TOPにinputをつなぐと読み込める。
スクリーンショット 2017-08-27 3.06.28.png

sTD2DInputs[0]は一番上のinputに繋いだものが出る。sTD2DInputs[1]は上から2番め。
下記のようにして2つの入力をいじくることもできる。

glsl1_pixel
uniform float blend;

out vec4 fragColor;
void main()
{
    vec4 input1 = texture(sTD2DInputs[0], vUV.st);
    vec4 input2 = texture(sTD2DInputs[1], vUV.st);

    fragColor = blend*input1 + (1-blend)*input2;
}

スクリーンショット 2017-08-27 4.56.06.png

こんな感じ。四則演算できるからAdd TOPとかCross TOPよりカスタマイズできる。

inputにShaderを適用する

ここからが本番。
GLSL in Touch Designer - Lesson 3の内容。

いい感じのShaderを探す

Shadertoyという、いろんなShaderが共有されまくっている神サイトがあるのでdigしてみましょう。

上記のLessonではこんなシンプルなやつを使っている。
Simple Radial Blur
ちょっとつまんないのでこっちを使ってみる。
edge glow

ShaderをTouchDesignerに最適化する

ものによってはここが手強いのでがんばりましょう。

まずはShadertoyからGLSL TOPの下のText DATにコピペ。

edgeglow
float d;

float lookup(vec2 p, float dx, float dy)
{
    vec2 uv = (p.xy + vec2(dx * d, dy * d)) / iResolution.xy;
    vec4 c = texture(iChannel0, uv.xy);

    // return as luma
    return 0.2126*c.r + 0.7152*c.g + 0.0722*c.b;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    d = sin(iTime * 5.0)*0.5 + 1.5; // kernel offset
    vec2 p = fragCoord.xy;

    // simple sobel edge detection
    float gx = 0.0;
    gx += -1.0 * lookup(p, -1.0, -1.0);
    gx += -2.0 * lookup(p, -1.0,  0.0);
    gx += -1.0 * lookup(p, -1.0,  1.0);
    gx +=  1.0 * lookup(p,  1.0, -1.0);
    gx +=  2.0 * lookup(p,  1.0,  0.0);
    gx +=  1.0 * lookup(p,  1.0,  1.0);

    float gy = 0.0;
    gy += -1.0 * lookup(p, -1.0, -1.0);
    gy += -2.0 * lookup(p,  0.0, -1.0);
    gy += -1.0 * lookup(p,  1.0, -1.0);
    gy +=  1.0 * lookup(p, -1.0,  1.0);
    gy +=  2.0 * lookup(p,  0.0,  1.0);
    gy +=  1.0 * lookup(p,  1.0,  1.0);

    // hack: use g^2 to conceal noise in the video
    float g = gx*gx + gy*gy;
    float g2 = g * (sin(iTime) / 2.0 + 0.5);

    vec4 col = texture(iChannel0, p / iResolution.xy);
    col += vec4(0.0, g, g2, 1.0);

    fragColor = col;
}

スクリーンショット 2017-08-27 5.12.22.png
まあこんな感じでエラー出ちゃって動かないはず。
info DATを使いながらひたすらデバッグしましょう。

注目ポイントは以下の3つ。

①void main()

void mainImage( out vec4 fragColor, in vec2 fragCoord )を、
void main()に書き換える。
中身のout vec4 fragColor, in vec2 fragCoordは、下記のように改行して一番上の行に入れておく。

edgeglow
out vec4 fragColor;
in vec2 fragCoord;

②変数を外に出す

じっくり見ると、ここで対応が必要なのはiResolutioniChannel0iTimeの3つだけ。

  • iResolutionは解像度なのでuniformで出して別途入力。
  • iChannel0sTD2DInputs[0]に置き換えればOK。
  • iTimeはTouchDesigner内のTimeCodeと合わせればよいので、こちらもuniformで出して最初の値に水色でme.time.frameを入れておく。

ShaderToyのソースコードをTouchDesignerで使う - Qiita
こちらを参考にさせて頂きました。矢崎さんあざす!

③fragCoord.xy は vUV.xy * iResolution.xy

これでもまだうまくいかない。これはfragCoord.xyのせい。
fragCoord.xyはひらたくいうと、各ピクセルを並列で読み込むための印なのだが、TouchDesignerでそれに相当するものはvUV.xyというやつ。
こいつが少し曲者で、0-1の間で標準化されている

となると解決策は簡単で、解像度に合わせて引き伸ばせばよし。
つまりfragCoord.xyvUV.xy * iResolution.xyに置き換える。

正解者に拍手

edgeglow
out vec4 fragColor;
in vec2 fragCoord;

float d;

uniform vec2 iResolution;
uniform float iTime;

float lookup(vec2 p, float dx, float dy)
{
    vec2 uv = (p.xy + vec2(dx * d, dy * d)) / iResolution.xy;
    vec4 c = texture(sTD2DInputs[0], uv.xy);

    // return as luma
    return 0.2126*c.r + 0.7152*c.g + 0.0722*c.b;
}

void main ()
{
    d = sin(iTime * 5.0)*0.5 + 1.5; // kernel offset
    vec2 p = vUV.xy * iResolution;

    // simple sobel edge detection
    float gx = 0.0;
    gx += -1.0 * lookup(p, -1.0, -1.0);
    gx += -2.0 * lookup(p, -1.0,  0.0);
    gx += -1.0 * lookup(p, -1.0,  1.0);
    gx +=  1.0 * lookup(p,  1.0, -1.0);
    gx +=  2.0 * lookup(p,  1.0,  0.0);
    gx +=  1.0 * lookup(p,  1.0,  1.0);

    float gy = 0.0;
    gy += -1.0 * lookup(p, -1.0, -1.0);
    gy += -2.0 * lookup(p,  0.0, -1.0);
    gy += -1.0 * lookup(p,  1.0, -1.0);
    gy +=  1.0 * lookup(p, -1.0,  1.0);
    gy +=  2.0 * lookup(p,  0.0,  1.0);
    gy +=  1.0 * lookup(p,  1.0,  1.0);

    // hack: use g^2 to conceal noise in the video
    float g = gx*gx + gy*gy;
    float g2 = g * (sin(iTime) / 2.0 + 0.5);

    vec4 col = texture(sTD2DInputs[0], p / iResolution.xy);
    col += vec4(0.0, g, g2, 1.0);

    fragColor = col;
}

これでuniformで出した2つのパラメータを、入力データ(今回は1280x720)に合わせて下記のように設定すればいけるはず。
スクリーンショット 2017-08-27 5.23.44.png

できたやつがコレ。

55FPSくらい出る。強い子〜
映像は岐阜県大垣市の大垣駅付近です。大都会!

快適なTouchDesigner×GLSLライフを

とりあえずひつじさんのofxPostGlitchを移植したいなーと思ってまーす

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした