Ray/Plane intersection is a basic intersection used in game development. It can be used for several purposes in shaders, for example, to perform raytracing, which is becoming more important every day. In this post, I’m going to not only present how to calculate the intersection but also to derive the method and show GLSL code. I’m going to work in vector form, as it’s more convenient for graphics programming.

Vector equation of a ray (letters in bold are vectors):

where:

Vector equation of a plane:

where:

By inserting from the ray equation into the plane equation we get:

Now, the only unknown variable is . We isolate it:

Analysis of this equation:

Following there is a GLSL function to calculate . By inserting the value of in the ray equation we get the intersection point. The reason to not calculate the intersection point directly is that sometimes we need the distance from the ray origin to the intersection with the plane. It turns out that is this distance multiplied by the length of the ray direction vector, so we use this function with a unit length direction (or divide by the length). Also, we are usually only interested in intersections forwards from the ray origin (), so the function takes advantage and uses negatives values to indicate that such an intersection doesn’t exist.

// Parameters:
//   ray_origin: Origin of the ray.
//   ray_direction: Direction of the ray. It must be nonzero.
//   plane: plane.xyz is the normal of the plane and plane.w is the D of the
//          general plane equation. The normal must be nonzero.
// Returns:
//   >= 0 if there is an intersection and it is not behind the ray. it's
//        the t from the ray equation.
//   <  0 otherwise.
float ray_plane_intersection(vec3 ray_origin, vec3 ray_direction, vec4 plane)
{
	float denom = dot(plane.xyz, ray_direction);

	// In theory it's denom == 0, but we account for numerical precision
	// errors.
	if (abs(denom) < 1e-6)
		return -1; // No intersection

	float num = plane.w + dot(plane.xyz, ray_origin);
	return -num/denom;
}