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:
@@ -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 --
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user