Level 3 · ●●○
The March Into 3D
Prerequisites: Levels 1–2. Vectors introduced in-page.
Here is a deal almost too good to be honest: everything you built in two dimensions comes to 3D unchanged. length(p) - r never asked how many coordinates carries. Give it two and it draws a circle; give it three and it describes a sphere. The min/max algebra, the smooth minimum, the domain tricks — all of them survive verbatim. What does notsurvive is the screen. A monitor is stubbornly flat, so for the first time we must ask: how do you turn a 3D field into a 2D image? The answer is this site's golden key.
Go deeper: vectors as arrows — all the 3D math you need★☆☆
A vector is an arrow: it has a length and a direction. In coordinates we write it by its components, — go across, up, toward you. Two kinds of arrows matter here:
- Positions: an arrow from the origin to a point. “The camera stands at .”
- Directions: an arrow that only says which way. We keep these at length 1 (“normalized”) so that position + t · direction walks exactly units along the arrow.
Length is Pythagoras with one more term: — length(v) in shader code, and the reason length(p) - r works in any dimension. normalize(v) is : same direction, length 1. One more tool arrives in Level 4 — the dot product, which measures how much two arrows agree — but you can march perfectly well without it today.
Same formulas, three components
A 3D distance field assigns a number to every point of space: distance to the nearest surface, negative inside. You cannot display all of it at once, but you can cut it. Below, the sphere's field length(p) - 0.7 is sliced by a movable plane — and every slice is an ordinary Level-1 picture:
The problem: a camera asks where rays hit
Every camera, real or rendered, answers one question per pixel: looking along this direction, what do I see first? Rendering by shooting a ray through each pixel and finding its first intersection is called raycasting, and for a handful of shapes it can be done with pure algebra — a ray hits a sphere where a quadratic equation says so, and that's how classical raytracing renders its glass balls, beautifully and exactly.
But look at what Level 2 left in our hands: shapes that have been melted together, repeated to infinity by a mod, bent by domain tricks. There is no quadratic formula for “two circles at , mirrored and tiled.” Algebraic intersection needs a formula per shape; our shapes no longer have names. What they have — all they have — is the one thing every field provides: at any point, a number promising how far the nearest surface is. We need a way to find ray hits that asks only that.
The golden key: leap exactly as far as the field allows
Stand at the ray's origin and ask the field: . By Level 1's Lipschitz promise, no surface exists within of you — in any direction, and in particular along the ray. So step forward exactly . Ask again. Step again:
When falls below a hair's width, you are standing on the surface; if runs past the horizon, the ray hit sky. That is the entire algorithm — sphere tracing, named for the spheres of guaranteed-empty space it leaps through. Watch it work, one honest step at a time:
Two behaviors deserve your attention in the stepper. Far from everything, the field is large and the ray crosses the scene in two or three giant leaps — empty space is cheap. Aimed near an edge, the safety circles shrink and the march tiptoes — grazing rays are expensive, which the step-cost view above renders as a glowing halo around every silhouette. And notice what showpiece B really is: the moment we run the same march for every pixel, the diagram becomes a renderer. White where rays land, black where they escape. It is unlit, flat, and a little anticlimactic — deliberately. Level 4 is one long crescendo from this silhouette to the landing page's hero, and every step of it is just more questions asked of the same field.
In the library, the march ships as raymarch— the loop you can read in either showpiece's code panel, with MAX_STEPS, a surface epsilon, and a far limit as its only knobs.
Go deeper: convergence, Lipschitz, and over-relaxation★★★
Why does the march terminate at all? For an exact field, each step covers the full distance to the nearest surface. If the ray actually hits, the remaining distance shrinks at worst geometrically near the surface (head-on rays converge in a handful of steps; the pathological case is a ray parallel to a nearby wall, where each step is bounded by the wall clearance — that is precisely the grazing halo). The Lipschitz bound is what makes the leap safe: a field with Lipschitz constant can never hide a surface inside the sphere of radius . If somewhere — a displacement cranked too high, a scale missing its * s — the promise breaks and rays tunnel through geometry.
Because cautious steps waste work in open space, production marchers often over-relax: step with , and fall back to the safe step if the next sample reveals the gamble overshot (the spheres of two consecutive steps must overlap; if they don't, retreat). Typical speedups are 20–40% on open scenes. The marcher in this site's library stays at — pedagogy prefers honesty to a free lunch with fine print.
Go deeper: when the field is only a bound — failure cases★★☆
Everything above assumed the field tells the truth. A bound field (smin welds, interiors of booleans, the octahedron shortcut) tells a cautious truth: never too large, possibly too small. Sphere tracing survives — smaller leaps, same guarantee — it just slows down in proportion to how timid the bound is.
What actually goes wrong in practice:
- Overestimating fields (broken scaling, aggressive displacement): rays leap past thin features and surfaces develop holes that flicker with the camera.
- Severely timid bounds: step counts explode and the renderer hits
MAX_STEPSbefore the surface — visible as a dark or missing silhouette edge, often misread as a shading bug. - Epsilon tuning: the “close enough” threshold trades a slightly inflated surface (large ε) against banding and step noise (small ε). Most artifacts you will ever see in raymarched work are one of these three.
Go deeper: raymarching vs raytracing vs rasterization★★☆
Three ways to put a scene on a screen, honestly compared. They are answers to different questions, not competitors for one crown:
| Sphere-traced raymarching | Analytic raytracing | Rasterization | |
|---|---|---|---|
| Scene description | one distance function (or bound) | intersection formula per shape | triangle lists |
| Finds a hit by | iterating safe leaps | solving equations exactly | projecting triangles, z-buffer |
| Loves | blends, repetition, fractals, fields | spheres, planes, quadrics; physical optics | huge meshes at 60 fps; hardware |
| Cost driver | steps per ray (grazing rays!) | rays × objects (until trees help) | triangles × overdraw |
| Weak spot | thin features, timid bounds | shapes without formulas | global effects need add-ons |
The deepest difference: rasterization starts from the geometry and asks which pixels it covers; both ray methods start from the pixel and ask what it sees. And within ray methods — if your shape has an intersection formula, analytic raytracing is exact and fast; the moment you melt, repeat, or displace, the formula evaporates and the march is what remains. Level 5 returns to raytracing for reflections, where the two approaches happily cooperate.
What you now know
- 2D formulas are 3D formulas —
length(p) − rwith a third component is a sphere, and slices of 3D fields are Level-1 pictures. - Rendering = one ray per pixel asking what do I see first? Analytic intersection answers it for textbook shapes; melted, repeated shapes have no formula.
- Sphere tracing: leap exactly , the distance the field guarantees empty — iterate to the surface. Empty space is cheap; grazing rays are expensive.
- Run the march for every pixel and the field is already a renderer — flat and unlit, for now.
A white silhouette knows where the surface is, but nothing about which way it faces, what color it wears, or what stands between it and the light. Level 4 asks the field five more questions — and the silhouette becomes a photograph.