Skip to main content

Crate isomesh

Crate isomesh 

Source
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. x varies 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 experimental feature.
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§

ConstShape3
A shape whose dimensions are known at compile time.
MeshBuffer
The default sink: three parallel Vecs, reusable across chunks.
RuntimeShape3
A shape whose dimensions are known at run time.

Enums§

Error
What went wrong.

Traits§

MeshSink
Receives the triangles an extraction algorithm produces.
Real
The scalar an Sdf samples 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.