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.
58 lines
2.4 KiB
C#
58 lines
2.4 KiB
C#
using VoxelEngine.Core;
|
|
|
|
namespace VoxelEngine.World.WorldGen;
|
|
|
|
public sealed class BiomeMap
|
|
{
|
|
private readonly NoiseSource _noise;
|
|
private readonly VoronoiCells _cells;
|
|
private readonly BiomeRegistry _biomes;
|
|
private readonly Configuration _cfg;
|
|
|
|
public BiomeMap(NoiseSource noise, VoronoiCells cells, BiomeRegistry biomes, Configuration cfg)
|
|
{
|
|
this._noise = noise;
|
|
this._cells = cells;
|
|
this._biomes = biomes;
|
|
this._cfg = cfg;
|
|
}
|
|
|
|
public int CellId(float worldX, float worldZ) => this._cells.Nearest(worldX, worldZ).Id;
|
|
|
|
public IBiome BiomeAt(float worldX, float worldZ)
|
|
=> this.BiomeForCell(this._cells.Nearest(worldX, worldZ));
|
|
|
|
// Climate -> biome, sampled at the cell centre so the biome is constant
|
|
// across the cell.
|
|
public IBiome BiomeForCell(VoronoiCells.Cell cell)
|
|
{
|
|
float temperature = this._noise.Temperature(cell.CenterX, cell.CenterZ);
|
|
float elevation = this._noise.Continent(cell.CenterX, cell.CenterZ);
|
|
float forest = this._noise.Forest(cell.CenterX, cell.CenterZ);
|
|
return Classify(temperature, elevation, forest, this._biomes, this._cfg);
|
|
}
|
|
|
|
// The biomes of the two nearest cells plus how far inside the nearer cell the
|
|
// point sits (SecondDist - FirstDist, in blocks; 0 exactly on the border).
|
|
// TerrainSampler uses this to ease height across biome borders.
|
|
public readonly record struct BiomeBlend(IBiome Near, IBiome Far, float BorderDistance);
|
|
|
|
public BiomeBlend NearestTwo(float worldX, float worldZ)
|
|
{
|
|
VoronoiCells.NearestPair p = this._cells.NearestTwo(worldX, worldZ);
|
|
return new BiomeBlend(
|
|
this.BiomeForCell(p.First),
|
|
this.BiomeForCell(p.Second),
|
|
p.SecondDist - p.FirstDist);
|
|
}
|
|
|
|
// Pure climate -> biome lookup. Thresholds in noise units (~[-1,1]).
|
|
public static IBiome Classify(float temperature, float elevation, float forest, BiomeRegistry biomes, Configuration cfg)
|
|
{
|
|
if (elevation > cfg.MountainsElevationThreshold) return biomes.Mountains; // high ground
|
|
if (temperature > cfg.DesertTemperatureThreshold) return biomes.Desert; // hot, low
|
|
if (temperature > cfg.ForestTemperatureThreshold && forest > cfg.ForestDensityThreshold) return biomes.Forest; // temperate, wooded
|
|
return biomes.Plains; // temperate/cold, low
|
|
}
|
|
}
|