Ray Mesh Intersection

Point-Cloud-Utils supports fast ray-mesh intersection using Intel Embree. There are two ways of performing ray-mesh queries. For one-off queries, use the functional interface, and for repeated queries on a mesh, use RayMeshIntersector

One-off Ray-Mesh Queries using the Functional Interface

You can call ray_mesh_intersection to compute the intersection between a collection of rays and a triangle mesh:

import point_cloud_utils as pcu
import numpy as np

# Generate a raster grid of Rays looking down the +Z axis
x, y = np.mgrid[-0.5:0.5:32j, -0.5:0.5:32j]
ray_d = np.stack([x.flatten(), y.flatten(), np.ones_like(x.flatten())], axis=-1)
ray_d /= np.linalg.norm(ray_d, axis=-1, keepdims=True)  # Normalize ray directions -- shape [N, 3]

# Rays originating at -Z looking down the Z-axis
ray_o = np.array([0.0, 0.15, -0.75])
ray_o = np.repeat(ray_o[None, :], ray_d.shape[0], axis=0)  # Repeat the ray origin so there is one per ray -- shape [N, 3]

fid, bc, t = pcu.ray_mesh_intersection(v.astype(ray_o.dtype), f, ray_o, ray_d)

# True only at the rays which intersected the shape



Repeated Ray-Mesh Queries using RayMeshIntersector

You can call ray_mesh_intersection to compute the intersection between a collection of rays and a triangle mesh:

import point_cloud_utils as pcu
import numpy as np

# Generate a raster grid of Rays looking down the +Z axis
x, y = np.mgrid[-0.5:0.5:32j, -0.5:0.5:32j]
ray_d = np.stack([x.flatten(), y.flatten(), np.ones_like(x.flatten())], axis=-1)
ray_d /= np.linalg.norm(ray_d, axis=-1, keepdims=True)  # Normalize ray directions -- shape [N, 3]

# Rays originating at -Z looking down the Z-axis
ray_o = np.array([0.0, 0.15, -0.75])
ray_o = np.repeat(ray_o[None, :], ray_d.shape[0], axis=0)  # Repeat the ray origin so there is one per ray -- shape [N, 3]

# Generate new rays via a random rotation
random_rotation = np.linalg.svd(np.random.randn(3, 3))[0]
ray_o2 = np.ascontiguousarray((random_rotation @ ray_o.T).T)
ray_d2 = np.ascontiguousarray((random_rotation @ ray_d.T).T)

intersector = pcu.RayMeshIntersector(v, f)

# Intersect first batch of rays
fid, bc, t = intersector.intersect_rays(ray_o, ray_d)
hit_mask = fid >= 0  # True only at the rays which intersected the shape

# Intersect second batch of rays
fid2, bc2, t2 = intersector.intersect_rays(ray_o2, ray_d2)
hit_mask2 = fid >= 0  # True only at the rays which intersected the shape

1. The index of the mesh face containing it (usually referred to as fid)
2. The barycentric coordinates of the point within that face (usually referred to as bc)
To recover vertex quantities from fid, bc pairs use the function pcu.interpolate_barycentric_coords(f, fid, bc, vertex_quantity)