Ray–Triangle Intersection & Barycentric Coordinates

Spheres and planes are warm-ups. The real scene — every character, prop and landscape — is a mesh: thousands of triangles stitched together. So the workhorse intersection of a ray tracer is ray–triangle, and the elegant coordinate system that runs it, barycentric coordinates, doubles as the engine behind smooth shading and texture mapping. One idea, two superpowers.

Barycentric coordinates, line by line

A triangle has three corners A, B, C. Barycentric coordinates describe any point as a weighted blend of those three corners.

Step 1 — write a point as a blend of the corners. Pick three weights u, v, w and mix:

P = u\,A + v\,B + w\,C.

Step 2 — make the weights sum to one. To land on the triangle's plane (not float off it), the weights must be a true average — they sum to one:

u + v + w = 1.

With this constraint, (u,v,w) = (1,0,0) is corner A, (0,1,0) is B, (0,0,1) is C, and (\tfrac13,\tfrac13,\tfrac13) is the centroid. Each weight measures "how much of that corner" is in the mix.

Step 3 — read off "inside" from the signs. A point sits inside the triangle exactly when all three weights are non-negative. A negative weight means you've stepped past the edge opposite that corner:

P \text{ is inside } \triangle ABC \iff u \ge 0,\ v \ge 0,\ w \ge 0 \quad (\text{with } u+v+w=1).

That single sign test is the whole containment check — no angle sums, no winding loops.

Step 4 — intersect by meeting the plane, then testing the weights. To hit triangle ABC with a ray, first find where the ray crosses the triangle's plane (a single t), then compute that point's barycentric weights and check they are all \ge 0. Inside ⇒ a real hit; any negative weight ⇒ the ray passed through the plane but outside the triangle.

Step 5 — Möller–Trumbore does it in one shot. The famous Möller–Trumbore algorithm fuses those two steps: using cross and dot products of the edge vectors e_1 = B - A, e_2 = C - A and the ray, it solves directly for (t, v, w) at once — recovering u = 1 - v - w for free — and bails out the instant a weight goes negative. It never explicitly builds the plane; the barycentrics fall straight out of the linear system.

Step 6 — reuse the weights to interpolate. Here is the payoff. Each vertex carries data — a normal, a colour, a texture coordinate. The same u, v, w that proved the hit blend that data smoothly across the face:

\text{value at } P = u\,(\text{value}_A) + v\,(\text{value}_B) + w\,(\text{value}_C).

The intersection test and the shading interpolation share one set of numbers. That is why barycentrics are everywhere in graphics.

For a triangle A, B, C:

Barycentric interpolation is not a niche trick — it is how a rasteriser fills a triangle. Assign each corner a colour and blend by u, v, w across the interior and you have Gouraud shading: a single triangle washes smoothly from red at A through green at B to blue at C, every interior pixel a weighted mix of the three.

Swap "colour" for "texture coordinate (s, t)" and the same blend becomes texture mapping: the weights tell each pixel which texel to fetch, so an image stretches correctly over the face. Swap in "vertex normal" and you get the smooth normals that make a faceted mesh look round. The same three numbers, asked to carry whatever data the vertices hold — the most reused little vector in real-time rendering.