はじめに
符号なし距離関数シリーズ第3弾です。
今回は、座標pに(1+距離関数)を掛けることによって実現できる魚眼レンズ効果で、色々な距離関数に置き換えてみましょう。
前回までの内容はこちら
元の画像
歪み具合が分かりやすいように、10x10のグリッドを用意し、それぞれのグリッドに左上から左下に掛けて番号を振り、円を描いた画像を用意しました。
魚眼レンズ(fish eye)効果
p*=(1.+length(p))*.5;
座標pに(1+ユークリッド距離)を掛けると魚眼レンズ効果になります。
ちょっと、コイツを掛けるとカッコよくなるので、結構使われていますね。
マンハッタン
チェビシェフ
ミンコフスキー (p=-∞)
ミンコフスキー (p=0.5)
ミンコフスキー (p=8)
六角形
星
逆魚眼
p*=(1.-length(p)*.25)*1.5;
中央を窪ませたい場合はマイナスすればよいです。
加算バージョンの魚眼
p+=sign(p)*length(p)*.05;
加算する場合はsignが必要です。lengthだとマイナスがなくなる為
減算バージョンの魚眼(逆魚眼)
p-=sign(p)*length(p)*1.5;
他、バリエーションは色々つくれますが、正直微妙です。
p-=sign(vec2(p.x,-p.y))*length(p);
p+=sign(vec2(p.x,-p.y))*length(p);
p-=length(p);
p+=length(p);
その他
魚眼レンズ効果と全く同じ距離関数を使うと距離関数の距離1を基点に歪ませることができます。
p*=(1.+lStar(p*rot(PI),5.))*.5;
.
.
.
l+= strokeInner(sd(lStar(p*rot(PI),5.)),.01);
デフォルトの魚眼レンズ効果でも同じことが起こってますね。
p*=(1.+length(p))*.5;
.
.
.
l+= strokeInner(sd(length(p)),.01);
サンプルプログラム
precision mediump float;
uniform vec2 m; // mouse
uniform float t; // time
uniform vec2 r; // resolution
uniform sampler2D smp; // prev scene
const float PI = acos(-1.);
const float TAU = PI * 2.;
#define saturate(x) clamp(x,0.,1.)
#define _tail2x(p,n) (mod(p,2.)-1.)
vec2 tail2x(vec2 p,float n){p*=n;return _tail2x(p,n);}
vec2 tailX2x(vec2 p,float n){p*=n;return vec2(_tail2x(p.x,n),p.y);}
vec2 tailY2x(vec2 p,float n){p*=n;return vec2(p.x,_tail2x(p.y,n));}
float cross(vec2 v1, vec2 v2) {return dot(v1,vec2(v2.y,-v2.x));}
mat2 rot(float a){float c=cos(a),s=sin(a);return mat2(c,-s,s,c);}
// signed distance
float sd(float d,float r){return r-d;}
float sd(float d){return 1.-d;}
float fill_na(float d){return step(0.,d);}
float fill(float d){return smoothstep(0.,0.01,d);}
float stroke(float d,float w){return 1.-smoothstep(w,w+0.01,abs(d));}
float strokeInner(float d,float w){return stroke(d-w,w);}
float strokeOuter(float d,float w){return stroke(d+w,w);}
float sumabs(vec2 p){return abs(p.x)+abs(p.y);}
float maxabs(vec2 p){return max(abs(p.x), abs(p.y));}
float minabs(vec2 p){return min(abs(p.x), abs(p.y));}
float lpnorm(vec2 p, float n){vec2 t=pow(abs(p),vec2(n));return pow(t.x+t.y,1./n);}
float lPoly(vec2 p,float n){
float a = atan(p.x,p.y)+PI;
float r = TAU/n;
return cos(floor(.5+a/r)*r-a)*length(p)/cos(r*.5);
}
float lStar(vec2 p,float n){
return min(lPoly(p,n*.5),lPoly(mod(n,2.)!=0.?vec2(-p.x,p.y):p*rot(TAU/n),n*.5));
}
float lStar(vec2 p,float n,float o){
return (lPoly(p,n)-lPoly(p*rot(PI/n),n)*o)/(1.-o);
}
float lHeart(vec2 p) {
p.y += .034;
p *= 1.1;
return sqrt(dot(p, p) - abs(p.x)*p.y);
}
float dot2(vec2 p){return dot(p,p);}
float sLocater(vec2 p){
float l=stroke(sd(maxabs(tailX2x(p,8.))),.016)*stroke(p.y,.03);
l+=stroke(sd(maxabs(tailY2x(p,8.))),.016)*stroke(p.x,.03);
l+=stroke(p.x,.001);
l+=stroke(p.y,.001);
return l;
}
float pCheckers(vec2 p,float n){vec2 q=p*n;return mod(floor(q.x)+floor(q.y),2.0);}
float seg(vec2 p,float s,float k){p=abs(p*k);return max(s+p.x,s*.5+p.y+p.x);}
float seg7(vec2 p,int n,float s,float k){
float l=5.,w=s*.5;
vec2 q=p.yx,h=vec2(s,0.),v=vec2(-w,w);
l = (n!=1 && n!=4 ?min(seg(q-h,s,k),l):l);
l = (n!=1 && n!=2 && n!=3 && n!=7?min(seg(p-v,s,k),l):l);
l = (n!=5 && n!=6 ?min(seg(p-w,s,k),l):l);
l = (n!=0 && n!=1 && n!=7 ?min(seg(q ,s,k),l):l);
l = (n==0 || n==2 || n==6 || n==8?min(seg(p+w,s,k),l):l);
l = (n!=2 ?min(seg(p+v,s,k),l):l);
l = (n!=1 && n!=4 && n!=7 ?min(seg(q+h,s,k),l):l);
return l;
}
void main(void){
vec2 p = (gl_FragCoord.xy * 2.0 - r) / min(r.x, r.y);
vec2 P =p;
float l=0.;
//p*=(1.+length(p))*.5;
//p*=(1.+sumabs(p))*.5;
//p*=(1.+maxabs(p))*.5;
//p*=(1.+minabs(p));
//p*=(1.+lpnorm(p,.5))*.5;
//p*=(1.+lpnorm(p,8.))*.5;
//p*=(1.+lPoly(p,6.))*.5;
p*=(1.+lStar(p*rot(PI),5.))*.5;
vec2 q=tail2x(p,10.);
l+= pCheckers(p,5.)*.25+.25;;
l+= stroke(seg7(q-vec2(.3,0.),int(floor((p.x+1.)*5.)),.4,1.3),.5);
l+= stroke(seg7(q+vec2(.3,0.),int(floor((1.-p.y)*5.)),.4,1.3),.5);
l+= strokeInner(sd(length(p)),.01);
//l+= strokeInner(sd(lStar(p*rot(PI),5.)),.01);
l*=step(-1.,p.x)*step(p.x,1.)*step(-1.,p.y)*step(p.y,1.);
l+=sLocater(P);
gl_FragColor = vec4(vec3(l), 1.0);
}