文脈です。
解説を書きます。基本的に試行錯誤9割で出来ています。
#つぶやきGLSL precision highp float;uniform vec2 resolution;uniform float time;void main(){vec4 p=gl_FragCoord/resolution.y-1.2;float y=pow(p.y,2.);p/=y;for(int i=0;i<3;i++)p.xy*=mat2(5,1,3,5)*.3,p=abs(fract(p+time)-.5);gl_FragColor=vec4(cos(vec3(4,3,5)+y+pow(p.y*2.3,5.))+1.,1);} pic.twitter.com/DgeeThEY3e
— phi16 (@phi16_) 2020年4月14日
precision highp float; uniform vec2 resolution; uniform float time; void main(){ vec4 p=gl_FragCoord/resolution.y-1.2; float y=pow(p.y,2.); p/=y; for(int i=0;i<3;i++)p.xy*=mat2(5,1,3,5)*.3,p=abs(fract(p+time)-.5); gl_FragColor=vec4(cos(vec3(4,3,5)+y+pow(p.y*2.3,5.))+1.,1); }
p
が座標、y
は奥行きで、圧縮すれば透視変換っぽいのではという適当な発想によりpow(p.y,2.)
を使っています。p
をy
で割っていい感じの座標系が手に入ります。- あとはIFSっぽい感じで。
mat2(5,1,3,5)*.3
は最初はmat2(3,2,-2,3)/sqrt(13.)
(純粋な回転) だったんですがいい感じのパラメータを探していったらこうなりました。乱数調整。 - 最後に色をつけます。このiqさんのpaletteの作り方を参考に、適当に
cos
に突っ込みました。cos
は 2π≒6 の周期を持つ関数なので適当に整数を突っ込むだけでもいろんな色味を探せます。vec3(4,3,5)
は RGB の差を表していて、後はy
で奥行き分の色味、pow(p.y,2.3,5.)
でさっき計算した模様をいい感じにパラメータに与えています。- あと
cos
の結果は -1 から 1 なので、1.
のオフセットを載せてあげると 0 から 2 になっていい感じに光ります。行儀は悪いけどそんなこと言ってられないということで。
終わり。そういえば gl_FragCoord.xy
の xy
がもったいないので全部 vec4
でやるということをやっていたけど効果あったのかはわかりません。
次です。
#つぶやきGLSL#define s e.xy*=mat2(9,-3,7,4)*.1,e=sin(e.xzy*2.)+.5
— phi16 (@phi16_) 2020年4月14日
precision lowp float;uniform vec2 resolution;uniform float time;void main(){vec3 p,e,d=p=vec3(gl_FragCoord.xy/resolution,1);p.z=time;for(int i=0;i<40;i++)e=p,s,s,s,p+=(e.z-.5)*d;gl_FragColor=vec4(cos(e.xyx-d),1);} pic.twitter.com/6g69VhbBb5
#define s e.xy*=mat2(9,-3,7,4)*.1,e=sin(e.xzy*2.)+.5 precision lowp float; uniform vec2 resolution; uniform float time; void main(){ vec3 p,e,d=p=vec3(gl_FragCoord.xy/resolution,1); p.z=time; for(int i=0;i<40;i++)e=p,s,s,s,p+=(e.z-.5)*d; gl_FragColor=vec4(cos(e.xyx-d),1); }
IFSっぽいノリで距離関数を書いたが結局見た目はそうはならなかった例。私がもともとそういう絵を作ったことがないので調整力が無い問題。
弄る前はこんな感じだったと思います。
precision highp float; uniform vec2 resolution; uniform float time; float f(vec3 p) { for(int i=0;i<3;i++) p.xy*=mat2(1,1,-1,1)/sqrt(2.),p=abs(fract(p.xzy)-.5)-.5; return length(p)-.3; } void main(){ vec3 p,d=p=vec3(gl_FragCoord.xy/resolution-.5,1); p.z=time; for(int i=0;i<40;i++)p+=f(p)*d; gl_FragColor=vec4(cos(p),1); }
この時点で p
を微妙にズレた場所に置いてしまうことで文字数を省略したり d
の normalize
をしないなどである程度稼ごうとしている感じですね。これはほぼ普通のraymarchのコード。
まず f
を潰します。abs(fract(p.xzy)-.5)-.5
はいい感じに三角波を生成していますが、どうせ周期関数なので sin(p.xzy)
にしました。当然シーンが崩壊するので周りの諸々をいじりながら調節するとこうなりました。
float f(vec3 p) { for(int i=0;i<3;i++)p.xy*=mat2(9,-3,7,4)*.1,p=sin(p.xzy*2.)+.5 return p.z-.5; }
- 回転行列をちょっと変えても線形変換は線形変換なのでなんとかなるイメージ
- 行列式が 0.57 で後に
*2.
してsin(x)≒x
するので空間の大きさとかをいい感じに変えない状況になってるかも(雑感)
- 行列式が 0.57 で後に
- あと
length(p)
の代わりにp.z
にしていますがこれも試行錯誤 (というよりlength
が長いので短く済むようにシーンを弄っていった) - (実際にはこの調節はコードを書きつつ絶えずやっている感じなのであまりこの工程順に意味はありません)
さて、関数とfor文がもったいないので潰します。
#define s e.xy*=mat2(9,-3,7,4)*.1,e=sin(e.xzy*2.)+.5 precision highp float; uniform vec2 resolution; uniform float time; void main(){ vec3 p,e,d=p=vec3(gl_FragCoord.xy/resolution-.5,1); p.z=time; for(int i=0;i<40;i++)e=p,s,s,s,p+=(e.z-.5)*d; gl_FragColor=vec4(cos(p),1); }
関数内で p
を弄っちゃってるので一度コピーしてあげる必要があります。ループはマクロでどうにかする。これで265chars。
あとは d
の計算で -.5
してるの消しても別によくない?と思って消して、5文字追加して色味を整えて (いろいろやって cos(e.xyx-d)
にした)、1文字足りなかったので lowp
にして (敗北) 終わり。
球がなんだか金属質な見た目になってかわいい。
あと最後。
#つぶやきGLSL#define m for(int i=0;i<15;i++)c=cos(e=p).z,e.xy*=mat2(c,c-1.,1.-c,c),e=sin(e*8.)*.2+.2,p+=(dot(e,e)-.1)*d;
— phi16 (@phi16_) 2020年4月15日
precision highp float;uniform float time;void main(){float c;vec3 d,e,u,p=d=gl_FragCoord.xyw/2e2-.7;p.z+=time;m u=p=e;m gl_FragColor=vec4(cos(e+u.z*3.),1);} pic.twitter.com/5q8LcCJRuh
#define m for(int i=0;i<15;i++)c=cos(e=p).z,e.xy*=mat2(c,c-1.,1.-c,c),e=sin(e*8.)*.2+.2,p+=(dot(e,e)-.1)*d; precision highp float; uniform float time; void main(){ float c; vec3 d,e,u,p=d=gl_FragCoord.xyw/2e2-.7; p.z+=time; m u=p=e; m gl_FragColor=vec4(cos(e+u.z*3.),1); }
gyaboさんの作品とかFMS_Catさんの作品がレイを2回飛ばしていて羨ましかったので2回飛ばしたかったというモチベーションです。
潰し始める前のvisualとcodeはコレ pic.twitter.com/r4BJsq0Q2n
— phi16 (@phi16_) April 15, 2020
precision highp float; uniform float time; float f(vec3 p){ p.xy *= mat2(cos(p.z),sin(p.z),-sin(p.z),cos(p.z)); for(int j=0;j<2;j++) p = fract(p.yzx)-.5, p.z-=0.1; return length(pow(abs(p),vec3(2.)))-.2; } void main(){ vec3 d,p=d=gl_FragCoord.xyw/4e2-.7; p.z+=time; for(int i=0;i<19;i++)p+=f(p)*d; gl_FragColor=vec4(cos(p)*.5+.5,1); }
ついに resolution
を使うのをやめたみたいです。
f
を潰していきます。
- 回転行列書くのが長いのでとりあえず
float c=cos(p.z), s=sin(p.z); p.xy *= mat2(c,s,-s,c);
にしました。 - ここで
s=sqrt(1.-c*c)
を考えましたが、なんとなくs=1.-c
にしてみたところ大して問題がないことがわかります。 float c=cos(p.z);p.xy*=mat2(c,1.-c,c-1.,c);
になりました。8文字減りました。- 今だとFabriceNEYRETさんのテクニックによる
p.xy*=mat2(cos(p.z+vec4(0,11,33,0)));
がもっと短くて良さそうです。14文字減ります。 - 追加情報
- 今だとFabriceNEYRETさんのテクニックによる
後は適当に書いた部分でどうでもよさそうなところを消しました。
float f(vec3 p){ float c=cos(p.z); p.xy*=mat2(c,c-1.,1.-c,c); p = fract(p.yzx-.5)-.5; return dot(p,p)-.1; }
fract(p.yzx-.5)-.5
をなんとなく sin(p*8.)*.2+.2
にしました。3文字減ります。pow(abs(p),vec3(2.))
で角ばっている感じを出していたのが戻ってきてうれしい気持ち。
あとはぐっとやります (242chars)。
precision highp float; uniform float time; void main(){ float c; vec3 d,e,p=d=gl_FragCoord.xyw/4e2-.7; p.z+=time; for(int i=0;i<19;i++)e=p,c=cos(e.z),e.xy*=mat2(c,c-1.,1.-c,c),e=sin(e*8.)*.2+.2,p+=(dot(e,e)-.1)*d; gl_FragColor=vec4(cos(p)*.5+.5,1); }
レイを飛ばす部分をマクロにして2度呼びます。どこから飛ばすかは何も考えてませんでしたが適当に弄っていたら e
がそれっぽく使えたので使います。偶然マーブル感ある模様になっていい感じ。
#define m for(int i=0;i<19;i++)e=p,c=cos(e.z),e.xy*=mat2(c,c-1.,1.-c,c),e=sin(e*8.)*.2+.2,p+=(dot(e,e)-.1)*d; precision highp float; uniform float time; void main(){ float c; vec3 d,e,u,p=d=gl_FragCoord.xyw/4e2-.7; p.z+=time; m u=p=e; m gl_FragColor=vec4(cos(e+u.z*3.),1); }
これで266chars。当初はこの時点だと足りなくて e=p,c=cos(e.z)
を c=cos(e=p).z
にして2文字稼いでますね。しんどいね。
お疲れさまでした。この記事の役に立たなさがすごい。ガチャ引きゲームに疲れたのでちゃんとvisual作りたいですね。