I've published 1.0.0 of brodo, a library for sparse 3D volumes, along with two companion crates, colino and mestolo.
- Repository: GitHub - akahmys/brodo · GitHub
- Docs: brodo, colino, mestolo
[dependencies] brodo = "1" colino = "1" brodo
brodo stores values only over the voxels you activate. They live in a fixed four-level tree with OpenVDB's default shape: a root, internal nodes of 32³ and 16³, and leaves of 8³. A uniform region is held as a single tile.
The main design choice is that the set of active voxels, Topology, is a value of its own, separate from the data. Any number of fields of any value type can sit on one topology. When you edit the topology, you get back a Remap that carries each field over to the new one, and a field refuses a topology it doesn't belong to.
use brodo::field::Field; use brodo::topology::Topology; let empty = Topology::new(); let mut edit = empty.edit(); edit.activate([0, 0, 0])?; edit.activate([8, 0, 0])?; let (t, _remap) = edit.commit()?; let mut solid = Field::new(&t, 0_u8); Beyond that, it has:
-
leaf-parallel updates, each leaf's 26 neighbours, and a leaf gathered with ghost layers, for stencil work. The result is the same at any thread count.
-
connected components, the Euler characteristic, and dilation and erosion, with 6- or 26-connectivity.
-
files:
- a cache file you can read in place (no copy) or memory-map
- a compressed archive that can be read back by region
- OpenVDB's
.vdbfor float and double grids, implemented in Rust. Files brodo writes are read back by OpenVDB 14.0.0's own tools with every value the same.
The bytes of brodo's own formats are specified in docs/formats.md, so other languages can read them.
-
a slice as PNG and a field as
.vtufor ParaView, for checking results by eye.
What it deliberately leaves out: level-set operations (CSG, offsetting, redistancing), meshing an SDF, and anything solver-specific. Those are left to the code that uses it.
colino
colino converts STL, OBJ and 3MF meshes to narrow-band signed distance fields on brodo's tree. Inside and outside are told by the generalised winding number, so self-intersecting or double-walled meshes still work.
It also reports how the conversion may have changed the shape:
- components, tunnels and cavities, of the solid and of the space around it
- the Euler characteristic compared with the input's, when the input is closed and manifold
- places thinner, or gaps narrower, than two voxels
mestolo
mestolo is a command for someone who receives one of these files and writes no Rust:
cargo install mestolo mestolo info grids.cache mestolo slice grids.cache --grid sdf --axis z --at 0 -o z0.png mestolo convert grids.cache -o grids.vdb mestolo convert grids.cache --grid sdf -o sdf.vtu Platform
- Rust 1.98 or later.
- 64-bit little-endian targets only, since the frozen layout is read in place.
- CI runs on Linux x86-64, macOS arm64 and Windows x86-64.
- No C or C++ in the build.
- The crates follow semver, and each release is checked against the previous one with cargo-semver-checks.
How it was written
Most of the code was written by AI coding agents, mainly Claude Code. I set the direction, decided the rules and the design questions, and approved each release. The rules the agents work under are in the repository, starting from AGENTS.md. As many of them as possible are checked by scripts that every change has to pass:
- a new test is shown to fail against the defect it guards
- mutation testing with cargo-mutants before each milestone closes
- fuzz targets for every parser of untrusted bytes
- Miri on the paths through unsafe code
- the semver check above
The crates are MIT OR Apache-2.0. To keep copyleft code out, the agents are blocked from reading certain sources, and what each source file drew on is recorded. For the same reason I don't take pull requests.
Issues are welcome, for bugs or for things the crates don't do yet. Some candidates for 1.x are already open there. 1.1 will fill small gaps in what 1.0 has, without breaking anything.
Feedback on the API is very welcome.
1 post - 1 participant



