Just for fun I decided to explain this a bit more elaborately.

So first we define a plane and a ray, both infinite mathematical entities. A plane is defined by an offset and a normal, a ray is defined by an offset and a direction, both sets of 2 vector3’s

If we subtract the plane origin from the ray origin, we get a point on the ray in the plane’s space, as a vector.

If we dot this vector with the plane normal, we get the distance from the ray origin to the plane.

Were we to multiply the plane normal with the negative distance, we get the nearest point on the plane from the ray origin.

If we consider the ray origin, the intersection point we’re looking for and this point, we also get a triangle, for which we know two directions (ray direction and plane normal) and one length (the distance from ray origin to plane).

Because triangles are scalable, we can dot the negative plane normal with the ray direction to get the ratio between the diagonal and the known length o the previously described triangle. So if we multiply one with the calculated value we get the length of this side, if we multiply the length between the ray origin and the intersection point we get the length between the ray origin and the nearest point on the plane.

When we divide the known length by this ratio however, we get the length between the ray origin and the plane. If we multiply the ray direction with this length (white), we get the intersection point as a vector from the ray origin, so we need to add the ray origin again to get this point in world space.

This code sample was written for a Houdini node, so it’s not functional with the Vec class I once posted, though the logic works and some minor changes should make it work with any vector class.

def rayPlaneIntersect(rayorigin, in_raydirection, planeorigin, in_planenormal): ''' @returns: Vector3, intersectionPoint-rayOrigin ''' raydirection = in_raydirection.normalized() planenormal = in_planenormal.normalized() distanceToPlane = (rayorigin-planeorigin).dot(planenormal) triangleHeight = raydirection.dot(-planenormal) if not distanceToPlane: return rayorigin-planeorigin if not triangleHeight: return None #ray is parallel to plane return raydirection * distanceToPlane * (1.0/triangleHeight)