-
Notifications
You must be signed in to change notification settings - Fork 0
World Generation
ZigCraft implements a Luanti-style phased pipeline for procedural voxel terrain generation with structure-first design, multi-layer terrain, and intentional negative space.
The terrain generator uses a 5-phase pipeline:
| Phase | Name | Description |
|---|---|---|
| A | Terrain Shape | Biome-agnostic stone + water |
| B | Biome Calculation | Climate params, Voronoi selection |
| C | Surface Dusting | Biome-specific top/filler blocks |
| D | Cave Carving | Worm caves + noise cavities |
| E | Decorations | Trees, flowers, ores |
File: src/world/worldgen/generator.zig
Structural Noises:
| Noise | Purpose |
|---|---|
continentalness_noise |
Land vs ocean (0-1 scale) |
erosion_noise |
Terrain smoothness |
peaks_noise |
Mountain peak intensity (ridged) |
ridge_noise |
Ridge/mountain chains |
Climate Noises:
| Noise | Purpose |
|---|---|
temperature_noise |
Macro + local blend |
humidity_noise |
Macro + local blend |
V7 Terrain Layers:
| Noise | Purpose |
|---|---|
terrain_base |
Rolling hills |
terrain_alt |
Flatter terrain |
height_select |
Blend factor |
terrain_persist |
Detail variation |
variant_noise |
Sub-biome patches |
1. HARD OCEAN DECISION
- c < 0.35 = OCEAN (returns ocean depth)
2. PATH SYSTEM
- Valleys, rivers, plains corridors
3. V7 TERRAIN BLEND
- lerp(base, alt, height_select) * mood_mult
4. BASE HEIGHT from continentalness
- height = getBaseHeight(c) + v7_terrain - path_depth
5. MOUNTAINS (if allowHeightDrama)
- height += mountainLift + ridgeHeight
6. DETAIL + COMPRESSION + RIVER CARVING
File: src/world/worldgen/biome.zig
| Category | Biomes |
|---|---|
| Ocean |
deep_ocean, ocean
|
| Coastal |
beach, coastal_plains
|
| Cold |
snow_tundra, taiga, snowy_mountains
|
| Temperate |
plains, forest, mountains
|
| Warm/Wet |
swamp, mangrove_swamp, jungle
|
| Hot/Dry |
desert, savanna, badlands
|
| Special |
mushroom_fields, river
|
| Transitions |
foothills, marsh, dry_plains
|
fn selectBiomeVoronoi(heat, humidity, height, continentalness, slope) {
for (BIOME_POINTS) |point| {
if (!meetsConstraints(point)) continue;
dist = sqrt(Δheat² + Δhumidity²) / point.weight;
if (dist < min_dist) closest = point.id;
}
return closest;
}Edge detection injects transitions between incompatible biomes:
| Pair | Transition |
|---|---|
| Desert ↔ Forest/Plains | dry_plains |
| Snow Tundra ↔ Plains/Forest | taiga |
| Swamp ↔ Forest/Plains | marsh |
| Mountains ↔ Plains/Forest | foothills |
Each biome specifies:
- Heat/humidity range
- Surface blocks (top, filler)
- Vegetation density
- Terrain modifiers
- Height constraints
File: src/world/worldgen/caves.zig
| Algorithm | Description | Y Range |
|---|---|---|
| Worm Caves | Sphere-marching tunnels | 15-110 |
| Intersection | noise1 ∩ noise2 | All |
| Large Caverns | Massive deep chambers | 0-32 |
| Noise Cavities | 3D fBm pockets | 15-140 |
1. Spawn 1-3 worms per cave-enabled chunk
2. Random start position, random direction
3. For each step (80-180 steps):
a. Carve sphere at position
b. Advance by step_size
c. Perturb direction (3D Perlin)
d. Dampen vertical component
e. Vary radius occasionally
4. Check 3-chunk radius for cross-boundary worms
- 2D noise determines cave-enabled regions
- Scale: 1/900 (large regions)
- Threshold: 0.42 (lower = more caves)
- Surface protection: 8 blocks minimum
File: src/world/worldgen/decorations.zig
| Type | Examples |
|---|---|
SimpleDecoration |
Grass, flowers, dead bush, cactus, boulders |
SchematicDecoration |
Trees (oak, birch, spruce, etc.) |
Sub-biome patches via variant noise (-1.0 to 1.0):
| Variant Range | Effect |
|---|---|
| < -0.6 | Dense flower patches (40% probability) |
| -0.4 to 0.4 | Standard forest (2% trees) |
| > 0.4 | Dense forest (15% trees) |
| > 0.6 | Rocky patches (boulders) |
for (DECORATIONS) |deco| {
if (!biomeAllowed) continue;
if (variant outside range) continue;
if (!surfaceBlockAllowed) continue;
if (random > probability * region_mult) continue;
place(deco);
}File: src/world/worldgen/region.zig
Implements intentional negative space via Region Roles and Moods.
| Role | Percentage | Description |
|---|---|---|
| Transit | 50% | Fast, boring, flat - for travel |
| Destination | 30% | One star feature (lake/forest/mountain) |
| Boundary | 20% | Awkward separation zones |
| Feature | Transit | Destination | Boundary |
|---|---|---|---|
| Lakes | NO | Only if lake focus | NO |
| Rivers | NO | YES | NO |
| Sub-biomes | NO | Only if forest focus | NO |
| Height Drama | NO | Only if mountain focus | Medium |
| Vegetation | 25% | Themed | 15% |
Connect regions for natural travel:
| Path Type | Connection | Width |
|---|---|---|
valley |
Destination ↔ Destination/Transit | 32 blocks |
river |
Mountain → Lake Destination | 16 blocks |
plains_corridor |
Transit ↔ Transit | 12 blocks |
File: src/world/worldgen/mood.zig
Art direction multipliers for large-scale regions (2048 blocks).
| Mood | Percentage | Description |
|---|---|---|
| Calm | 30% | Boring stretches for travel |
| Sparse | 30% | Empty, lonely areas |
| Lush | 25% | Abundant vegetation |
| Wild | 15% | Chaos, height variance |
| Mood | Vegetation | Height | Rivers | Sub-biomes |
|---|---|---|---|---|
| Calm | 0.5x | 0.6x | NO | NO |
| Sparse | 0.1x | 0.3x | NO | NO |
| Lush | 1.5x | 0.9x | YES | YES |
| Wild | 0.8x | 1.3x | YES | YES |
| Level | Features |
|---|---|
| LOD0 | Full generation (all phases) |
| LOD1 | Skip worm caves, reduced decorations, no ores |
| LOD2 | Skip all caves and decorations |
| LOD3 | Heightmap-only, no 3D block data |
.lod0 => { caves=true, worm_caves=true, decorations=true, ores=true, lighting=true }
.lod1 => { caves=true, worm_caves=false, decorations=true, ores=false, lighting=false }
.lod2 => { caves=false, worm_caves=false, decorations=false, ores=false }
.lod3 => { caves=false, worm_caves=false, decorations=false, ores=false }File: src/world/worldgen/world_class.zig
Ensures LOD consistency by caching authoritative decisions.
struct {
biome_id: BiomeId,
surface_type: SurfaceType,
is_water: bool,
continental_zone: ContinentalZone,
region_role: RegionRole,
path_type: PathType,
}enum { grass, sand, rock, snow, water_deep, water_shallow, dirt, stone }enum { deep_ocean, ocean, coast, inland_low, inland_high, mountain_core }┌─────────────────────────────────────────────────────────────────────────┐
│ WORLD GENERATION PIPELINE │
├─────────────────────────────────────────────────────────────────────────┤
│ Phase A: Terrain Shape (biome-agnostic) │
│ ├── Continentalness → Ocean vs Land decision │
│ ├── V7 terrain blend (base + alt via height_select) │
│ ├── Region constraints (Role + Mood multipliers) │
│ ├── Path carving (valleys, rivers, corridors) │
│ └── Mountains/ridges (if allowHeightDrama) │
├─────────────────────────────────────────────────────────────────────────┤
│ Phase B: Biome Calculation │
│ ├── Temperature + Humidity (macro + local blend) │
│ ├── Voronoi selection in heat/humidity space │
│ ├── Structural constraints (height, slope, continentalness) │
│ ├── Edge detection → Transition biome injection │
│ └── Classification cache population │
├─────────────────────────────────────────────────────────────────────────┤
│ Phase C: Surface Dusting │
│ ├── Coastal surface types (sand/gravel beach, cliff) │
│ ├── Biome-specific top/filler blocks │
│ └── Elevation-aware surface morphing │
├─────────────────────────────────────────────────────────────────────────┤
│ Phase D: Cave Carving │
│ ├── Region mask check │
│ ├── Worm caves (sphere-marching) │
│ ├── Intersection caves (noise1 ∩ noise2) │
│ ├── Large caverns (deep underground) │
│ └── Surface protection (8 blocks) │
├─────────────────────────────────────────────────────────────────────────┤
│ Phase E: Features │
│ ├── Ore generation (coal, iron, gold, glowstone) │
│ ├── Decorations (variant-noise gated) │
│ ├── Skylight propagation │
│ └── Block light propagation (BFS) │
└─────────────────────────────────────────────────────────────────────────┘
- Biomes - Biome reference
- Block Types - Block definitions
- World System - Chunk management
Source: src/world/worldgen/ | Last updated: January 2026