differt.rt.rays_intersect_triangles#
- rays_intersect_triangles(ray_origins, ray_directions, triangle_vertices, *, epsilon=None, smoothing_factor=None)[source]#
Return whether rays intersect corresponding triangles using the Möller-Trumbore algorithm.
The current implementation closely follows the C++ code from Wikipedia.
- Parameters:
ray_origins (
Float[ArrayLike, '*#batch 3']) – An array of origin vertices.ray_directions (
Float[ArrayLike, '*#batch 3']) – An array of ray directions. The ray ends should be equal toray_origins + ray_directions.triangle_vertices (
Float[ArrayLike, '*#batch 3 3']) – An array of triangle vertices.epsilon (
Float[ArrayLike, '']|None) –A small tolerance threshold that allows rays to hit the triangles slightly outside the actual area. A positive value virtually increases the size of the triangles, a negative value will have the opposite effect.
Such a tolerance is especially useful when rays are hitting triangle edges, a very common case if geometries are planes split into multiple triangles.
If not specified, the default is ten times the epsilon value of the currently used floating point dtype.
smoothing_factor (
Float[ArrayLike, '']|None) –If set, hard conditions are replaced with smoothed ones, as described in [2], and this argument parameterizes the slope of the smoothing function. The second output value is now a real value between 0 (
False) and 1 (True).For more details, refer to Smoothing Discontinuities for Fully Differentiable Ray Tracing.
- Return type:
tuple[Float[Array, '*batch'],Bool[Array, '*batch']|Float[Array, '*batch']]- Returns:
For each ray, return the scale factor of
ray_directionsfor the vector to reach the corresponding triangle, and whether the intersection actually lies inside the triangle.
Examples
The following example shows how to identify triangles that are intersected by rays.
>>> import equinox as eqx >>> from differt.geometry import fibonacci_lattice >>> from differt.plotting import draw_rays >>> from differt.rt import ( ... rays_intersect_triangles, ... ) >>> from differt.scene import ( ... get_sionna_scene, ... download_sionna_scenes, ... ) >>> from differt.scene import TriangleScene >>> >>> download_sionna_scenes() >>> file = get_sionna_scene("simple_street_canyon") >>> scene = TriangleScene.load_xml(file) >>> scene = eqx.tree_at( ... lambda s: s.transmitters, scene, jnp.array([-33, 0, 32.0]) ... ) >>> ray_origins, ray_directions = jnp.broadcast_arrays( ... scene.transmitters, fibonacci_lattice(25) ... ) >>> # [num_rays=25 num_triangles] >>> t, hit = rays_intersect_triangles( ... ray_origins[:, None, :], ... ray_directions[:, None, :], ... scene.mesh.triangle_vertices, ... ) >>> rays_hit = hit.any(axis=1) # True if rays hit any triangle >>> triangles_hit = hit.any(axis=0) # True if triangles hit by any ray >>> ray_directions *= jnp.max( ... t, axis=1, keepdims=True, initial=1.0, where=hit ... ) # Scale rays length before plotting >>> fig = draw_rays( # We only plot rays hitting at least one triangle ... ray_origins[rays_hit, :], ... ray_directions[rays_hit, :], ... backend="plotly", ... color="red", ... showlegend=False, ... ) >>> visible_color = jnp.array([0.2, 0.2, 0.2]) >>> scene = eqx.tree_at( ... lambda s: s.mesh.face_colors, ... scene, ... scene.mesh.face_colors.at[triangles_hit, :].set(visible_color), ... ) >>> fig = scene.plot(backend="plotly", figure=fig, showlegend=False) >>> fig