warp.geometry.sparse_marching_cubes#
- warp.geometry.sparse_marching_cubes(
- field,
- nx,
- ny,
- nz,
- *,
- lower=None,
- upper=None,
- threshold=0.0,
- lipschitz_bound=1.0,
- device=None,
- return_stats=False,
Extract an isosurface from an implicit function using a Lipschitz octree.
Rather than sampling a dense grid, this routine builds a sparse octree that provably brackets the level set of a 1-Lipschitz implicit function (such as a signed distance function) and runs marching cubes only on the near-surface cells, at a cost that scales with the surface area rather than the volume.
The grid is specified exactly as for
warp.geometry.IsoSurfaceMarchingCubes.extract():nx, ny, nzgrid nodes over the box[lower, upper], which may be anisotropic. Calling this function andextract()with the samenx, ny, nzand bounds produces the same surface.Both the pruning pass (at cell centers) and the extraction pass (at cell corners) query
fieldin batches, never one point at a time. Iffieldis implemented entirely with Warp (a kernel launch, with no host round trip), the whole pipeline stays on the GPU; seewarp/examples/geometry/example_sparse_marching_cubes.pyfor a mesh-query implicit function that does this. A callable that wraps a host library (NumPy, PyTorch, …) is equally valid – it just pays a device/host sync on every call, since the values it returns must still land back on the query points’ device.This function supports backward-mode automatic differentiation: if
field’s output array hasrequires_grad=True(the caller’s responsibility to allocate) and the call is wrapped in awarp.Tape(), gradient flows from the outputvertsback through the corner valuesfieldproduced. Cell selection (lipschitz_octree()) is not differentiated – it is a discrete, threshold-based search – and does not print tape warnings either.- Parameters:
field (Callable[[array], array]) – The implicit function, as a batched callable with the contract
evaluate(points: warp.array[warp.vec3]) -> warp.array[warp.float32], returning the signed distance (or any 1-Lipschitz field whosethresholdlevel set is the surface) at each query point. A bare single-point@warp.funcis not accepted directly – wrap it in a kernel that evaluates it over the batch (see above), which keeps evaluation on the GPU instead of hiding a per-point kernel launch behind what looks like a single call.nx (int) – Number of grid nodes in the x-direction.
ny (int) – Number of grid nodes in the y-direction.
nz (int) – Number of grid nodes in the z-direction.
lower (vec3f | tuple[float, float, float] | None) – The 3D coordinate that the grid’s corner at index
(0, 0, 0)maps to. Defaults to(0.0, 0.0, 0.0)ifNone. Anything outside[lower, upper]is never visited, so parts of the level set that leave it are simply missing from the output, leaving the mesh open where it exits.upper (vec3f | tuple[float, float, float] | None) – The 3D coordinate that the grid’s corner at index
(nx - 1, ny - 1, nz - 1)maps to. Defaults to align with the grid’s maximal indices ifNone.threshold (float) – The isovalue defining the surface.
lipschitz_bound (float) – An upper bound on the Lipschitz constant of
field. Use1.0for a true signed distance function. Larger values widen the retained band, trading speed for a stronger guarantee when the field varies faster than unit rate.device (Device | str | None) – The Warp device to run on. Defaults to the current device.
return_stats (bool) – If
True, also return a dictionary of diagnostics (leaf-cell count, unique-corner count, implicit-function evaluation count, culled-cell count) useful for benchmarking against a dense grid.
- Returns:
A tuple
(vertices, indices)whereverticesis awarp.array[warp.vec3]andindicesis a flatwarp.array[warp.int32]with three consecutive entries per triangle. Ifreturn_statsisTrue, returns(vertices, indices, stats).- Raises:
ValueError – If
nx,ny, ornzis less than 2, orlipschitz_boundis negative.TypeError – If
fieldis not callable (including a bare single-point@warp.func, which must be wrapped in a batched kernel first).
- Return type: