From ba2dcf71294006e7d8e1b6e1540f53eda0714033 Mon Sep 17 00:00:00 2001 From: Amatsugu Date: Sun, 7 Jul 2024 10:51:02 -0400 Subject: [PATCH] Biome blending Dithering to biome edges --- engine/world_generation/src/heightmap.rs | 18 +++++---- engine/world_generation/src/map/biome_map.rs | 41 ++++++++++++++++++++ engine/world_generation/src/map/chunk.rs | 2 + engine/world_generation/src/map/config.rs | 7 ++-- game/main/assets | 2 +- game/main/src/map_rendering/map_init.rs | 13 ++++--- game/main/src/utlis/chunk_utils.rs | 4 +- 7 files changed, 68 insertions(+), 19 deletions(-) diff --git a/engine/world_generation/src/heightmap.rs b/engine/world_generation/src/heightmap.rs index c924af8..acabd26 100644 --- a/engine/world_generation/src/heightmap.rs +++ b/engine/world_generation/src/heightmap.rs @@ -64,7 +64,7 @@ pub fn generate_biome_chunk( let moisture = sample_point( x as f64 + chunk_x as f64 * Chunk::SIZE as f64, z as f64 + chunk_y as f64 * Chunk::SIZE as f64, - &cfg.moisture_layer, + &cfg.moisture_noise, &noise_m, cfg.size.as_vec2(), cfg.border_size, @@ -72,7 +72,7 @@ pub fn generate_biome_chunk( let temperature = sample_point( x as f64 + chunk_x as f64 * Chunk::SIZE as f64, z as f64 + chunk_y as f64 * Chunk::SIZE as f64, - &cfg.temperature_layer, + &cfg.temperature_noise, &noise_t, cfg.size.as_vec2(), cfg.border_size, @@ -80,7 +80,7 @@ pub fn generate_biome_chunk( let continentality = sample_point( x as f64 + chunk_x as f64 * Chunk::SIZE as f64, z as f64 + chunk_y as f64 * Chunk::SIZE as f64, - &cfg.continent_layer, + &cfg.continent_noise, &noise_c, cfg.size.as_vec2(), cfg.border_size, @@ -109,8 +109,9 @@ pub fn generate_chunk( biome_chunk: &BiomeChunk, biome_painter: &BiomePainter, ) -> Chunk { - let mut result: [f32; Chunk::SIZE * Chunk::SIZE] = [0.; Chunk::SIZE * Chunk::SIZE]; - let mut data = [BiomeData::default(); Chunk::SIZE * Chunk::SIZE]; + let mut result: [f32; Chunk::SIZE * Chunk::SIZE] = [0.; Chunk::AREA]; + let mut data = [BiomeData::default(); Chunk::AREA]; + let mut biome_ids = [0; Chunk::AREA]; let noise = SuperSimplex::new(seed); for z in 0..Chunk::SIZE { for x in 0..Chunk::SIZE { @@ -132,13 +133,16 @@ pub fn generate_chunk( cfg.border_size, ) * blend; } - result[x + z * Chunk::SIZE] = sample; - data[x + z * Chunk::SIZE] = biome_data.clone(); + let idx = x + z * Chunk::SIZE; + biome_ids[idx] = biome_chunk.get_biome_id_dithered(x, z, &noise, cfg.biome_dither); + result[idx] = sample; + data[idx] = biome_data.clone(); } } return Chunk { heights: result, biome_data: data, + biome_id: biome_ids, chunk_offset: IVec2::new(chunk_x as i32, chunk_z as i32), ..default() }; diff --git a/engine/world_generation/src/map/biome_map.rs b/engine/world_generation/src/map/biome_map.rs index 0b6fe41..4a5e536 100644 --- a/engine/world_generation/src/map/biome_map.rs +++ b/engine/world_generation/src/map/biome_map.rs @@ -1,4 +1,5 @@ use bevy::math::{UVec2, Vec3}; +use noise::NoiseFn; use rayon::iter::{IntoParallelIterator, ParallelIterator}; use super::chunk::Chunk; @@ -120,6 +121,15 @@ impl BiomeMap { return Some(chunk.get_biome(x as usize - cx * Chunk::SIZE, y as usize - cy * Chunk::SIZE)); } + pub fn get_biome_id(&self, x: usize, y: usize) -> usize { + let cx = (x as f32 / Chunk::SIZE as f32).floor() as usize; + let cy = (y as f32 / Chunk::SIZE as f32).floor() as usize; + + let chunk = &self.chunks[cx + cy * self.size.x as usize]; + + return chunk.get_biome_id(x - (cx * Chunk::SIZE), y - (cy * Chunk::SIZE)); + } + pub fn get_biome_data(&self, x: usize, y: usize) -> &BiomeData { let cx = (x as f32 / Chunk::SIZE as f32).floor() as usize; let cy = (y as f32 / Chunk::SIZE as f32).floor() as usize; @@ -145,6 +155,37 @@ impl BiomeChunk { pub fn get_biome_data(&self, x: usize, y: usize) -> &BiomeData { return &self.data[x + y * Chunk::SIZE]; } + + pub fn get_biome_id(&self, x: usize, y: usize) -> usize { + let b = self.get_biome(x, y); + let mut max = 0.; + let mut idx = 0; + for i in 0..b.len() { + let blend = b[i]; + if blend > max { + max = blend; + idx = i; + } + } + return idx; + } + + pub fn get_biome_id_dithered(&self, x: usize, y: usize, noise: &impl NoiseFn, scale: f64) -> usize { + let cur_id = self.get_biome_id(x, y); + let b = self.get_biome(x, y); + let n = (noise.get([x as f64 / scale, y as f64 / scale]) as f32) * b[cur_id]; + for i in 0..b.len() { + let blend = b[i]; + if blend == 0. { + continue; + } + if n < blend { + return i; + } + } + + return cur_id; + } } #[cfg(test)] diff --git a/engine/world_generation/src/map/chunk.rs b/engine/world_generation/src/map/chunk.rs index edf414a..d59282e 100644 --- a/engine/world_generation/src/map/chunk.rs +++ b/engine/world_generation/src/map/chunk.rs @@ -8,6 +8,7 @@ pub struct Chunk { pub heights: [f32; Chunk::AREA], pub textures: [[u32; 2]; Chunk::AREA], pub biome_data: [BiomeData; Chunk::AREA], + pub biome_id: [usize; Chunk::AREA], pub chunk_offset: IVec2, } @@ -17,6 +18,7 @@ impl Default for Chunk { heights: [0.; Chunk::AREA], textures: [[0; 2]; Chunk::AREA], biome_data: [BiomeData::default(); Chunk::AREA], + biome_id: [0; Chunk::AREA], chunk_offset: Default::default(), } } diff --git a/engine/world_generation/src/map/config.rs b/engine/world_generation/src/map/config.rs index f7b07db..27582c9 100644 --- a/engine/world_generation/src/map/config.rs +++ b/engine/world_generation/src/map/config.rs @@ -10,9 +10,10 @@ pub struct GenerationConfig { pub sea_level: f64, pub border_size: f32, pub biome_blend: usize, - pub moisture_layer: NoiseConfig, - pub temperature_layer: NoiseConfig, - pub continent_layer: NoiseConfig, + pub biome_dither: f64, + pub moisture_noise: NoiseConfig, + pub temperature_noise: NoiseConfig, + pub continent_noise: NoiseConfig, pub size: UVec2, } diff --git a/game/main/assets b/game/main/assets index 2f1fb1b..d7389cf 160000 --- a/game/main/assets +++ b/game/main/assets @@ -1 +1 @@ -Subproject commit 2f1fb1ba3b08ea323d596f585952c8fd804f400f +Subproject commit d7389cf5b1dc0764ffe77ccf822aefdb6417f6d7 diff --git a/game/main/src/map_rendering/map_init.rs b/game/main/src/map_rendering/map_init.rs index 04ce150..06e5b42 100644 --- a/game/main/src/map_rendering/map_init.rs +++ b/game/main/src/map_rendering/map_init.rs @@ -207,8 +207,9 @@ fn create_heightmap( ) { let config = GenerationConfig { biome_blend: 16, - continent_layer: NoiseConfig { - scale: 450., + biome_dither: 16., + continent_noise: NoiseConfig { + scale: 500., layers: vec![GeneratorLayer { base_roughness: 2.14, roughness: 0.87, @@ -222,8 +223,8 @@ fn create_heightmap( first_layer_mask: false, }], }, - moisture_layer: NoiseConfig { - scale: 450., + moisture_noise: NoiseConfig { + scale: 500., layers: vec![GeneratorLayer { base_roughness: 2.14, roughness: 0.87, @@ -237,8 +238,8 @@ fn create_heightmap( first_layer_mask: false, }], }, - temperature_layer: NoiseConfig { - scale: 450., + temperature_noise: NoiseConfig { + scale: 500., layers: vec![GeneratorLayer { base_roughness: 2.14, roughness: 0.87, diff --git a/game/main/src/utlis/chunk_utils.rs b/game/main/src/utlis/chunk_utils.rs index 0433848..ea0d5e1 100644 --- a/game/main/src/utlis/chunk_utils.rs +++ b/game/main/src/utlis/chunk_utils.rs @@ -38,8 +38,8 @@ pub fn paint_chunk( for x in 0..Chunk::SIZE { let idx = x + z * Chunk::SIZE; let height = chunk.heights[idx]; - let biome_data = &chunk.biome_data[idx]; - let biome = painter.sample_biome(biome_data); + let biome_id = chunk.biome_id[idx]; + let biome = &painter.biomes[biome_id]; let mapper = mappers.get(biome.tile_mapper.clone()); let tile_handle = mapper.unwrap().sample_tile(height); let tile = tiles.get(tile_handle).unwrap();