【GLSL】立方体とトーラスと球
See the Pen box + round box + sphere + torus by aadebdeb (@aadebdeb) on CodePen.
#define PI 3.14159265359 #define TWO_PI PI * 2.0 #define HALF_PI PI / 2.0 precision mediump float; uniform float u_time; uniform vec2 u_mouse; uniform vec2 u_resolution; vec3 repeat(vec3 p, vec3 interval) { return mod(p, interval) - interval / 2.0; } vec3 rotateX(vec3 p, float theta) { float c = cos(-theta); float s = sin(-theta); mat3 m = mat3(vec3(1, 0.0, 0.0), vec3(0.0, c, -s), vec3(0.0, s, c)); return m * p; } vec3 rotateY(vec3 p, float theta) { float c = cos(-theta); float s = sin(-theta); mat3 m = mat3(vec3(c, 0.0, s), vec3(0.0, 1.0, 0.0), vec3(-s, 0.0, c)); return m * p; } vec3 rotateZ(vec3 p, float theta) { float c = cos(-theta); float s = sin(-theta); mat3 m = mat3(vec3(c, -s, 0.0), vec3(s, c, 0.0), vec3(0.0, 0.0, 1.0)); return m * p; } vec3 translate(vec3 p, vec3 t) { mat4 m = mat4(vec4(1.0, 0.0, 0.0, 0.0), vec4(0.0, 1.0, 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(-t.x, -t.y, -t.z, 1.0)); return (m * vec4(p, 1.0)).xyz; } float calcBoxDistance(vec3 p, vec3 size) { return length(max(abs(p) - size, 0.0)); } float calcRoundBoxDistance(vec3 p, vec3 size, float r) { return calcBoxDistance(p, size) - r; } float calcSphereDistance(vec3 p, float size) { return length(p) - size; } float calcPlainDistance(vec3 p, vec3 n) { return dot(p, n); } float calcTorusDistance(vec3 p, vec2 size) { vec2 q = vec2(length(p.xz) - size.x, p.y); return length(q) - size.y; } float calcCylinderDistance(vec3 p, vec3 size) { return length(p.xz - size.xy) - size.z; } float calcDistance(vec3 p) { float d = 1000000.0; d = min(d, calcSphereDistance(translate(p, vec3(2.0, 0.0, 2.0)), 1.0)); d = min(d, calcTorusDistance(translate(p, vec3(2.0, 0.0, -2.0)), vec2(1.0, 0.3))); d = min(d, calcBoxDistance(translate(p, vec3(-2.0, 0.0, 2.0)), vec3(1.0))); d = min(d, calcRoundBoxDistance(translate(p, vec3(-2.0, 0.0, -2.0)), vec3(0.9), 0.1)); return d; } vec3 calcNormal(vec3 p) { float delta = 0.00001; return normalize(vec3( calcDistance(p + vec3(delta, 0.0, 0.0)) - calcDistance(p - vec3(delta, 0.0, 0.0)), calcDistance(p + vec3(0.0, delta, 0.0)) - calcDistance(p - vec3(0.0, delta, 0.0)), calcDistance(p + vec3(0.0, 0.0, delta)) - calcDistance(p - vec3(0.0, 0.0, delta)) )); } void main(void) { vec2 st = (gl_FragCoord.xy * 2.0 - u_resolution) / min(u_resolution.x, u_resolution.y); vec2 mouse = (u_mouse * 2.0 - u_resolution) / min(u_resolution.x, u_resolution.y); vec3 cameraPosition = vec3(mouse.x * 10.0, 10.0, mouse.y * 10.0 + 10.0); vec3 viewCenter = vec3(mouse.x * 5.0, 0.0, mouse.y * 5.0); // vec3 viewCenter = cameraPosition + vec3(cos(mouse.x * PI), sin(mouse.y * HALF_PI), sin(mouse.x * PI)); vec3 viewDirection = normalize(viewCenter - cameraPosition); float fov = 60.0; float angle = fov / 2.0 * PI / 180.0; vec3 cameraTop = vec3(0.0, 1.0, 0.0); vec3 cameraSide = cross(viewDirection, cameraTop); cameraTop = cross(cameraSide, viewDirection); vec3 rayDirection = normalize(cameraSide * sin(angle * st.x) + cameraTop * sin(angle * st.y) + viewDirection * cos(angle * st.x)); vec3 rayPosition = cameraPosition; float radian = u_time * 0.0003; vec3 lightPosition = vec3(5.0, 5.0, 5.0); vec3 color = vec3(0.0); float d; for (int i = 0; i < 256; i++) { d = calcDistance(rayPosition); rayPosition += rayDirection * d; } if (d < 0.0001) { vec3 normal = calcNormal(rayPosition); float weight = dot(normal, normalize(lightPosition)); color = vec3(1.0) * max(weight, 0.0) + vec3(0.1); } gl_FragColor = vec4(color, 1.0); }