ordito is a GPU-first triangular mesh processing library built on NVIDIA Warp. It provides mesh geometry, connectivity, queries, editing, and solvers as plain array-in / array-out functions backed by Warp kernels, with a trimesh-inspired API. Every function runs on CUDA when a GPU is available and falls back to CPU otherwise, with the same code.
Ordito (or-DEE-toh) is Italian for the warp of a fabric, and an anagram of toroid: a fitting name for a mesh library built on Warp.
Highlights
- One dependency. The runtime depends on
warp-langalone; NumPy comes with Warp; nothing else (no SciPy, PyTorch or trimesh) is needed at runtime. - Broad coverage. Hundreds of functions across dozens of public modules, spanning primitives, topology, repair, remeshing, spatial queries, discrete differential operators, geodesics, sampling, surface reconstruction, and registration.
- Stays on the device. Functions take Warp arrays and return Warp arrays, so pipelines compose without host round-trips; device placement follows the inputs.
- Optional
Trimeshobject. A frozen mesh class with lazily cached derived quantities (normals, adjacency, boundary loops, manifoldness and watertightness predicates, BVH) for when an object API is more convenient than free functions. - Exact where it matters. Convex hulls and other topological decisions take exact orientation signs, so the answer does not depend on a tolerance or on the device.
- Reproducible on demand. One switch,
od.set_deterministic(True), makes results repeat bit for bit on CUDA; see Reproducible results. - Fully typed (
py.typed) and validated function-by-function against eleven reference implementations — nine established geometry-processing libraries plus SciPy and NumPy, all listed below.
Install
pip install ordito
uv add ordito
Requires Python ≥ 3.11 and warp-lang ≥ 1.18. A CUDA-capable GPU is recommended but not required.
Mesh file I/O via meshio is an optional extra:
pip install "ordito[io]".
Quickstart
import ordito as od
# Parametric primitives allocate directly on the default device (CUDA if available).
vertices, faces = od.creation.icosphere(subdivisions=4)
# Optional object API: derived quantities are computed on first access and cached.
mesh = od.Trimesh(vertices, faces)
print(f"{mesh.area:.4f}") # 12.5514
print(mesh.is_watertight) # True
print(mesh.euler_characteristic) # 2
# Feature-preserving isotropic remeshing (split / collapse / flip / smooth / reproject).
remeshed_vertices, remeshed_faces = od.remesh.isotropic_remesh(vertices, faces, target_length=0.05)
Continue with Getting started for the full walkthrough (including a repair-then-remesh pipeline on a realistically broken mesh), or jump straight to a task:
- Concepts — the design principles worth knowing before writing anything nontrivial.
- Examples — a gallery of runnable examples, each with the image it produces: creation, inspection, curvature, geodesics, parametrization, smoothing, remeshing, repair, voxels, queries, cutting, point clouds, reconstruction and registration.
- Migrating from another library — already know trimesh, libigl, Open3D, MeshLab, potpourri3d, or PyTorch3D? Start here.
- Benchmarks — a curated set of ordito-vs-reference comparisons, rendered as charts, each library named by its own logo.
One GPU library instead of nine
Mesh processing in Python has long meant stitching together several excellent — but mostly CPU-bound and stylistically different — libraries. ordito consolidates the functionality it needs from each of them behind a single GPU-accelerated API:
| Replaces | For | In ordito |
|---|---|---|
| trimesh | Mesh bookkeeping: edges, adjacency, boundary, validation, primitives, sampling, proximity | edges, adjacency, boundary, validation, creation, sample, proximity, the Trimesh class |
| libigl (Python bindings) | Discrete differential geometry: cotangent Laplacians, mass matrices, curvature, parametrization, heat-method geodesics | laplacian, energies, curvature, parametrization, heat |
| Open3D | Point clouds, registration, and surface reconstruction: ICP, screened Poisson, ball pivoting | points, registration, reconstruction |
| MeshLab (PyMeshLab) | Mesh editing filters: isotropic remeshing, decimation, smoothing, hole filling, uniform resampling | remesh, smoothing, holes, repair |
| PyVista (VTK) | The VTK toolkit: feature edges, cell-quality metrics, contouring and clipping, point location, arc-length and polyline measures, voxelization | edges, triangles, intersection, levelset, proximity, polyline, voxels |
| MeshLib | Minimum-weight hole filling and stitching, self-intersection repair, voxel offsets and booleans, projection queries, spike and outlier detection | holes, repair, levelset, voxels, proximity, points |
| PyMeshFix (MeshFix / TMesh) | The repair pipeline end to end: a broken digitised surface in, one watertight solid out | repair, holes, validation |
| potpourri3d (geometry-central) | The heat-method family: vector heat, parallel transport, log maps, signed distance, tangent frames | heat, tangent_space |
| PyTorch3D | Batched neighbour and Chamfer primitives, the mesh regularization losses, cubify and marching cubes | metrics, neighbors, energies, registration, levelset, voxels |
SciPy's spatial.KDTree and sparse.csgraph (covered by neighbors,
graph and proximity) and NumPy's array primitives (array, reduce, grouping, linalg)
round the set out to the eleven reference implementations the suite measures against.
These libraries are not runtime dependencies; they are test oracles. Wherever one of them
computes the same quantity as an ordito function, a regression test compares the two outputs
value by value. A parity gate in the test suite fails the build if any library the benchmarks
time against ordito is neither compared in a test nor exempted with a written reason. Every
(group, library) pair in the benchmark suite is either covered by a value test or carries a
written exemption (typically a different algorithm answering a related question); none are
uncovered, and python -m tests.parity prints the current matrix. Where ordito and a reference disagree by definition rather than by rounding
(a sign convention, a squared distance), the docstring says so and the test pins the difference.
Development
git clone https://github.com/lucagrementieri/ordito
cd ordito
uv sync --all-groups # runtime + dev + test + docs + bench dependencies
uv run pytest # regression tests against the reference libraries
uv run ruff format ordito tests && uv run ruff check ordito tests
uv run basedpyright # type checking (0 errors expected)
uv run zensical serve # preview the docs locally
See the source repository for contribution guidelines and the full development setup.