Raymarched fractal

A raymarched Sierpiński tetrahedron emerges from pure black under directional light and restrained HDR bloom, with drag-only orbit controls.

Open fullscreen
struct Params {
  resolution: vec2f,
  yaw: f32,
  pitch: f32,
}
@group(0) @binding(0) var<uniform> params: Params;
 
const V0 = vec3f(0.0, 1.0, 0.0);
const V1 = vec3f(0.94280904158, -0.33333333333, 0.0);
const V2 = vec3f(-0.47140452079, -0.33333333333, 0.81649658093);
const V3 = vec3f(-0.47140452079, -0.33333333333, -0.81649658093);
 
fn closestVertex(p: vec3f) -> vec3f {
  var vertex = V0;
  var score = dot(p, V0);
  let score1 = dot(p, V1); if (score1 > score) { score = score1; vertex = V1; }
  let score2 = dot(p, V2); if (score2 > score) { score = score2; vertex = V2; }
  let score3 = dot(p, V3); if (score3 > score) { vertex = V3; }
  return vertex;
}
 
fn fractalDistance(point: vec3f) -> f32 {
  var p = point;
  p = 2.0 * p - closestVertex(p);
  p = 2.0 * p - closestVertex(p);
  p = 2.0 * p - closestVertex(p);
  p = 2.0 * p - closestVertex(p);
  p = 2.0 * p - closestVertex(p);
  p = 2.0 * p - closestVertex(p);
  let d = max(max(dot(-V0, p), dot(-V1, p)), max(dot(-V2, p), dot(-V3, p))) - 0.33333333333;
  return d / 64.0;
}
 
fn clipPlane(ro: vec3f, rd: vec3f, normal: vec3f, interval: vec2f) -> vec2f {
  let a = dot(normal, ro) - 0.33333333333;
  let b = dot(normal, rd);
  if (abs(b) < 0.000001) {
    if (a > 0.0) { return vec2f(1.0, -1.0); }
    return interval;
  }
  let t = -a / b;
  if (b < 0.0) { return vec2f(max(interval.x, t), interval.y); }
  return vec2f(interval.x, min(interval.y, t));
}
 
fn outerInterval(ro: vec3f, rd: vec3f) -> vec2f {
  var bound = vec2f(-100000.0, 100000.0);
  bound = clipPlane(ro, rd, -V0, bound);
  bound = clipPlane(ro, rd, -V1, bound);
  bound = clipPlane(ro, rd, -V2, bound);
  bound = clipPlane(ro, rd, -V3, bound);
  return bound;
}
 
fn normalAt(p: vec3f, e: f32) -> vec3f {
  let k0 = vec3f(1.0, -1.0, -1.0);
  let k1 = vec3f(-1.0, -1.0, 1.0);
  let k2 = vec3f(-1.0, 1.0, -1.0);
  let k3 = vec3f(1.0, 1.0, 1.0);
  return normalize(k0 * fractalDistance(p + k0 * e) + k1 * fractalDistance(p + k1 * e) +
    k2 * fractalDistance(p + k2 * e) + k3 * fractalDistance(p + k3 * e));
}
 
fn ambientOcclusion(p: vec3f, n: vec3f) -> f32 {
  let d0 = fractalDistance(p + n * 0.012);
  let d1 = fractalDistance(p + n * 0.028);
  let d2 = fractalDistance(p + n * 0.060);
  let d3 = fractalDistance(p + n * 0.120);
  let occlusion = max(0.0, 0.012 - d0) * 8.0 + max(0.0, 0.028 - d1) * 3.0 +
    max(0.0, 0.060 - d2) * 1.2 + max(0.0, 0.120 - d3) * 0.35;
  return clamp(1.0 - occlusion, 0.55, 1.0);
}
 
@fragment fn fs_main(@location(0) uv: vec2f) -> @location(0) vec4f {
  let cp = cos(params.pitch); let sp = sin(params.pitch);
  let cy = cos(params.yaw); let sy = sin(params.yaw);
  let orbitTarget = vec3f(0.0, 0.18, 0.0);
  let orbitOffset = vec3f(3.15 * sy * cp, 3.15 * sp, 3.15 * cy * cp);
  let ro = orbitTarget + orbitOffset;
  let forward = normalize(orbitTarget - ro);
  let right = normalize(cross(forward, vec3f(0.0, 1.0, 0.0)));
  let up = cross(right, forward);
  var screen = uv * 2.0 - 1.0;
  screen.y = -screen.y;
  screen.x *= params.resolution.x / max(params.resolution.y, 1.0);
  let rd = normalize(forward + (right * screen.x + up * screen.y) * 0.32491969623);
  let bound = outerInterval(ro, rd);
  if (bound.x > bound.y || bound.y < 0.0) { return vec4f(0.0, 0.0, 0.0, 1.0); }
 
  var t = max(bound.x, 0.0);
  var eps = max(0.0008, 0.0003 * t);
  var hit = false;
  for (var step = 0; step < 96; step++) {
    let d = fractalDistance(ro + rd * t);
    eps = max(0.0008, 0.0003 * t);
    if (d < eps) { hit = true; break; }
    t += max(d * 0.8, eps * 0.5);
    if (t > bound.y || t > 6.0) { break; }
  }
  if (!hit || t > bound.y + eps || t > 6.0) { return vec4f(0.0, 0.0, 0.0, 1.0); }
  let p = ro + rd * t;
  let n = normalAt(p, max(0.0015, 2.0 * eps));
  let light = normalize(vec3f(-0.55, 0.78, 0.30));
  let diffuse = max(dot(n, light), 0.0);
  let ao = ambientOcclusion(p, n);
  let color = vec3f(1.0) * ao * (0.11 + 1.55 * diffuse);
  return vec4f(color, 1.0);
}