GLSLでドット絵のパターンを考えていて、ひし形(正方形を45度傾けた形)ドットを作りたかったので色々試して勉強します。
1.ドット絵の角をとる
モザイクのときのように画像をブロックごとに分けて処理する。
20ブロックのドット絵にする関数でx+y<N
の条件を足してひし形にする。
1 2 3 4 5 6 7 8 9 10 11 |
precision highp float; varying vec2 uv; uniform sampler2D t; #define NUM_BLOCK 20. void main(){ vec2 p=floor(uv*NUM_BLOCK)/NUM_BLOCK+.5/NUM_BLOCK; vec4 c=texture2D(t,p); if(abs(uv.x-p.x)+abs(uv.y-p.y)<=.5/NUM_BLOCK) gl_FragColor=c; } |
惜しい気がしなくもないけど根本的な部分が違う。
まぁこれはこれで何かに使えるかも。
2.交互に敷き詰める
glslの練習【crop-tiling】の交互に敷き詰めの要領でドットをずらす。
1 2 3 4 5 6 7 8 |
void main(){ float y=floor(uv.y*NUM_BLOCK); float x=floor(uv.x*NUM_BLOCK+step(1.,mod(y,2.))*.5); vec2 p=vec2(x,y)/NUM_BLOCK+vec2(.5/NUM_BLOCK); vec4 c=texture2D(t,p); gl_FragColor=c; } |
通常ドット絵とはまた違う印象を受ける。
3.1と2を組み合わせる(失敗)
1 2 3 4 5 6 7 8 9 10 |
void main(){ float y=floor(uv.y*NUM_BLOCK); float x=floor(uv.x*NUM_BLOCK+step(1.0, mod(y, 2.0))*.5); vec2 p=vec2(x,y)/NUM_BLOCK+vec2(.5/NUM_BLOCK); vec4 c=texture2D(t,p); if(abs(uv.x-p.x)+abs(uv.y-p.y)<=.5/NUM_BLOCK) gl_FragColor=c; } |
パックマン柄に切り抜かれた。
偶然できたものだけど細かくして使うと味があるかも。
4.1と2を組み合わせる
x
をずらした分uv
もずらして判定を行う。
1 2 3 4 5 6 7 8 9 10 |
void main(){ float y=floor(uv.y*NUM_BLOCK); float x=floor(uv.x*NUM_BLOCK+step(1.0, mod(y, 2.0))*.5); vec2 p=vec2(x,y)/NUM_BLOCK+vec2(.5/NUM_BLOCK); vec4 c=texture2D(t,p); if(abs(uv.x+step(1.0, mod(y, 2.0))*.5/NUM_BLOCK-p.x)+abs(uv.y-p.y)<=.5/NUM_BLOCK) gl_FragColor=c; } |
ずいぶんそれっぽいけど、最後に切り抜きを行う以上隙間ができる。
この方針で何とかしたければY方向に重ねて処理する必要がある。
5.ひし形と三角形で処理する
四角形の集まりとして扱うと処理が複雑になる。
1の隙間部分を4つの三角形としてみて、これらが同じ画素値を参照すればよい。
1 2 3 4 5 6 7 8 9 10 11 12 |
#define NUM_BLOCK_X 20. #define NUM_BLOCK_Y 20. void main(){ float _x=.5/NUM_BLOCK_X; float _y=.5/NUM_BLOCK_Y; float x=floor(uv.x*NUM_BLOCK_X)/NUM_BLOCK_X+_x; float y=floor(uv.y*NUM_BLOCK_Y)/NUM_BLOCK_Y+_y; vec2 p=abs(uv.x-x)+abs(uv.y-y)<_y?vec2(x,y):vec2(uv.x-x>0.?x+_x:x-_x,uv.y-y>0.?y+_y:y-_y); vec4 c=texture2D(t,p); gl_FragColor=c; } |
ようやく目的通りの処理ができた。
縦横でブロック数を変えると6角形と4角形の敷き詰めになりアート感?がある。
6.六角形敷き詰め
4で作った形の隙間を埋める形で6角形を作ります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#define NUM_BLOCK_X 20. #define NUM_BLOCK_Y 20. void main(){ float _x=.5/NUM_BLOCK_X; float _y=.5/NUM_BLOCK_Y; float y=floor(uv.y*NUM_BLOCK_Y)/NUM_BLOCK_Y+_y; float s=step(1.0, mod((y-_y)*NUM_BLOCK_Y, 2.0))*.5; float x=floor(uv.x*NUM_BLOCK_X+s)/NUM_BLOCK_X+_x; s=s/NUM_BLOCK_X; vec2 p=abs(uv.x-x+s)+abs(uv.y-y)<_y?vec2(x,y): uv.y-y<=0.?vec2(x,y): s!=0.? vec2(uv.x-x+s>0.?x:x-2.*_x,y+2.*_y): vec2(uv.x-x>0.?x+2.*_x:x,y+2.*_y); vec4 c=texture2D(t,p); gl_FragColor=c; } |
ずらす処理のせいで大分複雑になりましたが、どの場合にどの位置の画素を使うかを決めていれば意外と書けます。
縦方向を縮めれば隙間の形が変わって和柄っぽくなります。
所感
失敗しつつも理解が深まってちゃんとできるようになるのが気持ちいい。
思いついて適当に書き始めるとまず失敗するけど、自発的には作れないような予想外の結果になったりするので楽しいです。
今回描いたやり方以外でもっと簡単だったり処理が軽かったりする書き方があるんだろうなと思いますが、こだわりすぎるときりがない気もする。