ツイッターでGLSLを書くという試み「#つぶやきGLSL」があります。
266文字という短いコードで何とかしようという楽しい遊びです。
今回描いたものは結構手こずったので出来上がるまでの流れと、文字数削減の方法を残しておきます。
ツールとして twigl.app を使わせていただきます。
過去のコードなどは以下に置いてます。
最初の一歩
classic
モードで適当に書き始めます。
アイデアとしては3方向からRGBのライトが照らす感じです。
各色のライトの範囲を円形に絞りつつ、内積(角度)を色の強さにしてます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
precision highp float; uniform vec2 resolution; uniform vec2 mouse; uniform float time; uniform sampler2D backbuffer; float f(vec2 p,vec2 c,vec2 v){ return pow(dot(normalize(p-c),normalize(v)),10.); } void main(){ vec2 r=resolution,p=gl_FragCoord.xy/r.y; vec3 c=vec3(0); if(length(p)<1.)c+=vec3(1,0,0)*f(p,vec2(0),vec2(1,1)); if(length(p-vec2(1,0))<1.)c+=vec3(0,1,0)*f(p,vec2(1,0),vec2(-1,1)); if(length(p-vec2(.5,1))<1.)c+=vec3(0,0,1)*f(p,vec2(.5,1),vec2(0,-1)); gl_FragColor=vec4(c,1); } |
色々試す
geek
モードに変えて文字数を減らしながら色々変えて確かめます。
今回は時間変数を使って光を左右に振ってみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
precision highp float; uniform vec2 r; uniform vec2 m; uniform float t; void f(out vec3 o,vec3 d,vec2 p,vec2 c,vec2 v){ float t=cos(t)*.3; mat2 m=mat2(cos(t),-sin(t),sin(t),cos(t)); if(length(p-c)<1.)o+=d*pow(dot(normalize(p-c),normalize(m*v)),10.); } void main(){ vec2 p=gl_FragCoord.xy/r.y; vec3 c=vec3(0),b=vec3(0,1,.5); f(c,b.yxx,p,b.xx,b.yy); f(c,b.xyx,p,b.yx,vec2(-1,1)); f(c,b.xxy,p,b.zy,-b.xy); gl_FragColor=vec4(c,1); } |
twigl にはアニメーション gif を書き出す機能もあるのですが、今回は表現される色が多く gif に向いてないのでサンプルは静止画か動画にします。
文字数を減らす
geeker
モードで表現を変えつつ文字数を減らしていく。
最初は楽しいけど、減らせるところが見つからなかくなったりすると辛い。
文字数削減の変形で以下のような面白い見た目になったりもしましたが、文字数の関係上削られることになりました。
1 2 3 4 5 6 7 8 9 10 11 12 |
vec3 o,a=vec3(0,1,.5); void f(vec3 d,vec2 c,vec2 v){ float t=cos(t)*.3,l=cos(t),m=sin(t); o+=d*pow(dot(normalize(c),normalize(mat2(l,-m,m,l)*v)),9.)/length(c); } void main(){ vec2 p=gl_FragCoord.xy/r; f(a.yxx,p,a.yy); f(a.xyx,p-a.yx,vec2(-1,1)); f(a.xxy,p-a.zy,-a.xy); gl_FragColor.xyz=o; } |
完成
1文字でも多く削っていき何とか 266 文字に収める。
言うのは簡単だけど無理なものは無理だし、妥協と革新のせめぎあいになる。
以下から改行やスペースを除くとちょうど266文字になった。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
vec3 o,a=vec3(0,1,.5); void f(vec3 d,vec2 c,vec2 v){ float t=cos(t)*.3,l=cos(t),m=sin(t); o+=d*pow(dot(c/length(c),mat2(l,-m,m,l)*v/length(v)),9.); } void main(){ vec2 p=gl_FragCoord.xy/r; f(a.yxx,p,a.yy); f(a.xyx,p-a.yx,a.xy-a.yx); f(a.xxy,p-a.zy,-a.xy); gl_FragColor.xyz=o; } |
文字数削減
ベクトルはスウィズル演算子を使って短縮できることが多いです。
出来るだけ新規の宣言を避け、他のベクトルと一緒に定義したいところ。
vec3
であれば 0, 1
のほかに1つ数値を定義できます。
1 2 3 4 5 6 7 8 9 10 |
vec2 a=vec2(0,1); vec2(1,1) a.yy vec3(0,0,1) a.xxy vec2(-1,1) a.xy-a.yx |
ベクトル初期化は書かなくてもいい。
1 2 |
vec3 o=vec3(0); vec3 o; |
normalize
のような長いビルドイン関数は3回以上使うなら #define
も考える。
無理矢理1文字減らすこともできる。
1 2 |
normalize(v) v/length(v) |
出来た色の代入も多少縮めて書ける。
1 2 |
gl_FragColor=vec4(c,1); gl_FragColor.xyz=c; |
回転行列は長いですが float
宣言を新規で書かなければ多少短くできます。
1 2 3 4 5 |
mat2(cos(t),-sin(t),sin(t),cos(t)); float c=cos(t),s=sin(t);mat(c,-s,s,c); //他のfloat宣言に合わせる場合 ,c=cos(t),s=sin(t)mat(c,-s,s,c); |
最後に、できるだけ宣言を少なくすることを意識します。
引数もなくていいものはなくす、グローバル変数に入れる。
float f
の7文字や vec3 v
の5文字を減らすために+4文字くらいで別方法が取れないか模索しているとどんどん楽しくなります。
ああ、PCと一緒に脳が焼ける。