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 } }