Ray–Sphere Intersection

We have a ray P(t) = O + tD and a ball floating in the scene. The first real raytracing question is the one a player would ask: does the line of sight hit the ball, and if so, where? A sphere is the friendliest shape to test because its definition is one clean equation — and substituting the ray into it collapses the whole problem to a quadratic you already know how to solve.

From sphere to quadratic, line by line

A sphere with centre C and radius r is every point exactly r away from C. Squaring the distance (to dodge a square root) gives the implicit equation:

\lVert P - C\rVert^2 = r^2.

Step 1 — substitute the ray. A point is on the sphere when it satisfies this; a point is on the ray when it equals O + tD. Asking for both at once means plugging the ray in for P:

\lVert (O + tD) - C\rVert^2 = r^2.

Step 2 — name the offset. Let M = O - C, the vector from the sphere's centre to the ray's origin. The bracket becomes tD + M:

\lVert tD + M\rVert^2 = r^2.

Step 3 — expand the squared length with the dot product. For any vector, \lVert v\rVert^2 = v\cdot v, and the dot product distributes just like ordinary multiplication. So \lVert tD + M\rVert^2 = (tD + M)\cdot(tD + M) expands to:

(D\cdot D)\,t^2 + 2\,(D\cdot M)\,t + (M\cdot M) = r^2.

Step 4 — move r^2 over and read off a quadratic in t. Everything except t is a known number, so this is at^2 + bt + c = 0 in disguise:

\underbrace{(D\cdot D)}_{a}\,t^2 + \underbrace{2\,(D\cdot M)}_{b}\,t + \underbrace{(\lVert M\rVert^2 - r^2)}_{c} = 0.

(If the direction is a unit vector then a = D\cdot D = 1, tidying it further.) Solve it with the quadratic formula:

t = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}.

Step 5 — let the discriminant decide whether you hit. The term under the root, \Delta = b^2 - 4ac, is the entire hit test, and its sign reads off geometrically:

\Delta < 0\ (\text{miss}), \qquad \Delta = 0\ (\text{tangent — a graze}), \qquad \Delta > 0\ (\text{two hits}).

A negative discriminant means no real t — the ray sails past the ball. Zero means the ray just kisses the surface at one point. Positive means it punches clean through: the smaller root is where it enters, the larger where it exits.

Step 6 — take the nearest hit in front of you. Of the (up to two) roots, we want the closest surface the camera can actually see: the smallest t > 0. A root with t \le 0 is behind the origin (or the origin sits inside the ball) and is rejected. Plug that t back into the ray to get the hit point itself:

P_{\text{hit}} = O + t\,D. For a ray P(t) = O + tD and a sphere \lVert P - C\rVert^2 = r^2, write M = O - C. Then:

The quadratic is bulletproof, but there's a slicker route that skips the algebra when the direction is a unit vector. Drop the centre C onto the ray by projecting: the parameter of the closest approach is

t_{ca} = (C - O)\cdot D,

the foot of the perpendicular from C to the ray. The squared distance from C to the ray at that point is, by Pythagoras,

d^2 = \lVert C - O\rVert^2 - t_{ca}^2.

If d^2 > r^2 the ray misses entirely — done, no square root, no formula. Otherwise the chord half-length is h = \sqrt{r^2 - d^2}, and the two hits sit symmetrically about the closest approach at t = t_{ca} \pm h. It is the very same answer the discriminant gives — \Delta > 0 is exactly d^2 < r^2 — just reorganised so the cheap rejection test happens first. Engines love this: most rays miss most spheres, and the early-out saves the square root on the common case.