Expand description
Engine-agnostic isosurface extraction. Field in, triangles out.
use isomesh::marching_cubes::MarchingCubes;
use isomesh::fields::Sphere;
use isomesh::{MeshBuffer, RuntimeShape3};
let field = Sphere::<f32>::canonical(); // any `Sdf` -- yours, or one of eight here
let shape = RuntimeShape3::new([33; 3])?; // 33 samples per axis, so 32 cells
let mut mesh = MeshBuffer::<f32>::new(); // reused across calls; never reallocated
MarchingCubes::<f32>::new()
.extract(&field, &shape, [-2.0; 3], 0.125, &mut mesh)?;
assert!(mesh.triangle_count() > 0);mesh.positions is Vec<[f32; 3]> and mesh.indices is Vec<u32> — hand
them to a renderer, a physics engine, or an exporter. There is no mesh type to
learn and no math library in the way.
§Why it looks like this
isomesh has to serve both a real-time voxel game and a CAD tool, and that
single constraint decides most of its design: no math library appears in a
public signature, output buffers are caller-provided and reusable, and the
scalar type is generic over f32 and f64.
§Which extractor
Seven implement Extractor. Two questions decide it,
and both answers are measured rather than argued.
Are you chunking? Then the seam is structural, not a bug someone will fix
later: MarchingCubes and
SubgridMarchingTetrahedra
tile with zero boundary edges on a shared plane; the dual methods place one
vertex per cell and are gapped by construction.
Do you need sharp corners? Then
DualContouring reaches a box corner to
0.01 cells where SurfaceNets stops at
0.58, and is 101× closer in Hausdorff distance on a sharp field — and 1.2× on
a smooth one, which is why this is a choice rather than an upgrade.
You cannot have both today. That is measured and open, not hidden.
The others are for narrower jobs:
MarchingTetrahedra trades ~3× the
triangles for better sharp-field accuracy,
ManifoldDualContouring
splits a cell by surface component, and
GreedyQuads is the blocky path.
§Conventions
These hold for every type and every algorithm in this crate. They are stated once here and repeated on the items they constrain, because each one is a convention rather than a fact, and a mismatch across a module boundary produces output that looks plausible and is wrong.
- Sign. Negative is inside. A field is negative strictly inside the solid, positive strictly outside, and the surface is the zero level set.
- Handedness. Right-handed.
x × y = +z. - Winding. Counter-clockwise viewed from outside the solid.
- Normals. Point away from the solid, i.e. along increasing field value.
- Index order.
xvaries fastest:i = x + y·sx + z·sx·sy.
§Float math
Every transcendental goes through libm, unconditionally — there is no
std fast path. Two reasons. One execution path: a #[cfg(feature = "std")]
fork would mean two float backends and two sets of results for the same
input. And determinism: std’s sin/cos are the platform’s, are not
correctly rounded, and differ between macOS and Linux, which would make
committed golden hashes platform-specific. It costs nothing at run time —
libm::sqrtf compiles to fsqrt on aarch64+neon and sqrtss on
x86-64+sse2.
§no_std
This crate is no_std unconditionally, not cfg_attr-conditionally. A
conditional attribute would put std’s prelude in scope for the default
build, so a stray use std::collections::HashMap would compile here and
break only in some later no_std build. Unconditional makes that a compile
error at the moment it is typed.
Modules§
- brush
- Brush operations: the edits a sculpting tool makes to a field.
- chunk
- Chunking: the coordinate system a streamed world is meshed in.
- collider
- Handing a mesh to a physics engine, and knowing first whether it will take it.
- connectivity
- Connectivity of the air sublevel set, repaired incrementally as you dig and as you fill.
- construct
- Building a distance field, rather than consuming one.
- dual
- The machinery both dual methods share.
- dual_
contouring - Dual Contouring — the sharp-feature method.
- experiment
- Pre-registration, as a compile error.
- experimental
- Speculative algorithms, behind the
experimentalfeature. - extractor
- One trait over every extraction algorithm, and one list of them.
- fields
- The fourteen reference fields.
- greedy_
quads - Blocky meshing with greedy quad merging.
- hermite
- Hermite data: where the surface crosses each cell edge, and which way it faces there.
- lod
- Coarsening a sampled field, and the four ways people do it.
- manifold_
dual_ contouring - Manifold Dual Contouring — one vertex per surface component, not per cell.
- marching_
cubes - Marching Cubes.
- marching_
tetrahedra - Marching Tetrahedra.
- mass
- Volume, centre of mass and the inertia tensor of the solid the triangles bound — computed on the surface, with no volume mesh and no round trip through a physics crate.
- normals
- Where a vertex normal comes from, made a decision rather than an assumption.
- orient
- Give a mesh a coherent orientation, one connected component at a time.
- paint
- Surface attributes that survive destruction: paint that stays where it was sprayed when the wall under it is carved away.
- predicates
- Exact geometric predicates: sign tests that are never wrong.
- subgrid
- Subgrid Marching Tetrahedra — features finer than one cell.
- surface_
nets - Surface Nets — the dual method.
- transvoxel
- Transvoxel — stitching two blocks meshed at different resolutions.
- validate
- Mesh validity metrics.
- weld
- Welding coincident vertices, and the lattice that finds them.
Macros§
- experiment
- The pre-registration for
$id, or a compile error if there is none. - for_
each_ extractor - Every extractor the suite covers, run once each.
- for_
each_ reference_ field - Runs a block once per reference field, with the field bound to a concrete type.
Structs§
- Const
Shape3 - A shape whose dimensions are known at compile time.
- Mesh
Buffer - The default sink: three parallel
Vecs, reusable across chunks. - Runtime
Shape3 - A shape whose dimensions are known at run time.
Enums§
- Error
- What went wrong.
Traits§
- Mesh
Sink - Receives the triangles an extraction algorithm produces.
- Real
- The scalar an
Sdfsamples in and the vertex solvers work in. - Sdf
- A scalar field sampled at a point. This is the only thing an extraction algorithm needs to see.
- Shape3
- Maps a 3D grid coordinate to a flat buffer index and back.
Type Aliases§
- Result
- This crate’s result type.