newton.geometry.ParticleSurface#
- class newton.geometry.ParticleSurface(voxel_size, *, kernel_radius=None, threshold=0.25, smooth_lambda=0.5, anisotropic=False, anisotropy_ratio=4.0, kernel_scale=0.5, anisotropy_scale=1.0, anisotropy_min_neighbors=25, padding=2, field_smooth_iterations=0, field_smooth_radius=1, field_mode=None, redistance_iterations=0, mesh_smooth_iterations=0, mesh_smooth_lambda=1.0, device=None, anisotropy_strength=1.0, surface_method='density', particle_sdf_radius_scale=1.0, particle_sdf_band=2.0, max_grid_cells=None, world_count=1, anisotropy_binning=False)[source]#
Bases:
objectReusable context for extracting a triangle mesh from particle data.
Uses the Yu & Turk (2010) anisotropic kernel method: per-particle Weighted PCA determines oriented ellipsoidal kernels that produce a smooth scalar field whose isosurface tightly wraps the particles.
- Parameters:
voxel_size (float) – Edge length of each grid voxel [m].
max_grid_cells (int | None) – Maximum active sparse-grid cell count across all worlds. When set, extraction uses preallocated, graph-capturable buffers. When
None, each extraction uses tight sparse field and mesh allocations. Rebuildable topology-node capacities assume spatially coherent surface bands; highly scattered fields can exhaust them before reaching this cell count.world_count (int) – Number of independent particle worlds to extract.
kernel_radius (float | None) – Search radius for neighbor queries [m]. Defaults to
3 * voxel_size.threshold (float) – Isosurface level for marching cubes. The scalar field is approximately 1.0 inside dense particle regions. Defaults to 0.25.
smooth_lambda (float) – Blending factor for position smoothing [0, 1]. Higher values produce smoother surfaces. Defaults to 0.5.
anisotropic (bool) – Enable per-particle WPCA anisotropic kernels. When
False(default), all particles use isotropic kernels.anisotropy_ratio (float) – Maximum anisotropic kernel axis ratio. Higher values allow flatter ellipsoids.
kernel_scale (float) – Kernel radius multiplier relative to
kernel_radius. This sets the isotropic kernel radius and the geometric-mean radius of anisotropic kernels.anisotropy_scale (float) – Relative multiplier for anisotropic kernel radii. Values greater than 1 widen anisotropic kernels without changing the isotropic fallback scale. Defaults to 1.
anisotropy_min_neighbors (int) – Minimum number of other particles required for anisotropic kernels. Sparser particles use isotropic kernels.
anisotropy_binning (bool) – Share one WPCA kernel among particles in each spatial bin. Bins are half the kernel radius wide. This reduces neighbor-query cost at the expense of spatial resolution.
anisotropy_strength (float) – Blend from isotropic kernels to anisotropic kernels [0, 1]. Lower values preserve more normal support from boundary particles back into the interior.
surface_method (Literal['density', 'particle_sdf']) – Surface reconstruction method.
"density"uses anisotropic density splatting."particle_sdf"directly unions per-particle anisotropic ellipsoid SDFs and stores an SDF field.particle_sdf_radius_scale (float) – Radius multiplier for
surface_method="particle_sdf".particle_sdf_band (float) – Narrow-band half-width in normalized ellipsoid coordinates for
surface_method="particle_sdf". Must be at least 1 so the band contains the zero level set.padding (int) – Extra voxels added around the particle bounding box.
field_smooth_iterations (int) – Number of separable Gaussian blur passes applied to the scalar field before marching cubes. Defaults to 0.
field_smooth_radius (int) – Half-width of the Gaussian blur in voxels. Defaults to 1.
field_mode (Literal['density', 'sdf'] | None) – Field representation retained after extraction.
"density"keeps the scalar density field used by marching cubes."sdf"converts it to a signed distance approximation with negative values inside the particle surface. Defaults to"sdf"forsurface_method="particle_sdf"and"density"otherwise.redistance_iterations (int) – Number of Eikonal redistancing iterations applied when
field_mode="sdf". Set to 0 to skip.mesh_smooth_iterations (int) – Number of Laplacian smoothing passes applied to the extracted mesh. Set to 0 to disable.
mesh_smooth_lambda (float) – Laplacian step size [0, 1].
device (wp.DeviceLike) – Warp device for computation.
- class ExtractionMesh(vertices, indices, normals, counts, active_particle_count, vertex_world_offsets, index_world_offsets, *, exact)#
Bases:
objectParticle surface mesh and its device-resident logical counts.
Buffers are exact-sized when
max_grid_cellsisNoneand preallocated otherwise.Vertices and indices from each world occupy contiguous ranges. Their offsets are stored in
vertex_world_offsetsandindex_world_offsets, each with shape(world_count + 1,). Worldioccupies the half-open range[offsets[i], offsets[i + 1]).- __init__(vertices, indices, normals, counts, active_particle_count, vertex_world_offsets, index_world_offsets, *, exact)#
- to_arrays()#
Return one exact-length mesh containing every world as a disconnected component.
- class SparseField(volume, voxel_data, background, world_index_offsets, per_world_status)#
Bases:
objectSparse scalar field stored as an index grid and per-voxel data.
Pass
volume,voxel_data, andbackgroundtowarp.volume_sample_index()to sample the field. The voxel-data buffer may include reserved capacity; the volume maps index-space coordinates to the corresponding live entries.Multiple worlds share one packed index grid. To sample world
iat world-space positionposition, passposition / particle_surface.voxel_size + wp.vec3(world_index_offsets[i])as theuvwargument towarp.volume_sample_index(). The offset is zero for a single-world surface.Reacquire
ParticleSurface.sparse_fieldafter updating or extracting the field because its underlying storage may be replaced. When using preallocated storage, inspectper_world_statusbefore consuming results; a nonzero entry means the sparse field may be incomplete because its capacity was exceeded.- __init__(volume, voxel_data, background, world_index_offsets, per_world_status)#
- per_world_status: wp.array[wp.int32]#
Extraction status per world, shape
(world_count,).Zero indicates success; a nonzero value indicates sparse-grid overflow.
- world_index_offsets: wp.array[wp.vec3i]#
Offset of each world’s coordinates in the packed index grid [voxels], shape
(world_count,).
- __init__(voxel_size, *, kernel_radius=None, threshold=0.25, smooth_lambda=0.5, anisotropic=False, anisotropy_ratio=4.0, kernel_scale=0.5, anisotropy_scale=1.0, anisotropy_min_neighbors=25, padding=2, field_smooth_iterations=0, field_smooth_radius=1, field_mode=None, redistance_iterations=0, mesh_smooth_iterations=0, mesh_smooth_lambda=1.0, device=None, anisotropy_strength=1.0, surface_method='density', particle_sdf_radius_scale=1.0, particle_sdf_band=2.0, max_grid_cells=None, world_count=1, anisotropy_binning=False)#
- extract(positions, radii, *, compute_normals=True, particle_flags=None, particle_world=None)#
Extract a triangle mesh from particle positions.
When
max_grid_cellsis set, this method performs no host synchronization and can be captured in a CUDA graph. Otherwise it allocates exact-size field and mesh arrays.- Parameters:
positions (wp.array[wp.vec3f]) – Particle positions [m], shape
(N,), dtypewp.vec3.radii (wp.array[wp.float32]) – Per-particle radii [m], shape
(N,), dtypewp.float32.compute_normals (bool) – Whether to compute per-vertex normals.
particle_flags (wp.array[wp.int32] | None) – Optional per-particle flags. Particles without
ACTIVEare skipped.particle_world (wp.array[wp.int32] | None) – Optional world index per particle. Particles with negative or out-of-range world indices are skipped.
- Returns:
Mesh buffers and device-resident logical counts.
- Return type:
- redistance(iterations)#
Apply Eikonal redistancing to the current SDF field.
- Parameters:
iterations (int) – Number of redistancing iterations.
- resurface(*, compute_normals=True)#
Re-run marching cubes on the current field.
- Parameters:
compute_normals (bool) – Whether to compute per-vertex normals.
- Returns:
Mesh buffers and device-resident logical counts.
- Return type:
- update_field(positions, radii, *, particle_flags=None, particle_world=None)#
Update the scalar field without extracting a mesh.
- Parameters:
positions (wp.array[wp.vec3f]) – Particle positions [m], shape
(N,), dtypewp.vec3.radii (wp.array[wp.float32]) – Per-particle radii [m], shape
(N,), dtypewp.float32.particle_flags (wp.array[wp.int32] | None) – Optional per-particle flags. Particles without
ACTIVEare skipped.particle_world (wp.array[wp.int32] | None) – Optional world index per particle. Particles with negative or out-of-range world indices are skipped.
- Returns:
The sparse index grid and its per-voxel data, or
Nonewhen no sparse field topology was produced.- Return type:
SparseField | None
- property sparse_field: SparseField | None#
Current sparse scalar field, or
Nonebefore field extraction.