ちょっといつもと違う感じにお絵描きがしたくなったので、基本になる四角形を色々書いてみます。正方形、長方形、角丸、適当な4点などの基本形。
正方形
今回は処理する点 p を -1 < x,y < 1 の範囲にします。
点 p と中心 c の距離のうち大きい方が、.5 より小さいかどうか見ています。
1 2 3 4 5 6 7 8 9 10 11 12 |
precision highp float; uniform vec2 resolution; float box(vec2 p,vec2 c,float size){ float len=max(abs(p-c).x,abs(p-c).y); return step(len,size); } void main(){ vec2 p=(gl_FragCoord.xy*2.-resolution)/resolution.y; gl_FragColor.b=box(p,vec2(.1),.5); } |
長方形
距離ベクトルとサイズベクトルの比較をする。
1 2 3 4 |
float box(vec2 p,vec2 c,vec2 size){ float len=max(abs(p-c).x-size.x,abs(p-c).y-size.y); return step(len,0.); } |
少し整理するとこうなります。
1 2 3 4 5 6 7 8 |
float box(vec2 p,vec2 c,vec2 size){ vec2 d=abs(p-c)-size; return step(max(d.x,d.y),0.); } void main(){ vec2 p=(gl_FragCoord.xy*2.-resolution)/resolution.y; gl_FragColor.b=box(p,vec2(.2),vec2(.5,.7)); } |
角丸四角形
角を丸めた四角形は距離関数を使うと簡単に作れます。
点から一定距離の図形が円で、四角から一定距離の図形が角丸四角形です。
距離関数からエッジ分を引いて処理するだけ。
そのままだと四角形はエッジ分膨らむので最初に補正しています。
1 2 3 4 5 6 7 8 9 10 |
float box(vec2 p,vec2 c,vec2 size,float edge){ vec2 d=abs(p-c)-size+edge; float l=length(max(d,0.))+min(max(d.x,d.y),0.); return step(l-edge,0.); } void main(){ vec2 p=(gl_FragCoord.xy*2.-resolution)/resolution.y; gl_FragColor.b=box(p,vec2(.1),vec2(.5,.7),.1); } |
回転
基本的な回転行列を適応すれば回転します。
p
にかければ中央を軸に、(p-c)
にかけると c
を軸に回転します。
1 2 3 4 5 6 7 8 9 10 11 12 |
const float th=acos(-1.)/4.; float box(vec2 p,vec2 c,vec2 size,float edge){ mat2 m=mat2(cos(th),-sin(th),sin(th),cos(th)); vec2 d=abs((p-c)*m)-size+edge; float l= length(max(d,0.))+min(max(d.x,d.y),0.); return step(l-edge,0.); } void main(){ vec2 p=(gl_FragCoord.xy*2.-resolution)/resolution.y; gl_FragColor.b=box(p,vec2(.1),vec2(.5,.7),.1); } |
任意の四点
GLSLの練習【Crop, Tiling】でやった三角形のように、外積で内外判定します。
渡す点の順番は時計回りか、反時計回りに。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
float cross2d (vec2 p1, vec2 p2) { return p1.x * p2.y - p2.x * p1.y; } float box(vec2 p,vec2 a,vec2 b,vec2 c,vec2 d){ bool _a=cross2d(b-a,p-a)<0.; bool _b=cross2d(c-b,p-b)<0.; bool _c=cross2d(d-c,p-c)<0.; bool _d=cross2d(a-d,p-d)<0.; return (_a==_b&&_b==_c&&_c==_d)?1.:0.; } void main(){ vec2 p=(gl_FragCoord.xy*2.-resolution)/resolution.y; gl_FragColor.b=box(p,vec2(-.1),vec2(.6,.1),vec2(.5),vec2(.1,.6));//ok gl_FragColor.r=box(p,vec2(-.1),vec2(.1,.6),vec2(.5),vec2(.6,.1));//ok gl_FragColor.g=box(p,vec2(.5),vec2(-.1),vec2(.1,.6),vec2(.6,.1));//ng } |
点の順番を気にしたくないなら3角形を組み合わせる方法もあります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
bool tri(vec2 p,vec2 a,vec2 b,vec2 c){ bool _a=cross2d(p - a, b - a) < 0.0; bool _b=cross2d(p - b, c - b) < 0.0; bool _c=cross2d(p - c, a - c) < 0.0; return _a==_b&&_b==_c; } float box(vec2 p,vec2 a,vec2 b,vec2 c,vec2 d){ return (tri(p,a,b,c)||tri(p,a,c,d)||tri(p,b,c,d)||tri(p,b,d,a))?1.:0.; } void main(){ vec2 p=(gl_FragCoord.xy*2.-resolution)/resolution.y; gl_FragColor.b=box(p,vec2(-.1),vec2(.6,.1),vec2(.5),vec2(.1,.6));//ok gl_FragColor.r=box(p,vec2(-.1),vec2(.1,.6),vec2(.5),vec2(.6,.1));//ok gl_FragColor.g=box(p,vec2(.5),vec2(-.1),vec2(.1,.6),vec2(.6,.1));//ok! } |
おまけ / メイン
ちょっと弄って適当な図形を書いてみます。
コードをずっと書いてたこのツールのアイコン。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
precision highp float; uniform vec2 resolution; float cross2d (vec2 p1, vec2 p2) { return p1.x * p2.y - p2.x * p1.y; } bool tri(vec2 p,vec2 a,vec2 b,vec2 c){ bool _a=cross2d(p - a, b - a) < 0.0; bool _b=cross2d(p - b, c - b) < 0.0; bool _c=cross2d(p - c, a - c) < 0.0; return _a==_b&&_b==_c; } bool box(vec2 p,vec2 a,vec2 b,vec2 c,vec2 d){ return (tri(p,a,b,c)||tri(p,a,c,d)||tri(p,b,c,d)||tri(p,b,d,a)); } void main(){ vec2 p=(gl_FragCoord.xy*2.-resolution)/resolution.y; if(box(p,vec2(-1,-.3),vec2(-.8,-.5),vec2(.5,1),vec2(1,.8)))gl_FragColor=vec4(0,.4,.7,1); if(box(p,vec2(-1,.3),vec2(-.8,.5),vec2(.5,-1),vec2(1,-.8)))gl_FragColor=vec4(0,.5,.8,1); if(box(p,vec2(.5,-1),vec2(1,-.8),vec2(.5,1),vec2(1,.8)))gl_FragColor=vec4(.1,.7,1.,1); } |
折り目と角を気にしなければ結構いい感じにできました。