Ray tracing
Computer graphics
3D rendering
Geometry
Intersection algorithms

Ray-triangle intersection

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Introduction

Ray-triangle intersection is one of the core tests in ray tracing, picking, collision queries, and geometric visibility checks. The standard practical solution is the Moller-Trumbore algorithm because it computes the hit distance and barycentric coordinates directly without first building an explicit plane equation.

What the Test Needs to Answer

Given:

  • a ray origin
  • a ray direction
  • three triangle vertices

you usually want to know:

  • does the ray hit the triangle
  • how far along the ray the hit occurs
  • where inside the triangle the hit lies

The “inside the triangle” part matters because a ray can intersect the infinite plane of the triangle without landing inside the actual triangle bounds.

The Moller-Trumbore Idea

The algorithm works by solving the ray and triangle equations together in barycentric form. Instead of testing the plane first and then doing a separate point-in-triangle test, it solves everything in one compact sequence using dot and cross products.

The outputs are commonly:

  • 't for distance along the ray'
  • 'u and v as barycentric coordinates'

A valid hit requires:

  • the determinant is not near zero
  • 'u is inside the valid range'
  • 'v is inside the valid range'
  • 'u + v does not exceed one'
  • 't is positive if you only want forward ray hits'

A Working Python Implementation

Here is a simple implementation using tuples:

python
1def subtract(a, b):
2    return (a[0] - b[0], a[1] - b[1], a[2] - b[2])
3
4
5def dot(a, b):
6    return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]
7
8
9def cross(a, b):
10    return (
11        a[1] * b[2] - a[2] * b[1],
12        a[2] * b[0] - a[0] * b[2],
13        a[0] * b[1] - a[1] * b[0],
14    )
15
16
17def ray_triangle_intersect(origin, direction, v0, v1, v2, eps=1e-9):
18    edge1 = subtract(v1, v0)
19    edge2 = subtract(v2, v0)
20
21    h = cross(direction, edge2)
22    a = dot(edge1, h)
23
24    if -eps < a < eps:
25        return None
26
27    f = 1.0 / a
28    s = subtract(origin, v0)
29    u = f * dot(s, h)
30    if u < 0.0 or u > 1.0:
31        return None
32
33    q = cross(s, edge1)
34    v = f * dot(direction, q)
35    if v < 0.0 or u + v > 1.0:
36        return None
37
38    t = f * dot(edge2, q)
39    if t > eps:
40        return t, u, v
41
42    return None
43
44
45hit = ray_triangle_intersect(
46    origin=(0.0, 0.0, 0.0),
47    direction=(0.0, 0.0, 1.0),
48    v0=(-1.0, -1.0, 5.0),
49    v1=(1.0, -1.0, 5.0),
50    v2=(0.0, 1.0, 5.0),
51)
52
53print(hit)

If the function returns None, there is no valid forward hit. Otherwise, it returns the distance t and barycentric coordinates u and v.

What the Barycentric Coordinates Mean

The barycentric coordinates tell you where the hit lies inside the triangle. They are useful for more than just inside-outside testing.

You can also use them to interpolate:

  • normals
  • texture coordinates
  • vertex colors
  • other per-vertex attributes

If the triangle vertices carry UV coordinates, for example, the barycentric weights let you compute the texture coordinate exactly at the hit point.

That is one reason Moller-Trumbore is so widely used in rendering pipelines.

Numerical Stability Notes

The eps threshold matters. Rays that are almost parallel to the triangle plane can produce determinants very close to zero. Without a tolerance, floating-point noise can cause unstable hit results.

This also means you should think carefully about:

  • back-face culling or no culling
  • whether hits at t = 0 count
  • scene scale and numeric precision

If you want to ignore back-facing triangles, you can add an orientation check instead of using a symmetric near-zero test.

The main reasons are practical:

  • it is fast
  • it avoids unnecessary intermediate geometry
  • it returns both hit existence and useful hit data
  • it fits well into acceleration structures such as BVHs

For individual triangle tests, the savings may seem small. In a ray tracer or mesh query system doing millions of tests, the efficiency matters a great deal.

Common Pitfalls

The most common pitfall is forgetting that the ray direction does not need to be normalized for the intersection test itself, but the returned t then scales with that direction vector.

Another mistake is treating a plane hit as automatically being a triangle hit. The barycentric checks are essential.

A third issue is ignoring floating-point tolerances for nearly parallel rays, which can cause flickering or unstable collision results.

Finally, developers sometimes forget to define whether back-face hits should count. That policy affects both correctness and rendering behavior.

Summary

  • The standard practical algorithm for ray-triangle intersection is Moller-Trumbore.
  • It computes hit distance and barycentric coordinates directly.
  • A valid hit requires the ray to intersect the triangle, not just the supporting plane.
  • Numerical tolerances matter for near-parallel cases.
  • Barycentric coordinates are useful for both hit testing and attribute interpolation.

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.