warp.geometry.swept_volume_mesh#

warp.geometry.swept_volume_mesh(
meshes,
transforms,
voxel_size=None,
*,
resolution=None,
lower=None,
upper=None,
threshold=0.0,
sign_mode=SweptVolumeSignMode.WINDING_NUMBER,
device=None,
)[source]#

Extract the swept volume (motion envelope) of animated rigid meshes.

Samples the swept-volume signed-distance field with swept_volume_field() and extracts its threshold isosurface with marching cubes, returning a single triangle mesh in world coordinates that traces the union of every input mesh over every sampled pose.

The field is evaluated by brute force at the provided pose samples. At low temporal sample rates relative to mesh speeds or thicknesses, the extracted swept volume will exhibit known “stroboscopic” defects.

Parameters:
  • meshes (Sequence[warp.Mesh]) – Sequence of rest-pose warp.Mesh objects.

  • transforms (warp.array2d[warp.transform] | npt.ArrayLike) – Per-mesh, per-sample rigid poses; see swept_volume_field().

  • voxel_size (float | None) – Edge length of a grid cell in world units; see swept_volume_field().

  • resolution (tuple[int, int, int] | None) – Node counts (nx, ny, nz); see swept_volume_field().

  • lower (warp.vec3 | tuple[float, float, float] | None) – World coordinate that node (0, 0, 0) maps to. Defaults to the swept bounds padded by threshold plus roughly two cells, so the extracted level stays inside the domain. Supplying the corners makes that padding your responsibility.

  • upper (warp.vec3 | tuple[float, float, float] | None) – World coordinate that node (nx-1, ny-1, nz-1) maps to.

  • threshold (float) – Field level to extract. threshold = 0.0 traces the envelope through the sampled poses; a positive value dilates it outward. Due to grid sampling, the extracted marching cubes mesh is only guaranteed to enclose all sampled poses when threshold > 0.5 * hypot(hx, hy, hz).

  • sign_mode (SweptVolumeSignMode) – Inside/outside classification method; see SweptVolumeSignMode. SweptVolumeSignMode.NO_SIGN requires a positive threshold to result in a non-empty surface, since the field is positive everywhere.

  • device (DeviceLike | None) – Device on which to run. Defaults to the device of the first mesh.

Returns:

A tuple (vertices, indices) where vertices is a warp.array(dtype=warp.vec3) in world coordinates and indices is a flat warp.array(dtype=warp.int32) with three entries per triangle.

Return type:

tuple[wp.array[wp.vec3], wp.array[wp.int32]]

Examples

Sweep a tetrahedron one unit along x. The swept solid spans (0, 0, 0) to (2, 1, 1), and extracting at the conservative threshold guarantees the envelope encloses it.

>>> import numpy as np
>>> import warp as wp
>>> import warp.geometry as geo
>>> points = np.array([[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]])
>>> faces = [0, 2, 1, 0, 3, 2, 0, 1, 3, 1, 2, 3]
>>> tet = wp.Mesh(wp.array(points, dtype=wp.vec3), wp.array(faces, dtype=wp.int32), support_winding_number=True)
>>> xforms = np.zeros((1, 8, 7), dtype=np.float32)  # one mesh, eight poses
>>> xforms[..., 6] = 1.0  # identity quaternions
>>> xforms[0, :, 0] = np.linspace(0.0, 1.0, 8)  # translate along x
>>> voxel_size = 0.05
>>> vertices, indices = geo.swept_volume_mesh(
...     [tet], xforms, voxel_size=voxel_size, threshold=0.5 * np.sqrt(3.0) * voxel_size
... )
>>> v = vertices.numpy()
>>> bool(np.all(v.min(axis=0) <= 0.0) and np.all(v.max(axis=0) >= [2.0, 1.0, 1.0]))
True