API Reference¶
Functions¶
- isoext.marching_cubes(grid: isoext.isoext_ext.Grid, level: float = 0.0, method: str = 'nagae') tuple¶
Extract an iso-surface from a grid using the Marching Cubes algorithm.
- Parameters:
grid – The input grid (UniformGrid or SparseGrid) containing scalar values.
level – The iso-value at which to extract the surface. Default is 0.0.
method – The marching cubes variant to use. Options are ‘nagae’ (default) or ‘lorensen’.
- Returns:
A tuple (vertices, faces) where vertices is an (N, 3) float32 tensor of vertex positions and faces is an (M, 3) int32 tensor of triangle indices.
- isoext.dual_contouring(grid: isoext.isoext_ext.Grid, level: float = 0.0, intersection: isoext.isoext_ext.Intersection | None = None, reg: float = 0.009999999776482582, svd_tol: float = 9.999999974752427e-07) tuple¶
Extract an iso-surface using the Dual Contouring algorithm.
Dual Contouring produces meshes with better-placed vertices than Marching Cubes, especially for sharp features. It solves a QEF (Quadric Error Function) per cell to find optimal vertex positions.
- Parameters:
grid – The input grid containing scalar values.
level – The iso-value. Default is 0.0.
intersection – Optional Intersection data from get_intersection(). If not provided, intersections are computed automatically. If provided but normals not set, normals are computed automatically.
reg – Regularization weight for the QEF solver. Default is 0.01.
svd_tol – SVD tolerance for the QEF solver. Default is 1e-6.
- Returns:
A tuple (vertices, faces) where vertices is an (N, 3) float32 tensor and faces is an (M, 3) int32 tensor of triangle indices.
- isoext.get_intersection(grid: isoext.isoext_ext.Grid, level: float = 0.0, compute_normals: bool = False) isoext.isoext_ext.Intersection¶
Compute edge-surface intersections for dual contouring.
Finds where grid edges cross the iso-surface and computes intersection points using linear interpolation.
- Parameters:
grid – The input grid containing scalar values.
level – The iso-value. Default is 0.0.
compute_normals – If True, compute normals from grid values. Default is False.
- Returns:
An Intersection object containing points (and normals if compute_normals=True).
- isoext.make_grid(aabb, res, device='cuda')¶
Create a uniform grid from an axis-aligned bounding box.
- Parameters:
aabb (list[float]) – Axis-aligned bounding box as [x_min, y_min, z_min, x_max, y_max, z_max]
res (int | list[int]) – Resolution, either a single int or list of 3 ints for [x_res, y_res, z_res]
device (str) – Device to create the grid on (default: “cuda”)
- Returns:
Grid tensor with shape (x_res, y_res, z_res, 3)
- Return type:
Tensor
- isoext.write_obj(obj_path, v, f)¶
Write vertices and faces to an OBJ file.
- Parameters:
obj_path (str) – Path to the output OBJ file
v (Tensor) – Tensor of vertices with shape (N, 3)
f (Tensor) – Tensor of face indices with shape (M, 3)
- Return type:
None
Viewer¶
Interactive visualization built on viser.
Interactive mesh viewing and scene export built on viser.
Typical use:
import isoext
from isoext import viewer
v, f = isoext.marching_cubes(grid)
server = viewer.show(v, f) # open an interactive viewer in the browser
viewer.embed(v, f) # inline scene for (statically hosted) notebooks
- isoext.viewer.add_mesh(server, vertices, faces, *, name='/mesh', color=(0.71, 0.8, 1.0), flat_shading=False, wireframe=False)¶
Add a mesh from isoext output tensors to a viser scene.
- Parameters:
server – A viser.ViserServer instance.
vertices (Tensor) – (N, 3) tensor of vertex positions.
faces (Tensor) – (M, 3) tensor of triangle indices.
name (str) – Scene tree name of the mesh.
color – RGB tuple with components in [0, 1], or a color name.
flat_shading (bool) – Shade each triangle with a constant normal.
wireframe (bool) – Render the mesh as a wireframe.
- Returns:
The viser mesh handle.
- isoext.viewer.show(vertices, faces, *, port=8080, **mesh_kwargs)¶
Open an interactive viewer serving the given mesh.
The server keeps running until it is stopped or the process exits; the printed URL can be opened in any browser.
- Parameters:
vertices (Tensor) – (N, 3) tensor of vertex positions.
faces (Tensor) – (M, 3) tensor of triangle indices.
port (int) – Port to serve on (the next free port is used if taken).
**mesh_kwargs – Forwarded to add_mesh.
- Returns:
The running viser.ViserServer; call .stop() to shut it down.
- isoext.viewer.serialize_scene(vertices, faces, **mesh_kwargs)¶
Serialize a scene containing the given mesh to .viser bytes.
The bytes can be written to a
.viserfile and played back offline by viser’s static client, e.g. embedded in a web page. See save_scene and embed for convenience wrappers.- Parameters:
vertices (Tensor)
faces (Tensor)
- Return type:
bytes
- isoext.viewer.save_scene(path, vertices, faces, **mesh_kwargs)¶
Serialize a scene with the given mesh and write it to a .viser file.
- Parameters:
vertices (Tensor)
faces (Tensor)
- Return type:
None
- isoext.viewer.copy_client(directory)¶
Copy viser’s single-file static web client into a directory.
The client is a self-contained index.html that plays back .viser scene files passed via its
?playbackPath=URL parameter. The copy is refreshed whenever the installed viser ships a different build.- Returns:
The path of the copied index.html.
- Return type:
Path
- isoext.viewer.embed(vertices, faces, *, root='_static', height=420, **mesh_kwargs)¶
Display a mesh as a self-contained interactive scene in a notebook.
Unlike show, which starts a live server, this writes static assets – the viser client to root/viser/ and the serialized scene to root/scenes/ – and returns an IFrame referencing them with relative URLs. Rendered notebooks therefore stay interactive when hosted statically, for example on documentation pages.
- Parameters:
vertices (Tensor) – (N, 3) tensor of vertex positions.
faces (Tensor) – (M, 3) tensor of triangle indices.
root – Directory for the static assets, relative to the notebook.
height (int) – Height of the embedded viewer in pixels.
**mesh_kwargs – Forwarded to add_mesh.
- Returns:
An IPython IFrame displaying the scene.
Classes¶
UniformGrid¶
- class isoext.UniformGrid(shape, aabb_min=[-1, -1, -1], aabb_max=[1, 1, 1], default_value=float_max)¶
A dense uniform grid for storing scalar values.
The grid divides a 3D axis-aligned bounding box into a regular lattice of cells. Each cell has 8 corner points where scalar values are stored.
- Parameters:
shape (Sequence[int]) – The number of cells in each dimension (x, y, z).
aabb_min (Sequence[float]) – The minimum corner of the bounding box.
aabb_max (Sequence[float]) – The maximum corner of the bounding box.
default_value (float) – Initial scalar value for all points.
- UniformGrid.get_points(self) torch.Tensor[dtype=float32, order='C', device='cuda']¶
Return the 3D coordinates of all grid points as a (X, Y, Z, 3) float32 tensor.
- UniformGrid.get_values(self) torch.Tensor[dtype=float32, order='C', device='cuda']¶
Return the scalar values as a (X, Y, Z) float32 tensor.
- UniformGrid.set_values(self, new_values: torch.Tensor[dtype=float32, shape=(*, *, *), order='C', device='cuda']) None¶
Set the scalar values from a (X, Y, Z) float32 tensor.
SparseGrid¶
- class isoext.SparseGrid(shape, aabb_min=[-1, -1, -1], aabb_max=[1, 1, 1], default_value=float_max)¶
A sparse adaptive grid for storing scalar values.
Unlike UniformGrid, SparseGrid only allocates memory for cells that are explicitly added. This is useful for large domains where only a small region contains the iso-surface.
- Parameters:
shape (Sequence[int]) – The maximum number of cells in each dimension (x, y, z).
aabb_min (Sequence[float]) – The minimum corner of the bounding box.
aabb_max (Sequence[float]) – The maximum corner of the bounding box.
default_value (float) – Default scalar value for unset points.
- SparseGrid.get_num_cells(self) int¶
Return the number of active cells in the grid.
- SparseGrid.get_num_points(self) int¶
Return the number of points in active cells (num_cells * 8).
- SparseGrid.get_points(self) torch.Tensor[dtype=float32, order='C', device='cuda']¶
Return the 3D coordinates of points in active cells as an (N, 8, 3) float32 tensor.
- SparseGrid.get_values(self) torch.Tensor[dtype=float32, order='C', device='cuda']¶
Return the scalar values at active cell corners as an (N, 8) float32 tensor.
- SparseGrid.set_values(self, new_values: torch.Tensor[dtype=float32, shape=(*, 8), order='C', device='cuda']) None¶
Set the scalar values from an (N, 8) float32 tensor.
- SparseGrid.get_cells(self) torch.Tensor[dtype=uint32, order='C', device='cuda']¶
Return the cell connectivity as point indices.
- SparseGrid.add_cells(self, new_cell_indices: torch.Tensor[dtype=int32, shape=(*), order='C', device='cuda']) None¶
Add cells to the grid by their linear indices.
- Parameters:
new_cell_indices – 1D int32 tensor of cell indices to add.
- SparseGrid.remove_cells(self, new_cell_indices: torch.Tensor[dtype=int32, shape=(*), order='C', device='cuda']) None¶
Remove cells from the grid by their linear indices.
- Parameters:
new_cell_indices – 1D int32 tensor of cell indices to remove.
- SparseGrid.get_cell_indices(self) torch.Tensor[dtype=int32, order='C', device='cuda']¶
Return the linear indices of all active cells as a 1D int32 tensor.
- SparseGrid.get_potential_cell_indices(self, arg: int, /) list[torch.Tensor[dtype=int32, order='C', device='cuda']]¶
Get potential cell indices in chunks for memory-efficient processing.
- Parameters:
chunk_size – Maximum number of cells per chunk.
- Returns:
A list of 1D int32 tensors, each containing cell indices for a chunk.
- SparseGrid.get_points_by_cell_indices(self, cell_indices: torch.Tensor[dtype=int32, shape=(*), order='C', device='cuda']) torch.Tensor[dtype=float32, order='C', device='cuda']¶
Get the corner points of specified cells.
- Parameters:
cell_indices – 1D int32 tensor of cell indices.
- Returns:
An (N, 8, 3) float32 tensor of corner coordinates.
- SparseGrid.filter_cell_indices(self, cell_indices: torch.Tensor[dtype=int32, shape=(*), order='C', device='cuda'], values: torch.Tensor[dtype=float32, shape=(*, 8), order='C', device='cuda'], level: float = 0.0) torch.Tensor[dtype=int32, order='C', device='cuda']¶
Filter cells to keep only those that cross the iso-surface.
- Parameters:
cell_indices – 1D int32 tensor of cell indices to filter.
values – (N, 8) float32 tensor of scalar values at cell corners.
level – The iso-value to check against. Default is 0.0.
- Returns:
A 1D int32 tensor of cell indices that cross the iso-surface.
Intersection¶
- class isoext.Intersection¶
Stores edge-surface intersection points and normals for dual contouring.
Created by get_intersection() and used as input to dual_contouring(). You can modify the normals to control the surface reconstruction.
- get_normals¶
Return the surface normals at intersection points as an (N, 3) float32 tensor.
- get_points¶
Return the intersection points as an (N, 3) float32 tensor.
- has_normals¶
Return True if normals have been set or computed.
- set_normals¶
Set custom normals for the intersection points.
- Parameters:
new_normals – (N, 3) float32 tensor of normal vectors.