glsl 2D座標変換 疑似パースペクティブまとめ

# 概要

良く使われている疑似パースペクティブですが、glsl特有の省略によって、良く使われている疑似パースペクティブは座標がひっくり返っていたりして、意味あるテクスチャーを貼る場合に困ったので、自分用の覚書です。岩の模様とか意味がないやつは別に問題ないです。

# 画像変換前の画像
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135381/81c796d2-5caa-8582-10a6-b40b11866923.png)

# Bottom
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135381/32adce7a-07e8-1036-176f-fa8d92b894b1.png)

# Top
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135381/0f39817d-93cd-9adb-02c6-41a0ddce23c2.png)

# Left
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135381/c5efb0be-6e0a-71de-122e-35931518361d.png)

# Right
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135381/2392c925-b9e0-3d62-b24a-20cc77036c1a.png)

# 水平
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135381/c8f556d0-f860-36b5-87cf-df1144157c82.png)

# 垂直
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135381/9b3d01a6-5bbe-391c-19d0-959329b909e5.png)

# 水平 + 垂直
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135381/84d6254f-dc6d-b9c1-9d16-b381d45b0cae.png)

```glsl
vec2 fakePerspectiveVH(vec2 p){
  float r = 1./abs(abs(p.x)<abs(p.y)?p.y:p.x);
  return abs(p.x)<abs(p.y)?vec2(p.x*r,(-2.*(r-1.)+1.)*sign(p.y)):vec2((-2.*(r-1.)+1.)*sign(p.x),p.y*r);
}
```

# その他
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135381/2e5dd249-9efa-9267-5f27-0a3a6ea3afd9.png)

キューブの中を再現

```glsl
  l+=mapCheck(fakePerspectiveVH(p));
  l+=mapCheck(p*2.);
```

# サンプルプログラム
```glsl
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 maxabs(vec2 p){return max(abs(p.x), abs(p.y));}

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;
}

vec2 fakePerspectiveBottom (vec2 p){
  float r = 1./p.y;
  return vec2(-p.x*r, -2.*(r+1.)-1.);
}

vec2 fakePerspectiveTop (vec2 p){
  float r = 1./p.y;
  return vec2(p.x*r, -2.*(r-1.)+1.);
}

vec2 fakePerspectiveLeft(vec2 p){
  float r = 1./p.x;
  return vec2(-2.*(r+1.)-1.,-p.y*r);
}

vec2 fakePerspectiveRight(vec2 p){
  float r = 1./p.x;
  return vec2(-2.*(r-1.)+1.,p.y*r);
}

vec2 fakePerspectiveVertical(vec2 p){
  float r = 1./abs(p.x);
  return vec2((-2.*(r-1.)+1.)*sign(p.x),p.y*r);
}

vec2 fakePerspectiveHorizontal(vec2 p){
  float r = 1./abs(p.y);
  return vec2(p.x*r,(-2.*(r-1.)+1.)*sign(p.y));
}

vec2 fakePerspectiveVH(vec2 p){
  float r = 1./abs(abs(p.x)<abs(p.y)?p.y:p.x);
  return abs(p.x)<abs(p.y)?vec2(p.x*r,(-2.*(r-1.)+1.)*sign(p.y)):vec2((-2.*(r-1.)+1.)*sign(p.x),p.y*r);
}

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;
}

float mapCheck(vec2 p){
  float l=0.;
  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*=step(-1.,p.x)*step(p.x,1.)*step(-1.,p.y)*step(p.y,1.);
  return l;
}

void main(void){
  vec2 p = (gl_FragCoord.xy * 2.0 - r) / min(r.x, r.y);
  vec2 P =p;
  float l=0.;
  l+=mapCheck(fakePerspectiveHorizontal(p));
  //l+=mapCheck(fakePerspectiveVertical(p));
  //l+=mapCheck(fakePerspectiveVH(p));
  //l+=mapCheck(p*2.);

  //l=mapCheck(fakePerspectiveBottom(p));
  //l=mapCheck(fakePerspectiveTop(p));
  //l=mapCheck(fakePerspectiveLeft(p));
  //l=mapCheck(fakePerspectiveRight(p));

  l+=sLocater(p);

  gl_FragColor = vec4(vec3(l), 1.0);
}
```

* [サンプルはこちら](http://jp.wgld.org/js4kintro/editor/#precision%20mediump%20float%3B%0Auniform%20vec2%20%20m%3B%20%20%20%20%20%20%20%2F%2F%20mouse%0Auniform%20float%20t%3B%20%20%20%20%20%20%20%2F%2F%20time%0Auniform%20vec2%20%20r%3B%20%20%20%20%20%20%20%2F%2F%20resolution%0Auniform%20sampler2D%20smp%3B%20%2F%2F%20prev%20scene%0A%0Aconst%20float%20PI%20%3D%20acos(-1.)%3B%0Aconst%20float%20TAU%20%3D%20PI%20*%202.%3B%0A%0A%23define%20saturate(x)%20clamp(x%2C0.%2C1.)%0A%23define%20_tail2x(p%2Cn)%20(mod(p%2C2.)-1.)%0A%0Avec2%20tail2x(vec2%20p%2Cfloat%20n)%7Bp*%3Dn%3Breturn%20_tail2x(p%2Cn)%3B%7D%0Avec2%20tailX2x(vec2%20p%2Cfloat%20n)%7Bp*%3Dn%3Breturn%20vec2(_tail2x(p.x%2Cn)%2Cp.y)%3B%7D%0Avec2%20tailY2x(vec2%20p%2Cfloat%20n)%7Bp*%3Dn%3Breturn%20vec2(p.x%2C_tail2x(p.y%2Cn))%3B%7D%0A%0Afloat%20cross(vec2%20v1%2C%20vec2%20v2)%20%7Breturn%20dot(v1%2Cvec2(v2.y%2C-v2.x))%3B%7D%0Amat2%20rot(float%20a)%7Bfloat%20c%3Dcos(a)%2Cs%3Dsin(a)%3Breturn%20mat2(c%2C-s%2Cs%2Cc)%3B%7D%0A%0A%2F%2F%20signed%20distance%0Afloat%20sd(float%20d%2Cfloat%20r)%7Breturn%20r-d%3B%7D%20%0Afloat%20sd(float%20d)%7Breturn%201.-d%3B%7D%20%0A%0Afloat%20fill_na(float%20d)%7Breturn%20step(0.%2Cd)%3B%7D%0Afloat%20fill(float%20d)%7Breturn%20smoothstep(0.%2C0.01%2Cd)%3B%7D%0Afloat%20stroke(float%20d%2Cfloat%20w)%7Breturn%201.-smoothstep(w%2Cw%2B0.01%2Cabs(d))%3B%7D%0Afloat%20strokeInner(float%20d%2Cfloat%20w)%7Breturn%20stroke(d-w%2Cw)%3B%7D%0Afloat%20strokeOuter(float%20d%2Cfloat%20w)%7Breturn%20stroke(d%2Bw%2Cw)%3B%7D%0A%0Afloat%20maxabs(vec2%20p)%7Breturn%20max(abs(p.x)%2C%20abs(p.y))%3B%7D%0A%0Afloat%20sLocater(vec2%20p)%7B%0A%20%20float%20l%3Dstroke(sd(maxabs(tailX2x(p%2C8.)))%2C.016)*stroke(p.y%2C.03)%3B%0A%20%20l%2B%3Dstroke(sd(maxabs(tailY2x(p%2C8.)))%2C.016)*stroke(p.x%2C.03)%3B%0A%20%20l%2B%3Dstroke(p.x%2C.001)%3B%0A%20%20l%2B%3Dstroke(p.y%2C.001)%3B%0A%20%20return%20l%3B%0A%7D%0A%0Avec2%20fakePerspectiveBottom%20(vec2%20p)%7B%0A%20%20float%20r%20%3D%201.%2Fp.y%3B%0A%20%20return%20vec2(-p.x*r%2C%20-2.*(r%2B1.)-1.)%3B%0A%7D%0A%0Avec2%20fakePerspectiveTop%20(vec2%20p)%7B%0A%20%20float%20r%20%3D%201.%2Fp.y%3B%0A%20%20return%20vec2(p.x*r%2C%20-2.*(r-1.)%2B1.)%3B%0A%7D%0A%0Avec2%20fakePerspectiveLeft(vec2%20p)%7B%0A%20%20float%20r%20%3D%201.%2Fp.x%3B%0A%20%20return%20vec2(-2.*(r%2B1.)-1.%2C-p.y*r)%3B%0A%7D%0A%0Avec2%20fakePerspectiveRight(vec2%20p)%7B%0A%20%20float%20r%20%3D%201.%2Fp.x%3B%0A%20%20return%20vec2(-2.*(r-1.)%2B1.%2Cp.y*r)%3B%0A%7D%0A%0Avec2%20fakePerspectiveVertical(vec2%20p)%7B%0A%20%20float%20r%20%3D%201.%2Fabs(p.x)%3B%0A%20%20return%20vec2((-2.*(r-1.)%2B1.)*sign(p.x)%2Cp.y*r)%3B%0A%7D%0A%0Avec2%20fakePerspectiveHorizontal(vec2%20p)%7B%0A%20%20float%20r%20%3D%201.%2Fabs(p.y)%3B%0A%20%20return%20vec2(p.x*r%2C(-2.*(r-1.)%2B1.)*sign(p.y))%3B%0A%7D%0A%0Avec2%20fakePerspectiveVH(vec2%20p)%7B%0A%20%20float%20r%20%3D%201.%2Fabs(abs(p.x)%3Cabs(p.y)%3Fp.y%3Ap.x)%3B%0A%20%20return%20abs(p.x)%3Cabs(p.y)%3Fvec2(p.x*r%2C(-2.*(r-1.)%2B1.)*sign(p.y))%3Avec2((-2.*(r-1.)%2B1.)*sign(p.x)%2Cp.y*r)%3B%0A%7D%0A%0Afloat%20pCheckers(vec2%20p%2Cfloat%20n)%7Bvec2%20q%3Dp*n%3Breturn%20mod(floor(q.x)%2Bfloor(q.y)%2C2.0)%3B%7D%0A%0Afloat%20seg(vec2%20p%2Cfloat%20s%2Cfloat%20k)%7Bp%3Dabs(p*k)%3Breturn%20max(s%2Bp.x%2Cs*.5%2Bp.y%2Bp.x)%3B%7D%0Afloat%20seg7(vec2%20p%2Cint%20n%2Cfloat%20s%2Cfloat%20k)%7B%0A%20%20%20%20float%20l%3D5.%2Cw%3Ds*.5%3B%0A%20%20%20%20vec2%20q%3Dp.yx%2Ch%3Dvec2(s%2C0.)%2Cv%3Dvec2(-w%2Cw)%3B%0A%20%20%20%20l%20%3D%20(n!%3D1%20%26%26%20n!%3D4%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Fmin(seg(q-h%2Cs%2Ck)%2Cl)%3Al)%3B%0A%20%20%20%20l%20%3D%20(n!%3D1%20%26%26%20n!%3D2%20%26%26%20n!%3D3%20%26%26%20n!%3D7%3Fmin(seg(p-v%2Cs%2Ck)%2Cl)%3Al)%3B%0A%20%20%20%20l%20%3D%20(n!%3D5%20%26%26%20n!%3D6%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Fmin(seg(p-w%2Cs%2Ck)%2Cl)%3Al)%3B%0A%20%20%20%20l%20%3D%20(n!%3D0%20%26%26%20n!%3D1%20%26%26%20n!%3D7%20%20%20%20%20%20%20%20%3Fmin(seg(q%20%20%2Cs%2Ck)%2Cl)%3Al)%3B%0A%20%20%20%20l%20%3D%20(n%3D%3D0%20%7C%7C%20n%3D%3D2%20%7C%7C%20n%3D%3D6%20%7C%7C%20n%3D%3D8%3Fmin(seg(p%2Bw%2Cs%2Ck)%2Cl)%3Al)%3B%0A%20%20%20%20l%20%3D%20(n!%3D2%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Fmin(seg(p%2Bv%2Cs%2Ck)%2Cl)%3Al)%3B%0A%20%20%20%20l%20%3D%20(n!%3D1%20%26%26%20n!%3D4%20%26%26%20n!%3D7%20%20%20%20%20%20%20%20%3Fmin(seg(q%2Bh%2Cs%2Ck)%2Cl)%3Al)%3B%0A%20%20%20%20return%20l%3B%0A%7D%0A%0Afloat%20mapCheck(vec2%20p)%7B%0A%20%20float%20l%3D0.%3B%0A%20%20vec2%20q%3Dtail2x(p%2C10.)%3B%0A%20%20l%2B%3D%20pCheckers(p%2C5.)*.25%2B.25%3B%3B%0A%20%20l%2B%3D%20stroke(seg7(q-vec2(.3%2C0.)%2Cint(floor((p.x%2B1.)*5.))%2C.4%2C1.3)%2C.5)%3B%0A%20%20l%2B%3D%20stroke(seg7(q%2Bvec2(.3%2C0.)%2Cint(floor((1.-p.y)*5.))%2C.4%2C1.3)%2C.5)%3B%0A%20%20l%2B%3D%20strokeInner(sd(length(p))%2C.01)%3B%0A%20%20l*%3Dstep(-1.%2Cp.x)*step(p.x%2C1.)*step(-1.%2Cp.y)*step(p.y%2C1.)%3B%0A%20%20return%20l%3B%0A%7D%0A%0Avoid%20main(void)%7B%0A%20%20vec2%20p%20%3D%20(gl_FragCoord.xy%20*%202.0%20-%20r)%20%2F%20min(r.x%2C%20r.y)%3B%0A%20%20vec2%20P%20%3Dp%3B%0A%20%20float%20l%3D0.%3B%0A%20%20l%2B%3DmapCheck(fakePerspectiveHorizontal(p))%3B%0A%20%20%2F%2Fl%2B%3DmapCheck(fakePerspectiveVertical(p))%3B%0A%20%20%2F%2Fl%2B%3DmapCheck(fakePerspectiveVH(p))%3B%0A%20%20%2F%2Fl%2B%3DmapCheck(p*2.)%3B%0A%0A%20%20%2F%2Fl%3DmapCheck(fakePerspectiveBottom(p))%3B%0A%20%20%2F%2Fl%3DmapCheck(fakePerspectiveTop(p))%3B%0A%20%20%2F%2Fl%3DmapCheck(fakePerspectiveLeft(p))%3B%0A%20%20%2F%2Fl%3DmapCheck(fakePerspectiveRight(p))%3B%0A%0A%20%20l%2B%3DsLocater(p)%3B%0A%0A%20%20gl_FragColor%20%3D%20vec4(vec3(l)%2C%201.0)%3B%0A%7D)