Appearance
P0-C1: SDF Sphere Marching
Taught: 2026-04-24 (during Phase 0 Bootstrap) Milestone: Phase 0 — Bootstrap Result: PASS (after walkthrough with concrete numerical trace; original abstract teaching was insufficient) Backfilled: 2026-05-04 — original prose was scattered across the early planning session; reconstructed into the corrected conversational format
Why this concept matters here
Phase 0's core deliverable is a single sphere rendered in the browser via SDF ray-marching. Every later concept (composition, central-difference normals, Disney BRDF, MarchViz) builds on the march loop. Without the right intuition for "ray starts at the camera, steps by the SDF value, hits when distance is tiny, misses when t blows up," nothing else in the renderer makes sense.
The walkthrough
Step 1: What an SDF actually returns
An SDF (Signed Distance Function) is a function f(p) that, given any 3D point p, returns the distance to the nearest surface, with a sign:
- Positive if
pis outside the surface - Negative if
pis inside - Zero if
pis exactly on the surface
For a sphere of radius r at origin: f(p) = length(p) - r. Pick some points to verify:
Point p | length(p) | f(p) = length(p) - 1 | Meaning |
|---|---|---|---|
(0, 0, 0) (origin, inside) | 0 | −1 | "1 unit inside the surface" |
(0.5, 0, 0) | 0.5 | −0.5 | "0.5 inside" |
(1, 0, 0) (on surface) | 1 | 0 | "at the surface" |
(2, 0, 0) (outside) | 2 | +1 | "nearest surface 1 away" |
(5, 0, 0) (far away) | 5 | +4 | "nearest surface 4 away" |
Crucially, the SDF tells you the distance to the nearest surface. So at any point in space, you know how far you can move in any direction without hitting anything. That's what makes ray marching work.
Step 2: The march loop — what t means
We want to render the surface from a camera. We shoot a ray from the camera position into the scene, in some direction (computed from screen pixel + camera FOV).
ray_origin = camera_position
ray_dir = normalize(point_we're_aiming_at - camera_position)Now we walk along that ray. The variable t is how far we've walked from the camera. At t = 0 we're standing at the camera. At t = 5 we're 5 units along the ray.
current_position = ray_origin + ray_dir * tWe start with t = 0 (at the camera) and step forward.
Step 3: How big a step to take
Naive approach: take fixed-size steps, e.g., t += 0.01. Problem: at 0.01 per step, reaching a surface 5 units away takes 500 iterations. Too slow.
Smart approach (sphere tracing): at every position, ask the SDF "how far to the nearest surface?" Then step that far. The SDF guarantees nothing is closer, so this step is safe — you can't overshoot.
loop:
d = scene_sdf(current_position)
if d < HIT_EPS: HIT, stop
t += d
if t > MAX_DIST: MISS, stopThis is the entire algorithm. Each iteration:
- Sample the SDF
- If we're basically on the surface (
d < 0.001), declare a hit - Otherwise, take a step of size
d(the safe step) - If we've walked too far without hitting anything (
t > 20or so), declare a miss
Step 4: Concrete numerical trace — sphere at origin, radius 1, camera at (0, 0, 3)
Let's actually trace a ray through the algorithm, with real numbers, to see the safe-step shrinking pattern.
Setup: sphere of radius 1 at origin. Camera at (0, 0, 3) looking toward origin. Ray direction: (0, 0, -1). So current_position = (0, 0, 3 - t).
| Iter | t | position | length(p) | d = length(p)−1 | action |
|---|---|---|---|---|---|
| 0 | 0.0 | (0, 0, 3.0) | 3.0 | 2.0 | step by 2 |
| 1 | 2.0 | (0, 0, 1.0) | 1.0 | 0.0 | hit boundary; step by 0 (or hit at this iter if eps tolerates) |
Wait — at iteration 1, d is exactly 0 (we landed perfectly on the surface). With HIT_EPS = 0.001, we'd register a hit. In practice, ray directions aren't aligned to surfaces this cleanly, so let's redo with a slightly off-axis ray:
Ray from (0, 0, 3) toward (0.3, 0, 0). Direction (0.3, 0, -3) / length ≈ (0.0995, 0, -0.995).
| Iter | t | position | length(p) | d | action |
|---|---|---|---|---|---|
| 0 | 0.0 | (0, 0, 3.0) | 3.0 | 2.0 | step by 2 |
| 1 | 2.0 | (0.199, 0, 1.01) | 1.030 | 0.030 | step by 0.030 |
| 2 | 2.030 | (0.202, 0, 0.980) | 1.001 | 0.001 | HIT (d < HIT_EPS) |
Three iterations. Notice the safe steps shrink as you approach the surface — first step was 2.0 (big), then 0.030, then converged. This is the algorithm's whole magic: when you're far from anything, you take huge leaps; when you're near a surface, you crawl.
For a ray that misses the sphere entirely (e.g., aimed at (2, 0, 0)):
| Iter | t | position | length(p) | d | action |
|---|---|---|---|---|---|
| 0 | 0.0 | (0, 0, 3.0) | 3.0 | 2.0 | step by 2 |
| 1 | 2.0 | (1.11, 0, 1.34) | 1.74 | 0.74 | step by 0.74 |
| 2 | 2.74 | (1.52, 0, 0.73) | 1.69 | 0.69 | step by 0.69 |
| 3 | 3.43 | (1.91, 0, 0.16) | 1.91 | 0.91 | step by 0.91 |
| ... | ... | ray flies past sphere, getting farther | grows | ||
| ~25 | >20 | far away | huge | huge | MISS (t > MAX_DIST) |
For miss rays, t eventually exceeds the bailout threshold (MAX_DIST = 20 or 50).
Step 5: Why the magic numbers
Three constants in every march loop:
HIT_EPS = 0.001— how close is "on the surface enough." Smaller values = more accurate hit point but more iterations and more numerical noise. 0.001 is the standard for unit-scale scenes.MAX_STEPS = 64— iteration cap. If we haven't hit OR exceeded MAX_DIST in 64 steps, give up. Prevents infinite loops in pathological cases (e.g., a ray grazing parallel to a surface, taking tiny steps forever).MAX_DIST = 20.0(or 50): "if t exceeds this, the ray is into the void, declare a miss." Sets the effective render distance.
For unit-scale scenes (sphere radius ~1, camera ~3 units back), these defaults work. If you scale your scene up 100×, scale these too.
Step 6: Why the algorithm is correct (the safety argument)
The whole algorithm rests on one invariant: at every position, the SDF tells you a SAFE step distance — guaranteed not to overshoot.
Why? Because SDF returns "distance to nearest surface." If the nearest surface is 0.5 units away, you can move 0.5 units in any direction without hitting anything. Moving along the ray is "any direction," so it's safe.
This is what makes sphere tracing different from naive ray marching with fixed steps — it adaptively scales step size by what the geometry tells you. Far from surfaces: huge leaps. Near surfaces: tiny crawl. Every step is provably safe.
The mental model in one sentence
A ray marches from the camera by repeatedly asking the SDF "how far to the nearest surface?" and stepping that far — converging fast in empty space and slow near surfaces, terminating with a hit when distance is sub-epsilon and a miss when total travel exceeds a bailout threshold.
Explain-back question
Walk me through what happens in the march loop for two specific rays in a scene with a unit sphere at origin, camera at (0, 0, 3):
- A ray that hits the sphere — where is
tafter 1 step? After 2? When doesd < 0.001trigger?- A ray that misses — what does
tdo over many iterations, and which exit condition fires?Use the actual numerical values, not abstract reasoning.
User's answer (PASS)
When we trace a ray from camera first t=0... Then a ray is shot at the direction of the sphere. You calculate d... This time it is on the sphere and <0.001 check for floats pass... If it returns -1, the ray completely missed all the primitives in the scene!
Judgment
PASS. Got the core mechanics:
- t=0 starts at camera ✓
- Ray traced toward the sphere ✓
- d shrinks as we approach ✓
- HIT_EPS check fires when on surface ✓
- Miss case identified (referenced returning -1, the conventional "no hit" sentinel) ✓
Slight mix-up: the HIT condition is d < HIT_EPS (small d), and miss is t > MAX_DIST (large t). The "-1" in his answer is a function-return convention from some implementations, not a value of d. Minor; the mental model is intact. Numerical trace would have been crisper but the algorithmic understanding is there.