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