Skip to content

Add enhanced terrain generation features#929

Merged
brendancol merged 4 commits intomasterfrom
feature/enhanced-perlin-noise
Mar 2, 2026
Merged

Add enhanced terrain generation features#929
brendancol merged 4 commits intomasterfrom
feature/enhanced-perlin-noise

Conversation

@brendancol
Copy link
Contributor

Summary

  • Six new generate_terrain parameters: ridged multifractal noise, domain warping, lacunarity/persistence, adaptive octave count, Worley noise blending, hydraulic erosion
  • New worley.py and erosion.py modules, all 4 backends (numpy, cupy, dask+numpy, dask+cupy)
  • New _perlin_gpu_xy CUDA kernel for non-linear coordinate arrays (domain warping needs this)
  • Defaults reproduce existing output; API is backward-compatible

What changed

generate_terrain new parameters:

  • octaves (int or None) -- None = adaptive ceil(log2(min(H,W)))
  • lacunarity / persistence -- frequency and amplitude ratios per octave
  • noise_mode -- 'fbm' (default) or 'ridged' for sharp ridges
  • warp_strength / warp_octaves -- domain warping
  • worley_blend / worley_seed -- Worley cellular noise
  • erode / erosion_iterations / erosion_params -- particle-based hydraulic erosion post-pass

New modules:

  • worley.py -- Worley noise: @ngjit CPU kernel, CUDA kernels (linear + xy variants), dask wrappers, ArrayTypeFunctionMapping dispatch
  • erosion.py -- droplet simulation with bilinear gradient, inertia, sediment capacity, distance-weighted brush kernel. Materializes dask before processing since erosion is global.

Modified modules:

  • perlin.py -- added _perlin_gpu_xy kernel (same noise math, reads from 2D coordinate arrays instead of linear ranges)
  • terrain.py -- rewrote octave loop for all 4 backends; added warping, ridged, and Worley stages. dask+cupy backend inlines the full pipeline into one map_blocks callable.

Test plan

  • pytest xrspatial/tests/test_terrain.py -v -- 24 tests: basic generation, each feature individually, cross-backend matching (numpy vs dask, numpy vs cupy), combined smoke tests, input validation
  • pytest xrspatial/tests/test_perlin.py -v -- existing perlin tests still pass
  • Visual: generate_terrain(raster, noise_mode='ridged', warp_strength=0.4, worley_blend=0.1) on 512x512 should show ridged mountains with warping and rocky texture

…rley blending, and hydraulic erosion

New generate_terrain parameters: octaves, lacunarity, persistence,
noise_mode ('fbm'/'ridged'), warp_strength, warp_octaves,
worley_blend, worley_seed, erode, erosion_iterations, erosion_params.
Defaults reproduce existing behavior.

- perlin.py: add _perlin_gpu_xy kernel for non-linear coordinate arrays
- worley.py: new Worley (cellular) noise module with 4-backend support
- erosion.py: new particle-based hydraulic erosion module
- terrain.py: configurable octave loop, ridged multifractal, domain
  warping, Worley blending, erosion post-pass across all 4 backends
- __init__.py: export erode
- tests: 24 tests covering each feature, cross-backend matching,
  combined smoke tests, and input validation
@github-actions github-actions bot added the performance PR touches performance-sensitive code label Mar 2, 2026
- perlin.py: persist noise before computing min/ptp in both dask+numpy
  and dask+cupy paths, preventing a full recompute on normalization
- terrain.py: persist warped coordinates before the octave loop so each
  iteration doesn't rebuild the warp subgraph; persist worley noise
  before min/max so the blend doesn't recompute it
- terrain.py: pre-allocate scaled_x/scaled_y GPU buffers and use
  cupy.multiply(out=) instead of allocating temporaries per iteration
Use floor instead of int truncation for cell coordinates in perlin and
worley noise. int() truncates toward zero, which gives wrong cell
indices and negative fractional parts for coordinates below zero (common
with domain warping). Switched to np.floor / math.floor throughout
_perlin, _perlin_gpu, _perlin_gpu_xy, _worley_cpu, _worley_gpu, and
_worley_gpu_xy.

Fix _worley_gpu writing last-computed dist instead of min_dist.

Fix per-chunk worley normalization in the dask+cupy terrain backend.
Each chunk was normalizing worley noise with its own min/max, producing
visible seams at chunk boundaries. Added a worley pre-pass that computes
global min/max before the main terrain computation, and a
worley_norm_range parameter on _terrain_gpu to accept externally
computed bounds.

Added chunk-boundary continuity tests with odd chunk sizes (13x17) for
warp, worley, and combined features.
Add Worley noise and hydraulic erosion rows. Update Terrain Generation
description to mention ridged noise, domain warping, Worley blending,
and erosion options.
@brendancol brendancol merged commit 00317a1 into master Mar 2, 2026
11 checks passed
@brendancol brendancol deleted the feature/enhanced-perlin-noise branch March 5, 2026 03:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

performance PR touches performance-sensitive code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant