Sketch · 2026-11-09
Sphere tracing, and what each pixel costs.
There are no triangles in this scene. Each object is a function that returns how far a point is from its surface, and every pixel walks its ray forward by that distance until it gets close enough to call it a hit. The default view does not show the picture. It shows how many steps each pixel needed to find it.
This browser did not give the page a WebGL context, so the shader cannot run. The ray inspector below still works on the CPU.
- mean steps per pixel
- —
- rays out of steps
- —
- safe step scale at this twist
- —
Drag to orbit. Click without dragging to pick a ray. Arrow keys orbit too.
Note
A signed distance function, or SDF, takes a point and returns the distance to the nearest surface, negative inside. The useful property is that nothing can be closer than that number. So a ray standing at a point with distance 0.4 can move 0.4 forward without any chance of passing through something. It repeats until the distance drops below a threshold. John Hart named this sphere tracing in 1996, after the empty sphere each step is allowed to cross.
The heatmap shows where that idea is cheap and where it is not. Rays that hit a face head on finish in a dozen steps. Rays that graze an edge, or skim the floor towards the horizon, crawl: the surface is always near, so every step is short, even though the ray is not heading into it. Lower the max steps and those are the rays that run out first. In the shaded view they show up as holes along silhouettes and a horizon that comes closer.
The column on the right is a box with its cross-section rotated in proportion to height. That twist bends space, and the box's distance formula, evaluated in bent space, can overstate the real distance. Near a corner at radius r, twisting by k radians per unit stretches distances by up to the square root of 1 + (kr)². The number under the image is the step scale that bound says is safe. The usual fix is to multiply every step by it, which costs steps everywhere for the sake of one object. The bound is loose, though. It only bites near the corners, and the error only matters when a ray is about to cross the surface, so at twist 1.5 the column looks clean at full step size. Push the twist towards 8 and jagged slivers appear along its edges, where rays stepped inside and stopped at the wrong depth.
The floating slab is 0.03 units thick. Push the step scale towards 2 in the plain rule and rays start to jump clean over it, while everything else turns to broken glass. Pick a ray through a gap in the slab and the inspector shows it: the dense line dips below zero between two arcs, and the tracer never sampled the dip. Between 1 and 1.6 the damage is quieter. Rays land a little inside surfaces, the hits are reported at the wrong depth, and the shading goes faceted.
The second rule comes from Keinert and colleagues in 2014. Step further than the distance allows, by a factor around 1.6, then check. If the sphere around the new point and the sphere around the old one do not overlap, the gap between them was never proven empty, so the ray goes back to the safe step and continues without relaxing. The fallback in their paper lands somewhat short of the safe point. Here it returns to exactly that point, which is simpler to read in the inspector. On this scene the gain is modest. From the starting view, a factor of 1.4 cuts the mean from about 21 steps to about 17.5. At 1.6 it saves almost nothing, because the floor-skimming rays fail early and walk the rest of the way unrelaxed. Above 1.8 it costs more than the plain rule. I first tried letting rays keep relaxing after a fallback. That was worse at every factor, since each failure costs a wasted evaluation and these rays fail often.
Everything runs twice. The fragment shader draws the image, and a copy of the same distance function in TypeScript marches a 64 by 40 grid of rays for the counters and the single ray you pick. Reading pixels back from the GPU would also work, but the CPU copy is what lets the inspector record every step. The two can differ in the last float digit, which is why a ray on the very edge of a silhouette may disagree with the pixel under it.
Sources
- Hart, J. C. (1996). Sphere tracing: a geometric method for the antialiased ray tracing of implicit surfaces. The Visual Computer, 12(10), 527-545.
- Keinert, B., Schäfer, H., Korndörfer, J., Ganse, U., Stamminger, M. (2014). Enhanced Sphere Tracing. Smart Tools and Apps for Graphics, Eurographics Italian Chapter Conference.
- Quilez, I. Distance functions. iquilezles.org/articles/distfunctions (box, torus and twist formulas).