黄金螺旋のような渦で何か書きたい。
基本的な対数螺旋から確認していきます。
以下の #つぶやきGLSL の作成ログでもあります( #19 )。
#つぶやきGLSL#define C(a,b)if(length(s*vec2(a,b)-p)<s*.5)
mat3 m=mat3(1);vec3 u;vec2 p=(FC.xy*2.-r)/r;
for(float i=0.;i<20.;i++){float h=atan(p.x,p.y),TAU=2.*acos(-1.),y=mod(t+i,20.),j=mod(i,3.),a=sin(y),b=cos(y),s=.01*exp(.3*y);C(a,b)u+=m[int(j)];C(b,a)u+=m[2-int(j)];}
o.rgb=u; pic.twitter.com/Q4f38id9zO— Narumium (@Nr_Narumium) December 9, 2020
基本の対数螺旋
まず対数螺旋は次の式で表すことが出来ます。
r(半径)はa(半径の基準値)、b(広がり具合)で決まります。
1 2 3 4 5 6 7 8 |
precision highp float; uniform vec2 resolution; void main(){ vec2 r=resolution,p=(gl_FragCoord.xy*2.-r)/min(r.x,r.y); float h=atan(p.x,p.y); float y=.5*exp(.3*h); if(abs(y-length(p))<.01)gl_FragColor=vec4(1); } |
先ほどのは1周分です。2πを足して2周させてみます。
1 2 3 4 5 6 7 8 9 10 11 12 |
void main(){ vec2 r=resolution,p=(gl_FragCoord.xy*2.-r)/min(r.x,r.y); float h=atan(p.x,p.y),TAU=acos(-1.)*2.; float y=.1*exp(.2*h); float z=.1*exp(.2*(h+TAU)); if(abs(y-length(p))<.01)gl_FragColor=vec4(1); if(abs(z-length(p))<.01)gl_FragColor=vec4(1); /* 確認用 if(abs(y-length(p))<.01)gl_FragColor=vec4(1,0,0,1); if(abs(z-length(p))<.01)gl_FragColor=vec4(0,1,0,1); */ } |
θに時間を使わず固定であれば周回する分を書く必要があります。
黄金螺旋
黄金の回転としてよく見る四角形の外周を描くような螺旋は黄金数を使ってbを設定します。大体 0.306 くらい。
螺旋状に円を動かす
螺旋を何週もさせたかったら for 文を使います。
time を角度に使って半径と合わせて円を螺旋に合わせて動かします。
1 2 3 4 5 6 7 8 9 10 11 |
void main(){ vec2 p=(gl_FragCoord.xy*2.-resolution)/resolution; float h=atan(p.x,p.y),TAU=acos(-1.)*2.; float t=mod(time*4.,20.); for(float i=0.;i<4.;i++){ float s=.01*exp(.3*(h+TAU*i)); if(abs(s-length(p))<.01)gl_FragColor=vec4(1); } float r=.01*exp(.3*t); if(length(r*vec2(sin(t),cos(t))-p)<.05)gl_FragColor=vec4(1,0,0,1); } |
逆回転
b を負にすることで逆回転も書けます。
ただし角度で見るとつなぎ目がないため、先ほどのように円を動かすのは 2π 毎に式を変える必要があります。
1 2 3 4 5 6 7 8 9 10 |
void main(){ vec2 r=resolution,p=(gl_FragCoord.xy*2.-r)/r; float h=atan(p.x,p.y),TAU=2.*acos(-1.); for(float i=0.;i<4.;i++){ float u=.01*exp(.3*(h+TAU*i)); float v=.01*exp(-.3*(h-TAU*i)); if(abs(u-length(p))<.01)gl_FragColor+=vec4(0,1,0,1); if(abs(v-length(p))<.01)gl_FragColor+=vec4(1,0,0,1); } } |
なんかどこかで見たようなマークなんですが、なんだろう。
色々試す
螺旋に使う半径をそのまま円にして螺旋の動きで円を動かす。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
void main(){ mat3 m=mat3(1);vec3 o; vec2 r=resolution,p=(gl_FragCoord.xy*2.-r)/r; float h=atan(p.x,p.y),TAU=2.*acos(-1.); for(float i=0.;i<3.;i++){ float t=mod(time*4.+i,30.),j=mod(i,3.); float s=.01*exp(.3*(t)); if(length(s*vec2(sin(t),cos(t))-p)<s*.5)o+=m[int(i)]; if(length(s*vec2(cos(t),sin(t))-p)<s*.5)o+=m[int(i)]; if(abs(s-length(p))<.01)o+=m[int(i)]; } gl_FragColor.rgb=o; } |
いい感じのができて、この後 geekest(300es) に変えて文字列を減らしてみましたが、ツイッター文字数にはちょっと届かない。
1 2 3 4 5 6 7 8 9 10 |
#define C(a,b)if(length(s*vec2(a,b)-p)<s*.5) mat3 m=mat3(1);vec3 u; vec2 p=(FC.xy*2.-r)/r; for(float i=0.;i<20.;i++){ float h=atan(p.x,p.y),TAU=2.*acos(-1.),y=mod(t*4.+i,20.),j=mod(i,3.),a=sin(y),b=cos(y),s=.01*exp(.3*y); C(a,b)u+=m[int(mod(i+2.,3.))]; C(b,a)u+=m[2-int(j)]; if(abs(s-length(p))<.01*s)u+=m[int(j)]; } o.rgb=u; |
ここから色々省いた削減版がつぶやいたものです。
途中で色々面白い動きもあったので、なにかしら再利用することがあるかもしれません。