Möller–Trumbore intersection algorithm

Möller–Trumbore intersection algorithm
The Möller–Trumbore ray-triangle intersection algorithm, named after its inventors Tomas Möller and Ben Trumbore, is a fast method for calculating the intersection of a ray and a triangle in three dimensions without needing precomputation of the plane equation of the plane containing the triangle. Among other uses, it can be used in computer graphics to implement ray tracing computations involving triangle meshes.
Calculation
Definitions
The ray is defined by an origin point and a direction vector .
Every point on the ray can be expressed by , where the parameter ranges from zero to infinity.
The triangle is defined by three vertices, named .
The plane that the triangle is on, which is needed to calculate the ray-triangle intersection, is defined by a point on the plane, such as , and a vector that is orthogonal to every point on that plane, such as the cross product between the vector from to and the vector from to :
, where , and and are any points on the plane.
Check if the ray is parallel to the triangle
First, find out if the ray intersects with the plane that the triangle is on, and if it does, find the coordinates of that intersection. The only way that the ray will not intersect the plane is if the ray's direction vector is parallel to the plane. When this happens, the dot product between the ray's direction vector and the plane's normal vector will be zero. Otherwise, the ray does intersect the plane somewhere, but not necessarily within the triangle.
Check if the ray-plane intersection lies outside the triangle
Using barycentric coordinates, any point on the triangle can be expressed as a convex combination of the triangle's vertices:
The coefficients must be non-negative and sum to 1, so w can be replaced with :
, where is any point on the plane.
Observe that and are vectors on the edge of the triangle, and together, they span a plane (which goes through the origin). Each point on that plane can be written as and can be translated by to "move" that point onto the plane that the triangle is on.
To find and for a particular intersection, set the ray expression equal to the plane expression, and put the variables on one side and the constants on the other.
This is a system of linear equations with three equations (one each for , ) and three unknowns (and ), and can be represented as a matrix-vector multiplication.
This equation will always have a solution when the matrix has three linearly independent column vectors in and is thus invertible. This happens if and only if the triangle vertices aren't collinear and the ray isn't parallel to the plane.
The algorithm can use Cramer's Rule to find the and values for an intersection, and if it lies within the triangle, the exact coordinates of the intersection can be found by plugging in to the ray's equation.
C++ implementation
The following is an implementation of the algorithm in C++:
bool RayIntersectsTriangle(Vector3D rayOrigin,
Vector3D rayVector,
Triangle* inTriangle,
Vector3D& outIntersectionPoint)
{
const float EPSILON = 0.0000001;
Vector3D vertex0 = inTriangle->vertex0;
Vector3D vertex1 = inTriangle->vertex1;
Vector3D vertex2 = inTriangle->vertex2;
Vector3D edge1, edge2, h, s, q;
float a, f, u, v;
edge1 = vertex1 - vertex0;
edge2 = vertex2 - vertex0;
h = rayVector.crossProduct(edge2);
a = edge1.dotProduct(h);
if (a > -EPSILON && a < EPSILON)
return false; // This ray is parallel to this triangle.
f = 1.0 / a;
s = rayOrigin - vertex0;
u = f * s.dotProduct(h);
if (u < 0.0 || u > 1.0)
return false;
q = s.crossProduct(edge1);
v = f * rayVector.dotProduct(q);
if (v < 0.0 || u + v > 1.0)
return false;
// At this stage we can compute t to find out where the intersection point is on the line.
float t = f * edge2.dotProduct(q);
if (t > EPSILON) // ray intersection
{
outIntersectionPoint = rayOrigin + rayVector * t;
return true;
}
else // This means that there is a line intersection but not a ray intersection.
return false;
}
Java implementation
The following is an implementation of the algorithm in Java using javax.vecmath from Java 3D API:
public class MollerTrumbore {
private static final double EPSILON = 0.0000001;
public static boolean rayIntersectsTriangle(Point3d rayOrigin,
Vector3d rayVector,
Triangle inTriangle,
Point3d outIntersectionPoint) {
Point3d vertex0 = inTriangle.getVertex0();
Point3d vertex1 = inTriangle.getVertex1();
Point3d vertex2 = inTriangle.getVertex2();
Vector3d edge1 = new Vector3d();
Vector3d edge2 = new Vector3d();
Vector3d h = new Vector3d();
Vector3d s = new Vector3d();
Vector3d q = new Vector3d();
double a, f, u, v;
edge1.sub(vertex1, vertex0);
edge2.sub(vertex2, vertex0);
h.cross(rayVector, edge2);
a = edge1.dot(h);
if (a > -EPSILON && a < EPSILON) {
return false; // This ray is parallel to this triangle.
}
f = 1.0 / a;
s.sub(rayOrigin, vertex0);
u = f * (s.dot(h));
if (u < 0.0 || u > 1.0) {
return false;
}
q.cross(s, edge1);
v = f * rayVector.dot(q);
if (v < 0.0 || u + v > 1.0) {
return false;
}
// At this stage we can compute t to find out where the intersection point is on the line.
double t = f * edge2.dot(q);
if (t > EPSILON) // ray intersection
{
outIntersectionPoint.set(0.0, 0.0, 0.0);
outIntersectionPoint.scaleAdd(t, rayVector, rayOrigin);
return true;
} else // This means that there is a line intersection but not a ray intersection.
{
return false;
}
}
}
See also
Badouel intersection algorithm
MATLAB version of this algorithm (highly vectorized)
Baldwin-Weber ray-triangle intersection algorithm
Schlick–Subrenat algorithm for ray-quadrilateral intersection
Links
Fast Minimum Storage Ray-Triangle Intersection
Optimizations on the basic algorithm by Möller & Trumbore, code from journal of graphics tools
Ray-Tracing: Rendering a Triangle
References
Geometric algorithms
Geometric intersection