The baseline sphere produces roots four and six, with forward hit four. A nearer sphere at z minus three with radius one-half wins at 2.5. The inspector calculates roots, reports the chosen hit, and attempts a real WebGL2 result swatch when available; the numeric ledger remains usable when GPU support is unavailable.

Work through the example
Select Nearer sphere to compare F at t four with N at t 2.5. Select Behind sphere to see roots minus six and minus four: real intersections, but no positive hit. An offset x of two misses F. Invalid nonfinite offsets are rejected rather than leaving the previous hit accepted.
For every object, retain both roots and the forward-filter result before choosing across objects. Real roots can still lie entirely behind the origin. These small cases use unit direction and strict positive t; they do not define a tolerance for tangencies or surface starts. The GPU swatch displays the CPU decision, so independent shader intersection/readback remains a separate implementation check.
Define a ray parameter before calling it distance
Use:
p(t) = o + td, where o is the origin and d is a nonzero direction.
Here t is a ray parameter, not elapsed time. The authored ray directions are unit length, so their positive t values also equal distance in the model's coordinate units. For a nonunit direction, distance would be t times the direction's length; do not label t alone as world distance.
For sphere center s and positive radius r, substitute the ray into the sphere equation:
a = d·d
b = 2d·(o − s)
c = (o − s)·(o − s) − r²
Δ = b² − 4ac
For real roots, the formula is t = (−b ± √Δ)/(2a). UMBC's teaching note gives this vector/dot-product derivation and the discriminant distinction. Our coordinates and test cases are original. UMBC's ray–sphere derivation.
The helper contract requires finite vectors, positive finite radius, and nonzero d. A zero direction makes a zero quadratic coefficient and is not a valid ray input here.
Work the front-sphere case
Sphere F has center (0,0,−5) and radius 1. Ray R1 starts at o = (0,0,0) with d = (0,0,−1).
Then:
a = 1, b = −10, c = 24, Δ = 4.
The roots are:
(10 − 2)/2 = 4, and (10 + 2)/2 = 6.
Both are forward under this fixture's strict t > 0 rule. Choose 4, the first accepted surface along the ray. The expected hit point is (0,0,−4).
PBRT's introductory ray-intersection discussion describes selecting the closest intersection and the smallest positive root. The packet uses that limited concept; it does not implement PBRT's materials, lighting, or image formation. PBRT's closest-intersection discussion.
Separate an offset miss, an inside hit and a behind-only result
Keep sphere F unchanged for R2 and R3:
| Case | Ray origin / direction | Coefficients | Expected outcome |
|---|---|---|---|
| R2 | (2,0,0) / (0,0,−1) | a=1, b=−10, c=28, Δ=−12 | No real roots; miss |
| R3 | (0,0,−5) / (0,0,−1) | a=1, b=0, c=−1, Δ=4 | Roots −1,+1; choose +1 |
R3 starts at F's center. Its negative root is behind the origin; its positive root reaches the forward surface at (0,0,−6). Do not discard the positive exit merely because the origin lies inside the sphere.
For R4, use sphere B centered at (0,0,+5) with radius 1, and the original origin/direction from R1.
Now a=1, b=10, c=24, Δ=4, with roots −6 and −4. They are real but neither satisfies t > 0. The expected forward result is a miss.
A root's existence and a forward hit are separate checks. The discriminant alone cannot distinguish F's front hit from B's behind-only case.
Recreate this example
Build one self-contained responsive HTML example titled “WebGL ray tracing: inspect the forward root” for readers completing the stated task. Return the complete HTML with embedded CSS and JavaScript. Use no remote fonts, libraries, images, requests, account connections, or saved-state claims.
Evaluate a=dot(d,d), b=2*dot(d,o-s), c=dot(o-s,o-s)-r², the discriminant and both roots; accept only t>0. Start o=(0,0,0), d=(0,0,-1), sphere F center=(0,0,-5), radius=1: roots 4,6 and hit 4. Nearer sphere adds N center=(0,0,-3), radius=0.5: hit 2.5. Behind sphere at (0,0,5) has no forward hit. Origin x=2 misses; reject missing, nonfinite or out-of-range x outside [-1000,1000]. On input edits, retire the result, clear roots and hide the swatch. Validation failure also hides it. Show per-object roots and the closest accepted hit after calculation. Attempt a WebGL2 fragment swatch using the CPU hit uniform; label it display only with a truthful no-context fallback. No photorealistic claim.
Use a geometric hit inspector with a CPU numeric ledger and optional real WebGL2 result swatch design with a compact header. Keep the actual sample data, controls, and useful default result visible early on a 360px-wide screen. Use readable text at least 16px, generous paragraph spacing, strong contrast, semantic labels, visible keyboard focus, and wrapping source blocks. Stack records on narrow screens rather than forcing a wide table.
Wire each action to an explicit type=button click handler using element selectors; the host permits scripts but blocks form submission. Update the visible result when the described action occurs. Show specific error feedback for invalid or missing input and clear stale feedback after dependent inputs change. Use plain text when displaying user values.
The analytic CPU inspector and optional GPU display are not a photorealistic renderer or verified GPU numeric readback. Keep the source fixture and worked teacher or developer example distinct from actual user records. Include the domain-specific explanation and next check beside the result. Provide no fake download, send, deployment, approval, or persistence button. Everything operates locally for the current page session.
Review the prepared copy in NOS
Use the numeric ledger to review a shader implementation’s candidate selection and precision policy. An HTML derivation can be rendered in NOS, where eligible static geometric explanations can be revised visually. Keep actual GPU compile, uniform and numeric readback evidence with the native shader tests.