feat(world-gen): larger biomes, smooth height blending, capped mountains; centralize tunables in Configuration

Terrain feel: biome regions ~10x larger (Voronoi cell size 96->960); terrain height now eases across biome borders via a Voronoi distance blend (smooth, and ~25x cheaper than the old 169-sample box blur); mountains capped to ~2/3 world height and gentled (ridged amplitude/frequency lowered), snow line lowered to match.

Centralization: ~27 world-gen/render tuning constants (biome amplitudes & frequencies, climate-noise frequencies/octaves, biome-selection thresholds, blend width, cell size, filler depth, snow line, camera near plane, spawn offset, overlay scale) hoisted from scattered literals into a region-organized, fully-commented Configuration. Configuration is threaded into NoiseSource, the biomes, BiomeRegistry, BiomeMap (+Classify), TerrainSampler, WorldGenerator (+BlockAt filler depth), and Camera via Player. Defaults equal the prior values, so generation is unchanged; worldgen tests updated for the new constructor signatures.
This commit is contained in:
MDietermann
2026-06-03 16:27:06 +02:00
parent 96b8fffcd4
commit e034d10339
18 changed files with 367 additions and 136 deletions

View File

@@ -4,58 +4,205 @@ using OpenTK.Mathematics;
public sealed class Configuration
{
#region -- World --
// World generation seed. null → a fresh random seed each run; set a value for
// a reproducible world.
public int? Seed { get; set; } = null;
// Blocks above the terrain surface at (0,0) where the player spawns.
public float SpawnHeightOffset { get; set; } = 2f;
#endregion -- World --
#region -- Rendering & View --
// Horizontal view radius in chunks (Chebyshev). Drives how far terrain loads
// and the fog / far-plane distance. Higher = see further, much heavier load.
public int RenderDistanceHorizontal { get; set; } = 8;
// Camera vertical field of view, in degrees.
public float Fov { get; set; } = 60f;
// Near clip plane distance (world units); anything nearer is not drawn.
// (The far plane is derived from RenderDistanceHorizontal over in Player.)
public float CameraNearPlane { get; set; } = 0.1f;
// Distance fog begins at this fraction of the fog-end distance (fog end is
// derived from RenderDistanceHorizontal). 0.7 → fog starts at 70% of the edge.
public float FogStartFraction { get; set; } = 0.7f;
// Sky / clear color, also the distance-fog target color.
// Sky / clear colour, also the distance-fog target colour (RGB, 0–1).
public Vector3 SkyColor { get; set; } = new(0.45f, 0.65f, 0.95f);
public int SpawnReadyRadiusHorizontal { get; set; } = 1;
public int MaxGenerateJobsInFlight { get; set; } = 8;
public int MaxMeshUploadsPerFrame { get; set; } = 4;
public int WorkerThreadCount { get; set; } = Math.Max(1, Environment.ProcessorCount / 2);
#endregion -- Rendering & View --
// Multiplier applied to (dy)^2 in chunk-load priority. >1 prioritizes
// chunks at the player's Y over equally-distant chunks above/below, so the
// visible surface fills in before far-underground / overhead chunks.
public int VerticalPriorityWeight { get; set; } = 4;
#region -- Window --
public float MoveSpeed { get; set; } = 8f;
public float MouseSensitivity { get; set; } = 0.15f;
public float Fov { get; set; } = 60f;
public int WindowWidth { get; set; } = 1280;
// Initial window size in pixels.
public int WindowWidth { get; set; } = 1280;
public int WindowHeight { get; set; } = 720;
public int? Seed { get; set; } = null;
#endregion -- Window --
// -- Cave generation tuning --
#region -- Chunk Streaming --
// Horizontal radius (chunks) around spawn that must finish loading before the
// loading screen clears.
public int SpawnReadyRadiusHorizontal { get; set; } = 1;
// Max chunk generate/mesh jobs running on worker threads at once.
public int MaxGenerateJobsInFlight { get; set; } = 8;
// Max finished chunk meshes uploaded to the GPU per frame (caps per-frame hitches).
public int MaxMeshUploadsPerFrame { get; set; } = 4;
// Background worker threads used for chunk generation/meshing.
public int WorkerThreadCount { get; set; } = Math.Max(1, Environment.ProcessorCount / 2);
// Multiplier applied to (dy)² in chunk-load priority. >1 prioritizes chunks at
// the player's Y over equally-distant chunks above/below, so the visible
// surface fills in before far-underground / overhead chunks.
public int VerticalPriorityWeight { get; set; } = 4;
#endregion -- Chunk Streaming --
#region -- Player & Controls --
// Movement speed, in blocks per second.
public float MoveSpeed { get; set; } = 8f;
// Mouse-look sensitivity (degrees of rotation per pixel of mouse movement).
public float MouseSensitivity { get; set; } = 0.15f;
#endregion -- Player & Controls --
#region -- World Gen: Terrain Shape --
// Average width in blocks of one biome region (Voronoi cell). Larger = bigger,
// fewer biomes.
public float BiomeCellSize { get; set; } = 960f;
// Blocks over which terrain height eases from one biome to its neighbour across
// their shared border. Larger = gentler, wider transitions.
public float BiomeBlendWidth { get; set; } = 128f;
// Filler layers (dirt/sand) placed directly below the surface block before the
// biome's solid under-material (usually stone) begins.
public int SurfaceFillerDepth { get; set; } = 3;
#endregion -- World Gen: Terrain Shape --
#region -- World Gen: Climate Noise --
// Low-frequency fields that decide biome placement. Lower frequency = larger,
// smoother climate regions; more octaves = more fine variation.
// Elevation field — high values become Mountains, low values lowland.
public float ContinentFrequency { get; set; } = 0.0035f;
public int ContinentOctaves { get; set; } = 4;
// Temperature field — high values become Desert.
public float TemperatureFrequency { get; set; } = 0.0015f;
public int TemperatureOctaves { get; set; } = 3;
// Forest-density field — high values become Forest (else Plains).
public float ForestFrequency { get; set; } = 0.02f;
#endregion -- World Gen: Climate Noise --
#region -- World Gen: Biome Selection --
// Thresholds on the climate fields (values ≈ -1..1), tested in order:
// mountains → desert → forest → plains.
// Elevation at/above which a cell is Mountains.
public float MountainsElevationThreshold { get; set; } = 0.25f;
// Temperature above which a non-mountain cell is Desert.
public float DesertTemperatureThreshold { get; set; } = 0.33f;
// Minimum temperature for Forest (colder than this → Plains).
public float ForestTemperatureThreshold { get; set; } = -0.33f;
// Minimum forest-density for Forest (below this → Plains).
public float ForestDensityThreshold { get; set; } = 0f;
#endregion -- World Gen: Biome Selection --
#region -- World Gen: Biome Surface Heights --
// Per biome: surfaceHeight = SeaLevel + ContinentAmplitude·continentNoise
// + DetailAmplitude·detailNoise. Amplitudes are in blocks; detail frequency
// sets the bumpiness scale (higher = smaller, choppier features).
// Plains — gentle rolling grassland.
public float PlainsContinentAmplitude { get; set; } = 24f;
public float PlainsDetailAmplitude { get; set; } = 8f;
public float PlainsDetailFrequency { get; set; } = 0.01f;
// Forest — like plains, a touch hillier.
public float ForestContinentAmplitude { get; set; } = 24f;
public float ForestDetailAmplitude { get; set; } = 16f;
public float ForestDetailFrequency { get; set; } = 0.01f;
// Desert — flat with low dunes.
public float DesertContinentAmplitude { get; set; } = 16f;
public float DesertDetailAmplitude { get; set; } = 6f;
public float DesertDetailFrequency { get; set; } = 0.008f;
// Mountains — tall ridged peaks (uses ridged noise instead of a smooth detail
// field). Peaks roughly cap at SeaLevel + ContinentAmplitude + RidgedAmplitude.
public float MountainsContinentAmplitude { get; set; } = 40f;
public float MountainsRidgedAmplitude { get; set; } = 45f;
public float MountainsRidgedFrequency { get; set; } = 0.005f;
public int MountainsRidgedOctaves { get; set; } = 4;
// World-Y at/above which mountain tops render as snow.
public int MountainsSnowLine { get; set; } = 270;
#endregion -- World Gen: Biome Surface Heights --
#region -- Cave Generation --
// Spatial frequency of the 3D simplex cave-density field; higher = smaller,
// more frequent pockets.
public float CaveNoiseFrequency { get; set; } = 0.03f;
public float CaveNoiseFrequency { get; set; } = 0.03f;
// Density cutoff below which a solid voxel becomes air; higher = more cave.
public float CaveNoiseThreshold { get; set; } = -0.3f;
public float CaveNoiseThreshold { get; set; } = -0.3f;
// Edge length (blocks) of a worm-spawn grid cell; one worm candidate per cell.
public int WormCellSize { get; set; } = 64;
public int WormCellSize { get; set; } = 64;
// Per-cell chance out of 1000 that a worm spawns; 300 = 30%.
public int WormSpawnProbabilityPermille { get; set; } = 300;
public int WormSpawnProbabilityPermille { get; set; } = 300;
// Number of trace steps (≈ blocks) a worm travels.
public int WormMaxLength { get; set; } = 80;
// Worm tunnel radius bounds; interpolated + sine-modulated along the path
// to form bulges/chambers.
public float WormMinRadius { get; set; } = 1.5f;
public float WormMaxRadius { get; set; } = 3.5f;
public int WormMaxLength { get; set; } = 80;
// Worm tunnel radius bounds; interpolated + sine-modulated along the path to
// form bulges/chambers.
public float WormMinRadius { get; set; } = 1.5f;
public float WormMaxRadius { get; set; } = 3.5f;
// Ceiling: caves carve only at or below this world-Y ("no caves above").
// Default 256 = SeaLevel → caves stay below sea level, keeping the taller
// surface terrain solid. Raise toward WorldHeight-1 to allow surface caves.
public int MinCaveY { get; set; } = 256;
public int MinCaveY { get; set; } = 256;
#endregion -- Cave Generation --
#region -- Cave Lighting --
// Underground darkening: brightness fades from CaveDarkStartY down to
// CaveDarkEndY, never dropping below CaveMinBrightness.
// -- Cave lighting (fog-distance darkness) --
public float CaveDarkStartY { get; set; } = 264f; // WorldConstants.SeaLevel + 8
public float CaveDarkEndY { get; set; } = 224f; // WorldConstants.SeaLevel - 32
public float CaveMinBrightness { get; set; } = 0.15f;
public float CaveMinBrightness { get; set; } = 0.15f; // floor brightness deep underground (0–1)
#endregion -- Cave Lighting --
#region -- Debug Overlay --
// Pixel size of each font "pixel" in the on-screen debug text (biome + coords).
public int DebugOverlayTextScale { get; set; } = 3;
#endregion -- Debug Overlay --
}