symbios-ground
An algorithmic terrain engine for Rust. Provides procedural heightmap generation, physically-inspired erosion simulation, and GPU-ready texture weight (splat) mapping.
Features
- Three terrain generators — Diamond-Square fractal, Fractional Brownian Motion value noise, Voronoi terracing
- Two erosion simulations — droplet-based hydraulic erosion, talus-based thermal erosion
- Splat mapping — 4-channel RGBA texture weight map keyed on height and slope
- World-space queries — bilinear height sampling and central-difference surface normals at any floating-point world coordinate
- Deterministic — all generators are seeded with a
u64; identical seeds always produce identical output serdesupport —HeightMapderivesSerialize/Deserialize
Quick start
# Cargo.toml
[]
= "0.2"
use ;
// 1. Allocate a 129×129 heightmap (1 world-unit per cell).
let mut hm = new;
// 2. Fill with fractal Diamond-Square terrain.
new.generate;
// 3. Smooth steep slopes with thermal erosion.
new
.with_iterations
.with_talus_angle
.erode;
// 4. Carve river valleys with hydraulic erosion.
new.erode;
// 5. Generate a 4-channel texture weight map (grass/dirt/rock/snow).
let weights = default.generate;
// 6. Query world-space height and surface normal at any position.
let h = hm.get_height_at;
let n = hm.get_normal_at; // unit [x, y, z], y = up
API overview
HeightMap
The central data structure. Stores a flat row-major Vec<f32> buffer of
width × height cells. scale is the world-unit size of each cell.
| Method | Description |
|---|---|
new(w, h, scale) |
Allocate zeroed heightmap |
width() / height() / scale() |
Grid dimensions and world-units-per-cell |
get(x, z) / set(x, z, v) |
Grid-cell access |
get_mut(x, z) |
Mutable reference to a grid cell |
get_clamped(x, z) |
Grid access with edge clamping |
get_height_at(wx, wz) |
Bilinear world-space height sample |
get_normal_at(wx, wz) |
Central-difference surface normal |
normalize() |
Rescale all values to [0, 1] |
data() / data_mut() |
Direct slice access |
world_width() / world_depth() |
width * scale / height * scale |
Generators
All generators implement TerrainGenerator:
DiamondSquare
Classic fractal subdivision. Resizes the heightmap to the smallest 2^n + 1
that covers its current dimensions (e.g. a 100×100 map becomes 129×129).
new
// roughness: 0.4 = smooth, 0.8 = jagged
FbmNoise
Multi-octave value noise with quintic smoothstep interpolation. Builder API:
new
.with_octaves // 1–32; default 6; more = finer detail
.with_persistence // amplitude decay per octave (default)
// Additional public fields for advanced tuning:
// fbm.lacunarity — frequency multiplier per octave (default 2.0)
// fbm.base_frequency — world-space frequency of the first octave (default 1.0)
VoronoiTerracing
Distributes random seed points, assigns each cell to its nearest seed, and quantises heights into discrete terraces.
new
// e.g. ::new(1, 50, 8) → 50 regions, 8 terrace levels
Erosion
Erosion modifies a HeightMap in-place via .erode(&mut hm).
ThermalErosion
Iterative slope-smoothing. Material on slopes steeper than talus_angle slides
to downhill neighbours.
new
.with_iterations
.with_talus_angle
.with_water_level // heights ≤ this use underwater rules
.with_underwater_talus_angle // gentler smoothing below water
.erode;
// The `fraction` field (default 0.25) controls how much excess material
// is transferred per iteration. Clamped to (0.0, 0.25] internally.
HydraulicErosion
Particle simulation. Each droplet flows downhill, eroding and depositing sediment to carve valleys and ridges.
new.erode;
// Fine-tune via public fields:
let mut eroder = new;
eroder.num_drops = 100_000;
eroder.erosion_rate = 0.4;
eroder.water_level = 0.2; // heights ≤ this force deposition (river deltas)
eroder.erode;
SplatMapper / WeightMap
Produces a 4-channel RGBA weight map for GPU terrain shaders. Each pixel's channels sum to ~255.
| Channel | Default layer | Conditions |
|---|---|---|
| R | Grass | Low altitude, gentle slope |
| G | Dirt | Mid altitude, any slope |
| B | Rock | Steep slopes |
| A | Snow | High altitude, gentle slope |
// Default grass/dirt/rock/snow preset:
let wm = default.generate;
// Custom rules:
use ;
let mapper = new;
let wm = mapper.generate;
// wm.data: Vec<[u8; 4]>, row-major, wm.width × wm.height pixels
Running benchmarks
Criterion benchmarks for get_height_at, get_normal_at, DiamondSquare,
and FbmNoise are in benches/bench_main.rs.
License
MIT — see LICENSE.