Surface mesh generation from sparse (N, 3) voxel indices
Project description
sparse-cubes
Mesh generation for (N, 3) voxel indices - i.e. the equivalent of a 3D
sparse matrix in COOrdinate format.
sparse-cubes works directly on the sparse surface voxels which is faster and,
importantly, much more memory efficient than converting to a dense 3D matrix and
using e.g. marching cubes from scikit-image. Memory scales with the number of
surface voxels rather than the volume's bounding box.
Meshing modes
sparse-cubes finds the exposed faces of your voxels and turns them into a
mesh. There are two ways to place the vertices, selected with the smooth
flag on mesh() (or via the explicit surface_nets() / culled_faces()
functions):
- Smooth (
sc.mesh(voxels)/sc.surface_nets(voxels), the default). A naive SurfaceNets pass: one vertex per surface cell, placed at the centroid of the surface crossings around it. This is a dual method (a cousin of dual contouring) and smooths the staircase you would otherwise get on diagonal surfaces. Vertices are floats. - Blocky (
sc.mesh(voxels, smooth=False)/sc.culled_faces(voxels)). Each exposed voxel face becomes an axis-aligned quad with corners on the integer voxel grid ("culled cube faces", à la Minecraft). Fast and keeps the input integer dtype, but diagonal surfaces come out as 90° steps. This is the historical output.
Optional simplification (blocky only)
Pass simplify=True (or use sc.greedy_faces(voxels)) to merge coplanar faces
of the blocky mesh into maximal rectangles
(greedy meshing):
>>> full = sc.mesh(voxels, smooth=False)
>>> small = sc.mesh(voxels, smooth=False, simplify=True) # ~2x fewer triangles
This is lossless - the covered surface is identical - and keeps the integer vertex dtype. It typically roughly halves the triangle count (a flat W×H wall becomes a single quad instead of W·H quads) at little to no extra cost. Caveat: like all greedy meshing it can introduce T-junctions, so the simplified mesh may be "less watertight" than the per-face mesh; it is opt-in for that reason.
Please see this blog for an excellent introduction to dual contouring and SurfaceNets. See also notes at the end of the README.
Install
Install latest version from PyPI:
pip3 install sparse-cubes -U
To install the developer version from Github:
pip3 install git+https://github.com/navis-org/sparse-cubes.git
The only dependencies are numpy and trimesh. Will use fastremap if present.
Usage
>>> import sparsecubes as sc
>>> import numpy as np
>>> # Indices for two adjacent voxels
>>> voxel_xyz = np.array([[0, 0, 0],
... [0, 0, 1]],
... dtype='uint32')
>>> # Smooth (SurfaceNets) mesh by default; vertices are floats
>>> m = sc.mesh(voxel_xyz)
>>> m
<trimesh.Trimesh(vertices.shape=(12, 3), faces.shape=(20, 3))>
>>> m.is_winding_consistent
True
>>> # Pass smooth=False (or call sc.culled_faces) for the blocky, integer mesh
>>> m_blocky = sc.mesh(voxel_xyz, smooth=False)
>>> # ...and simplify=True (or sc.greedy_faces) to merge coplanar faces losslessly
>>> m_small = sc.mesh(voxel_xyz, smooth=False, simplify=True)
sc.dual_contour and sc.marching_cubes still exist as deprecated aliases
of sc.mesh (their old interpolate argument maps to smooth) but emit a
DeprecationWarning - neither name ever described what this library actually
does.
Notes
- The mesh might have non-manifold edges. Trimesh will report these meshes as not watertight but in the very literal definition they do hold water.
- The names
dual_contour/marching_cubeswere misnomers: the blocky path is really culled cube faces (vertices only ever land on cube corners) and the smooth default is naive dual/SurfaceNets placement. Full feature-preserving dual contouring (QEF-based placement using surface normals) is not implemented.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sparse_cubes-0.2.0.tar.gz.
File metadata
- Download URL: sparse_cubes-0.2.0.tar.gz
- Upload date:
- Size: 26.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.9.25
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a7a3ad6729e7527c975a0e0f4a76ab5f908d9317b92d351db1b21109745275ac
|
|
| MD5 |
e7a4211fcca9b6e79c4e2a762d86c82a
|
|
| BLAKE2b-256 |
39af95e62babe8357f5993c0b0878578705c9bef4c7184a86aa3ced66e8b472c
|
File details
Details for the file sparse_cubes-0.2.0-py3-none-any.whl.
File metadata
- Download URL: sparse_cubes-0.2.0-py3-none-any.whl
- Upload date:
- Size: 27.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.9.25
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
26cf2fb12372f911c43b51aa9a27898f2ee70709b4fc1a00769a1fdb74aace4a
|
|
| MD5 |
71238612a054669090aa720b7f3bff0f
|
|
| BLAKE2b-256 |
f37ec8d31978379c31f28cba8d98dff3ee632906d49272aeb3d2addd968c45b7
|