Raymarching rendering of mandelbulb
Log in to post a comment.
#version 300 es precision highp float; const float ambient = 0.1; const vec3 ambientCol = vec3(0,0,1); const float specStrength = 0.3; const vec3 specCol = vec3(1); const float shininess = 4.0; const float paleness = 0.3; uniform int iterations; // value=16 min=1 max=32 step=1 uniform float power; // value=2.0 min=2.0 max=32.0 step=1.0 const float h = 0.001; const vec3 bulbPos = vec3(0,0,5); uniform float iTime; uniform vec2 iResolution; in vec2 vScreen; out vec4 fragColor; /** * Returns vec2( * the actual value, * the number of needed iterations * ). */ vec2 mandelbulb(vec3 q) { float a = iTime * 0.2; q /= 3.5; vec3 p = vec3(q.x, q.z, q.y); p = vec3( cos(a) * p.x - sin(a) * p.y, sin(a) * p.x + cos(a) * p.y, p.z ); const float bailout = 2.0; vec3 z = p; float dr = 1.0; float r = 0.0; int i; for (i = 0; i < iterations; i++) { r = length(z); if (r > bailout) break; // Spherical coordinate transformation float theta = acos(z.z / r); float phi = atan(z.y, z.x); dr = pow(r, power - 1.0) * power * dr + 1.0; float zr = pow(r, power); theta *= power; phi *= power; // Convert back to Cartesian coordinates z = zr * vec3(sin(theta) * cos(phi), sin(theta) * sin(phi), cos(theta)) + p; } return vec2( 0.5 * log(r) * r / dr, float(i) ); } float sdf(vec3 p) { return mandelbulb(p - bulbPos).x; } vec3 march(vec3 p, vec3 dir) { for (int i=0; i<200; i++) { float d = sdf(p); d = abs(d); p += d * dir; if (d < h || d > 1000.0) break; } return p; } vec3 gradient(vec3 p) { return vec3( sdf(p + vec3(h, 0, 0)) - sdf(p - vec3(h, 0, 0)), sdf(p + vec3(0, h, 0)) - sdf(p - vec3(0, h, 0)), sdf(p + vec3(0, 0, h)) - sdf(p - vec3(0, 0, h)) ) / (2.0 * h); } vec3 rainbow(float r) { r *= 6.28318530718; return vec3( 0.5 * sin(r + 0.000 - 0.0 * iTime) + 0.5, 0.5 * sin(r + 2.094 - 0.0 * iTime) + 0.5, 0.5 * sin(r + 4.188 - 0.0 * iTime) + 0.5 ); } vec3 rainbowLowRes(float r, int n) { r = floor(float(n) * r) / float(n); return rainbow(r); } void main() { vec3 o = vec3(0, 0, -1); vec3 dir = normalize(vec3(vScreen, 0) - o); o += vec3(0, 0, 0); vec3 p = o; p = march(p, dir); bool collision = sdf(p) < h; if (collision) { float c = dot( normalize(p - o), normalize(gradient(p)) ); c = abs(c); c -= 0.5; c -= floor(c); vec3 lightPos = o + vec3(2, 4, 0); vec3 N = normalize(gradient(p)); vec3 L = normalize(lightPos - p); float diff = max(0.0, dot(N, L)); vec3 R = reflect(-L, N); float spec = specStrength * pow(max(0.0, dot(-dir, R)), shininess); float numIterations = mandelbulb(p - bulbPos).y; vec3 diffCol = rainbow(numIterations / float(iterations)); diffCol = mix(diffCol, vec3(1), paleness); // make it a bit more pale vec3 col = ambient * ambientCol + diffCol * diff + spec * specCol; fragColor = vec4(col, 1); } else { fragColor = vec4(0, 0, 0, 1); } }