漫画やアニメなどでよくある集中線をGLSL
で実装します。
テクスチャを読み込んで混ぜるのが一番簡単ですが、形状や場所に限界があるのでGLSL
の関数を使って自由に書けるようにします。
三角関数を使う
まずはシンプルに考えます。
正規化して中心からの角度を計算、適当な三角関数で縞模様を作る。
1 2 3 4 5 6 7 8 9 10 11 |
precision highp float; uniform vec2 resolution; vec3 bc=vec3(1),cc=vec3(0); float NUM_OF_LINE=12.; void main(){ vec2 r=resolution,p=(gl_FragCoord.xy*2.-r)/min(r.x,r.y); float t=atan(p.y,p.x); t=cos(t*NUM_OF_LINE); //t = step(.6,t); gl_FragColor=vec4(mix(bc,cc,t),1.); } |
コメントアウト部分で2値化すると、より集中線っぽい気がします。
外積を使う
先ほどの方法だと外周になるほど太くなってしまい、集中線というよりはめでたい感じになっています。
先ほどと同じように正規化後、角度を適当に分割します。
その角度方向のベクトルと座標ベクトルの外積をとることで一定の太さの線を引きます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
precision highp float; uniform vec2 resolution; float M=5.; float cross2d(vec2 a,vec2 b){ return a.x*b.y-a.y*b.x; } vec3 bc=vec3(1),cc=vec3(0); void main(void){ vec2 r=resolution,p=(gl_FragCoord.xy*2.-r)/min(r.x,r.y); float rad=floor(atan(p.y,p.x)*M)/M; float l=abs(cross2d(vec2(cos(rad),sin(rad)),p)); l=step(l,.01); gl_FragColor=vec4(mix(bc,cc,l),1.); } |
中央を空けるには中心からの距離を使ってl*=step(.5,length(p));
のようにします。
ランダムな長さにする
ランダム関数を追加して中央からの距離をバラバラにしました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
precision highp float; uniform vec2 resolution; float M=5.; float rand(vec2 co){ return fract(sin(dot(co.xy,vec2(12.9898,78.233)))*43758.5453); } float cross2d(vec2 a,vec2 b){ return a.x*b.y-a.y*b.x; } vec3 bc=vec3(1),cc=vec3(0); void main(void){ vec2 r=resolution,p=(gl_FragCoord.xy*2.-r)/min(r.x,r.y); float rad=floor(atan(p.y,p.x)*M)/M; float l=abs(cross2d(vec2(cos(rad),sin(rad)),p)); float k=length(p)-.5*rand(vec2(rad))-.3; l=k*step(l,.01); gl_FragColor=vec4(mix(bc,cc,l),1.); } |
かなり理想的な感じになってきました。
微調整
以下の調整を行って完成です。
- 線の数の調整
- 線の間隔をランダムにする
- 線の外側を少し太くする
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
precision highp float; uniform vec2 resolution; float M=8.; float rand(vec2 co){ return fract(sin(dot(co.xy,vec2(12.9898,78.233)))*43758.5453); } float cross2d(vec2 a,vec2 b){ return a.x*b.y-a.y*b.x; } vec3 bc=vec3(1),cc=vec3(0); void main(void){ vec2 r=resolution,p=(gl_FragCoord.xy*2.-r)/min(r.x,r.y); float rad=floor((atan(p.y,p.x))*M)/M; rad+=rand(vec2(rad)*vec2(rad))/M; float l=abs(cross2d(vec2(cos(rad),sin(rad)),p)); float k=length(p)-.5*rand(vec2(rad))-.3; l=k*step(l,.01+.01*(length(p)-.3)); gl_FragColor=vec4(mix(bc,cc,l),1.); } |
実際に画像に適応するとこんな感じになります。
良い感じにできました。
最終コードだけ見るとごちゃごちゃしてるように見えますが、1つずつ見ると基本的な処理の組み合わせだけです。