Terrain processing libraries for 3D tile generation.
This repository provides libraries for processing terrain data into formats suitable for 3D globe applications like CesiumJS.
- Mesh Generation - Generate adaptive meshes from heightmap data using the RTIN algorithm
- Quantized Mesh - Encode/decode Cesium quantized-mesh-1.0 terrain format
- Coordinate Transformations - Convert between geodetic and ECEF coordinates
| Language | Path | Status |
|---|---|---|
| Rust | rust/ | Available |
| JavaScript | js/ | Planned |
| Go | go/ | Planned |
RTIN (Right-Triangulated Irregular Network) mesh generation from heightmaps. Based on the Martini algorithm by Mapbox.
- Source:
rust/martini/ - Published on crates.io as
martini
Encoder and decoder for Cesium quantized-mesh-1.0 terrain format.
- Source:
rust/quantized-mesh/
Higher-level utilities — re-exports martini + quantized_mesh, plus
seamless DEM-gradient vertex normals (eliminates tile-boundary shading
seams) and RGB heightmap codecs (Terrarium / Mapbox Terrain-RGB / GSI).
- Source:
rust/terrain-codec/
- Load a heightmap (GeoTIFF, PNG, etc.)
- Mesh it with
martini→ vertices, indices, UVs - Encode with
quantized-mesh→.terrainfile (quantized-mesh-1.0)
Steps 2–3 can be done in a single call with
terrain_codec::terrain::encode_terrain,
which runs martini, quantises the mesh, builds the header, computes optional
vertex normals, and encodes — straight from an elevation grid to .terrain
bytes:
use terrain_codec::quantized_mesh::TileBounds;
use terrain_codec::terrain::{encode_terrain, TerrainOptions};
let terrain: Vec<u8> = encode_terrain(
&elevations, // flat row-major (north→south) f32 grid, grid_size² entries
grid_size, // 2^n + 1, e.g. 65
&bounds, // TileBounds in degrees
&TerrainOptions { max_error: 1.0, ..Default::default() },
);encode_terrain always folds the WGS84 ellipsoid "curvature bulge" into
martini's error pyramid (never into the stored heights), so nearly-flat
low-zoom tiles keep enough triangles to track the globe's curve instead of
collapsing to a flat quad that cuts under it. The bulge shrinks with the
square of the tile span, so it costs nothing at high zoom.
DEM tiles are usually served in web-mercator (XYZ; Terrarium, Mapbox
Terrain-RGB) while Cesium terrain is geodetic TMS (EPSG:4326). To bridge
the two,
terrain_codec::mercator::MercatorDem
stitches the covering web-mercator DEM tiles and resamples them onto the
geodetic grid encode_terrain expects (and the halo grid for seam-free
normals). Fetching the source tiles stays with the caller, so it's free of
async/IO assumptions.
MIT OR Apache-2.0