#この記事
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をつくる。
初期設定ではGLSL TOPの中身は真っ白になっている。GLSL TOPに紐付いているText DAT(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ウィンドウからいじれるようにする。
まずコードを下記のように書き換える。
// 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と記入。
そうするとParametersウィンドウからいじれるようになります。
absTime.frameとMultiply TOPを使えば綿貫くんもギラギラします。チャラい!
###小ネタ
info DATを使うとShaderのコンパイル状況を確認できます。
#inputを使ってあれこれ
GLSL in Touch Designer - Lesson 2の内容。
##GLSL TOPのinputを使う
最初から入っているvec4 color = texture(sTD2DInputs[0], vUV.st);
のコメントアウトを外し、vec4 color = myColor;
をコメントアウトする。
// 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をつなぐと読み込める。
sTD2DInputs[0]
は一番上のinputに繋いだものが出る。sTD2DInputs[1]
は上から2番め。
下記のようにして2つの入力をいじくることもできる。
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;
}
こんな感じ。四則演算できるから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にコピペ。
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;
}
注目ポイントは以下の3つ。
①void main()
void mainImage( out vec4 fragColor, in vec2 fragCoord )
を、
void main()
に書き換える。
中身のout vec4 fragColor, in vec2 fragCoord
は、下記のように改行して一番上の行に入れておく。
out vec4 fragColor;
in vec2 fragCoord;
②変数を外に出す
じっくり見ると、ここで対応が必要なのはiResolution
、iChannel0
、iTime
の3つだけ。
-
iResolution
は解像度なのでuniformで出して別途入力。 -
iChannel0
はsTD2DInputs[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.xy
をvUV.xy * iResolution.xy
に置き換える。
正解者に拍手
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)に合わせて下記のように設定すればいけるはず。
できたやつがコレ。
深夜に苦節2時間、TouchDesignerでGLSLの読み込みに成功して大喜びのまき pic.twitter.com/aV7deDhPnD
— さのかずや (@sanokazuya0306) 2017年8月26日
55FPSくらい出る。強い子〜
映像は岐阜県大垣市の大垣駅付近です。大都会!
#快適なTouchDesigner×GLSLライフを
とりあえずひつじさんのofxPostGlitchを移植したいなーと思ってまーす