A raymarched scene, running in the page

The scene below isn’t a video. It’s a fragment shader running on your GPU right now: every pixel marches a ray through a field of distances until it hits something. Drag it to look around.

Three spheres, blended with a smooth minimum. Drag to orbit.

Distances instead of triangles

There’s no mesh here. The whole scene is one function that takes a point and returns how far it is from the nearest surface. For a sphere, that’s one line:

float sphere(vec3 p, vec3 centre, float radius) {
  return length(p - centre) - radius;
}

Because the function never overestimates, a ray can safely step forward by whatever it returns. Near a surface the steps shrink, and once a step is tiny enough, the ray has arrived. That loop is called sphere tracing, and it’s about six lines long.

The smooth minimum

Taking the min of two distances joins two shapes, leaving a hard crease where they meet. A smooth minimum rounds the crease off instead, so when the shapes move, they melt into each other:

float smin(float a, float b, float k) {
  float h = max(k - abs(a - b), 0.0) / k;
  return min(a, b) - h * h * k * 0.25;
}

k is the blending distance. Beyond it, smin is the ordinary min. This polynomial version comes from Inigo Quilez’s article on smooth minimums, which covers several others.

Lighting from the same function

Everything else comes from the distance function too:

  • Normals come from its gradient, estimated with four extra samples.
  • Soft shadows march a second ray towards the light and track how closely it grazes the blobs.
  • Ambient occlusion samples a few points along the normal. Where the distance is smaller than expected, something is nearby.

The floor uses the page’s background colour, darkened only by shadow and occlusion, so it fades into the page. Switch your device between light and dark mode and the scene follows.