Ray Marching

Rendering with no geometry at all: the scene is a single function returning the distance to the nearest surface, and every pixel walks a ray through it in guaranteed-safe jumps. Shapes become formulas, boolean ops become min and max, and melting two objects together is one smooth-min.

Core Idea

The scene above contains no geometry. No vertex buffer, no triangles beyond the one full-screen triangle that wakes the fragment shader — the blob, the box, the ring and the floor are all one function:

float map(vec3 p)   // → distance from p to the nearest surface

That’s a signed distance field: positive outside, negative inside, zero on the skin. Rendering it means asking, for every pixel, where does my ray first touch zero? — and the answer is found by walking.

The Walk: Sphere Tracing

map(p) promises the nearest surface is at least that far away — in every direction. So the ray may jump exactly that far with a guarantee of hitting nothing on the way:

float t = 0.0;
for (int i = 0; i < 90; i++) {
    float d = map(ro + rd * t);
    if (d < EPSILON) break;    // touched the skin
    t += d;                    // the guaranteed-safe jump
}

Each circle in the demo is one d — watch the economy: empty space costs a few huge steps, while a ray grazing a surface takes many timid ones (aim along the sea circle’s edge). That asymmetry is the technique’s whole cost model.

The Scene Is Arithmetic

Because shapes are formulas, modeling becomes algebra:

Operation Code Meaning
union min(a, b) both shapes
intersection max(a, b) only the overlap
subtraction max(a, -b) b carved out of a
blend smin(a, b, k) shapes melt together
move a shape evaluate at p - offset translation = warping space
infinite copies evaluate at mod(p, cell) repetition costs nothing

Drag the hero’s k slider: smooth-min trades the hard min seam for a soft weld — an operation mesh modeling simply doesn’t have, which is why ray-marched work has that liquid, organic signature. And mod deserves its own sentence: one column becomes an infinite colonnade with zero extra cost, because the field just wraps.

Normals Without Normals

Meshes ship normals as stored data. A distance field doesn’t need to — the gradient of the field points straight out of the surface, so four to six extra samples recover it:

n = normalize(vec3(map(p + ex) - map(p - ex),
                   map(p + ey) - map(p - ey),
                   map(p + ez) - map(p - ez)));

Every lighting trick in the shading recipe then works unchanged — the hero’s soft shadows are just more marches, from the surface toward the light.

The Price

Ray marching inverts rasterization’s bargain. Rasterization asks “which pixels does this triangle cover?” and scales with geometry; marching asks “what does this pixel see?” and scales with resolution × steps — pure fragment-shader load, almost always GPU-bound. It shares that per-pixel question with ray tracing, but where tracing intersects rays against actual geometry analytically, marching only ever samples a function — which is why it handles shapes no mesh can express (fractals, infinite repetition, smooth blends) and why it starts to crawl when the field gets expensive.

Connections

The field itself is the signed distance idea promoted from a measurement to a scene description. The walk runs inside one GLSL fragment shader, lit by the standard shading recipe with gradient-derived normals. As a rendering strategy it sits opposite rasterization and beside ray tracing — three answers to the same question: how does a scene become pixels?