--shader(GLSL)の小技 08-- Capsuleの距離関数からオペレーション部分を取り出した
Inigo Quilez :: fractals, computer graphics, mathematics, shaders, demoscene and more ここにある sdCapsule の距離関数
float sdCapsule( vec3 p, vec3 a, vec3 b, float r ) { vec3 pa = p - a, ba = b - a; float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 ); return length( pa - ba*h ) - r; }
より、オペレーション部分を取り出し、他の距離関数にも使えるようにした。
vec4 opSlide(vec3 p, vec3 a, vec3 b, vec3 up){ vec3 ba = b - a; float h = clamp(dot(p-a, ba) / dot(ba, ba), 0., 1.); p -= a + ba * h; vec3 w = normalize(ba), u = normalize(cross(up, w)), v = cross(w, u); return vec4(p * mat3(u, v, w), h); }
使い方は sdCapsuleと同じだが、upという引数が増えた。lookat行列のupと同じだ。
返り値がvec4になっているが、返り値を d
とした場合、d.xyz
が変換された座標、 d.w
が伸びてる空間のt値。このt値を使って色々と細工が出来る。
今回は少しバリエーションがあるので、スクリプトの使い方を見てください。
中身の方だか、lookat行列と同じ手法でmat3()を取得したが、今回は、逆行列として使ってます。
今回のshader (shadertoy rule)
mat2 rotate(float a) { return mat2(cos(a),sin(a),-sin(a),cos(a)); } // これは、sdCapsuleの距離関数のロジックをオペレーションに転嫁して球以外のモノにも対応できるようにしました。 vec4 opSlide(vec3 p, vec3 a, vec3 b, vec3 up){ vec3 ba = b - a; float h = clamp(dot(p-a, ba) / dot(ba, ba), 0., 1.); p -= a + ba * h; vec3 w = normalize(ba), u = normalize(cross(up, w)), v = cross(w, u); return vec4(p * mat3(u, v, w), h); } float sdSphere(in vec3 p, in float s ) { return length(p)-s; } float sdTorus(in vec3 p, in vec2 t ) { vec2 q = vec2(length(p.xz)-t.x,p.y); return length(q)-t.y; } float sdHexPrism(in vec3 p, in vec2 h ) { vec3 q = abs(p); return max(q.z-h.y,max((q.x*0.866025+q.y*0.5),q.y)-h.x); } float udRoundBox(in vec3 p, in vec3 b, in float r ) { return length(max(abs(p)-b,0.0))-r; } float deJyabara(in vec3 p, in float t) { float de2 = abs(length(p.xz) - 0.5 + 0.05 * sin(t * 30.0)); vec2 d = abs(vec2(de2, p.y)) - vec2(0.08, 0.0); return min(max(d.x, d.y), -0.03) + length(max(d, 0.0)); } float map(in vec3 p) { vec3 a = vec3(1); vec3 b = vec3(-1); vec3 up = normalize(vec3(1,2,3)); vec4 op = opSlide(p, a, b, up); p = op.xyz; switch (int(floor(mod(iTime * 0.3, 5.0)))) { case 0: return length(max(abs(p) - vec3(0.5, 0.2, 0.0), 0.0)) - 0.05; case 1: return sdTorus(p, vec2(0.5, 0.2)); case 2: return sdHexPrism(p.xzy, vec2(0.3, 0.2)); case 3: return sdSphere(p, 0.35); case 4: return deJyabara(p.xzy, op.w); } } vec3 doColor(vec3 p) { return vec3(0.8,0.5,0.2); } void mainImage( out vec4 fragColor, in vec2 fragCoord ) { vec2 uv=(fragCoord*2.0-iResolution.xy)/iResolution.y; vec3 ro=vec3(0,2,-5); ro.zx*=rotate(iTime*0.5); vec3 rd=normalize(vec3(uv,2)); vec3 ta=vec3(0); vec3 w=normalize(ta-ro); vec3 u=normalize(cross(w,vec3(0,1,0))); vec3 v=cross(u,w); mat3 lookat=mat3(u,v,w); rd=lookat*rd; float d,i,t=0.0; vec3 p=ro; vec3 col=vec3(0); for(i=1.0;i>0.0;i-=1./50.0) { t+=d=map(p); if(d<0.001) { col=doColor(p); col*=i*i; break; } p+=rd*d; } fragColor=vec4(col,1.0); }