fixed blending

Implementing noise blending
This commit is contained in:
2024-07-07 00:00:34 -04:00
parent 97f2497940
commit 8e92df8008
6 changed files with 85 additions and 41 deletions

View File

@@ -64,6 +64,22 @@ impl BiomePainter {
return biome; return biome;
} }
pub fn sample_biome_index(&self, data: &BiomeData) -> usize {
assert!(self.biomes.length() != 0, "There are no biomes");
let mut biome = 0;
let mut dist = f32::INFINITY;
for i in 0..self.biomes.len() {
let d = self.biomes[i].distance(data.into());
if d < dist {
biome = i;
dist = d;
}
}
return biome;
}
} }
create_asset_loader!( create_asset_loader!(

View File

@@ -1,4 +1,4 @@
use bevy::math::IVec2; use bevy::math::{IVec2, UVec2};
use bevy::prelude::{FloatExt, Vec2}; use bevy::prelude::{FloatExt, Vec2};
use bevy::utils::default; use bevy::utils::default;
use bevy::utils::petgraph::data; use bevy::utils::petgraph::data;
@@ -10,7 +10,7 @@ use crate::map::biome_map::{self, BiomeChunk, BiomeData, BiomeMap};
use crate::prelude::*; use crate::prelude::*;
pub fn generate_heightmap(cfg: &GenerationConfig, seed: u32, painter: &BiomePainter) -> Map { pub fn generate_heightmap(cfg: &GenerationConfig, seed: u32, painter: &BiomePainter) -> Map {
let biomes = &generate_biomes(cfg, seed); let biomes = &generate_biomes(cfg, seed, painter);
// let mut chunks: Vec<Chunk> = Vec::with_capacity(cfg.size.length_squared() as usize); // let mut chunks: Vec<Chunk> = Vec::with_capacity(cfg.size.length_squared() as usize);
let chunks = (0..cfg.size.y) let chunks = (0..cfg.size.y)
.into_par_iter() .into_par_iter()
@@ -29,13 +29,13 @@ pub fn generate_heightmap(cfg: &GenerationConfig, seed: u32, painter: &BiomePain
}; };
} }
pub fn generate_biomes(cfg: &GenerationConfig, seed: u32) -> BiomeMap { pub fn generate_biomes(cfg: &GenerationConfig, seed: u32, biome_painter: &BiomePainter) -> BiomeMap {
let mut map = BiomeMap::new(cfg.size, 8); let mut map = BiomeMap::new(cfg.size, biome_painter.biomes.len());
map.chunks = (0..cfg.size.y) map.chunks = (0..cfg.size.y)
.into_par_iter() .into_par_iter()
.flat_map(|y| { .flat_map(|y| {
(0..cfg.size.x).into_par_iter().map(move |x| { (0..cfg.size.x).into_par_iter().map(move |x| {
return generate_biome_chunk(x as usize, y as usize, cfg, seed); return generate_biome_chunk(x as usize, y as usize, cfg, seed, biome_painter);
}) })
}) })
.collect(); .collect();
@@ -43,8 +43,15 @@ pub fn generate_biomes(cfg: &GenerationConfig, seed: u32) -> BiomeMap {
return map; return map;
} }
pub fn generate_biome_chunk(chunk_x: usize, chunk_y: usize, cfg: &GenerationConfig, seed: u32) -> BiomeChunk { pub fn generate_biome_chunk(
chunk_x: usize,
chunk_y: usize,
cfg: &GenerationConfig,
seed: u32,
biome_painter: &BiomePainter,
) -> BiomeChunk {
let mut chunk = BiomeChunk { let mut chunk = BiomeChunk {
offset: UVec2::new(chunk_x as u32, chunk_y as u32),
data: [BiomeData::default(); Chunk::AREA], data: [BiomeData::default(); Chunk::AREA],
tiles: Vec::with_capacity(Chunk::AREA), tiles: Vec::with_capacity(Chunk::AREA),
}; };
@@ -78,11 +85,16 @@ pub fn generate_biome_chunk(chunk_x: usize, chunk_y: usize, cfg: &GenerationConf
cfg.size.as_vec2(), cfg.size.as_vec2(),
cfg.border_size, cfg.border_size,
); );
chunk.data[x + z * Chunk::SIZE] = BiomeData { let data = BiomeData {
moisture, moisture: moisture.clamp(0., 100.),
temperature, temperature: temperature.clamp(0., 100.),
continentality, continentality: continentality.clamp(0., 100.),
}; };
let mut b = vec![0.; biome_painter.biomes.len()];
b[biome_painter.sample_biome_index(&data)] = 1.;
chunk.data[x + z * Chunk::SIZE] = data;
chunk.tiles.push(b);
} }
} }
@@ -103,15 +115,23 @@ pub fn generate_chunk(
for z in 0..Chunk::SIZE { for z in 0..Chunk::SIZE {
for x in 0..Chunk::SIZE { for x in 0..Chunk::SIZE {
let biome_data = biome_chunk.get_biome_data(x, z); let biome_data = biome_chunk.get_biome_data(x, z);
let biome = biome_painter.sample_biome(biome_data); let biome_blend = biome_chunk.get_biome(x, z);
let sample = sample_point( let mut sample = 0.;
x as f64 + chunk_x as f64 * Chunk::SIZE as f64, for i in 0..biome_blend.len() {
z as f64 + chunk_z as f64 * Chunk::SIZE as f64, let blend = biome_blend[i];
&biome.noise, if blend == 0. {
&noise, continue;
cfg.size.as_vec2(), }
cfg.border_size, let biome = &biome_painter.biomes[i];
); sample += sample_point(
x as f64 + chunk_x as f64 * Chunk::SIZE as f64,
z as f64 + chunk_z as f64 * Chunk::SIZE as f64,
&biome.noise,
&noise,
cfg.size.as_vec2(),
cfg.border_size,
) * blend;
}
result[x + z * Chunk::SIZE] = sample; result[x + z * Chunk::SIZE] = sample;
data[x + z * Chunk::SIZE] = biome_data.clone(); data[x + z * Chunk::SIZE] = biome_data.clone();
} }

View File

@@ -6,6 +6,7 @@ use super::chunk::Chunk;
pub struct BiomeMap { pub struct BiomeMap {
pub height: usize, pub height: usize,
pub width: usize, pub width: usize,
pub size: UVec2,
pub biome_count: usize, pub biome_count: usize,
pub chunks: Vec<BiomeChunk>, pub chunks: Vec<BiomeChunk>,
} }
@@ -33,6 +34,7 @@ impl BiomeMap {
pub fn new(size: UVec2, biome_count: usize) -> Self { pub fn new(size: UVec2, biome_count: usize) -> Self {
let len = size.x as usize * size.y as usize * Chunk::AREA; let len = size.x as usize * size.y as usize * Chunk::AREA;
return BiomeMap { return BiomeMap {
size: size,
height: size.y as usize * Chunk::SIZE, height: size.y as usize * Chunk::SIZE,
width: size.x as usize * Chunk::SIZE, width: size.x as usize * Chunk::SIZE,
biome_count, biome_count,
@@ -57,7 +59,10 @@ impl BiomeMap {
.map(|y| { .map(|y| {
let mut new_tiles = Vec::with_capacity(self.width); let mut new_tiles = Vec::with_capacity(self.width);
for x in 0..Chunk::SIZE { for x in 0..Chunk::SIZE {
let kernel = self.get_kernel(x as i32, y as i32); let tx = x as u32 + chunk.offset.x * Chunk::SIZE as u32;
let ty = y as u32 + chunk.offset.y * Chunk::SIZE as u32;
let kernel = self.get_kernel(tx as i32, ty as i32);
let r = kernel let r = kernel
.iter() .iter()
.filter_map(|f| *f) .filter_map(|f| *f)
@@ -77,6 +82,7 @@ impl BiomeMap {
.flatten() .flatten()
.collect(); .collect();
return BiomeChunk { return BiomeChunk {
offset: chunk.offset,
tiles, tiles,
data: chunk.data, data: chunk.data,
}; };
@@ -107,27 +113,27 @@ impl BiomeMap {
return None; return None;
} }
let cx = x as usize / Chunk::SIZE; let cx = (x as f32 / Chunk::SIZE as f32).floor() as usize;
let cy = y as usize / Chunk::SIZE; let cy = (y as f32 / Chunk::SIZE as f32).floor() as usize;
let chunk = &self.chunks[cx + cy * Chunk::SIZE];
let chunk = &self.chunks[cx + cy * self.size.x as usize];
return Some(chunk.get_biome(x as usize - cx * Chunk::SIZE, y as usize - cy * Chunk::SIZE)); return Some(chunk.get_biome(x as usize - cx * Chunk::SIZE, y as usize - cy * Chunk::SIZE));
} }
pub fn get_biome_data(&self, x: usize, y: usize) -> &BiomeData { pub fn get_biome_data(&self, x: usize, y: usize) -> &BiomeData {
let cx = x / Chunk::SIZE; let cx = (x as f32 / Chunk::SIZE as f32).floor() as usize;
let cy = y / Chunk::SIZE; let cy = (y as f32 / Chunk::SIZE as f32).floor() as usize;
let chunk = &self.chunks[cx + cy * Chunk::SIZE]; let chunk = &self.chunks[cx + cy * self.size.x as usize];
return chunk.get_biome_data(x - cx * Chunk::SIZE, y - cy * Chunk::SIZE); return chunk.get_biome_data(x - (cx * Chunk::SIZE), y - (cy * Chunk::SIZE));
} }
} }
#[derive(Clone)] #[derive(Clone)]
pub struct BiomeChunk { pub struct BiomeChunk {
pub tiles: Vec<Vec<f32>>, pub tiles: Vec<Vec<f32>>,
pub offset: UVec2,
pub data: [BiomeData; Chunk::AREA], pub data: [BiomeData; Chunk::AREA],
} }
@@ -148,9 +154,9 @@ mod tests {
#[test] #[test]
fn biome_blend() { fn biome_blend() {
let mut biome = BiomeMap::new(UVec2::ONE * 16, 8); let mut biome = BiomeMap::new(UVec2::splat(4), 8);
let w = biome.width / Chunk::SIZE; let w = biome.size.x as usize;
let h = biome.height / Chunk::SIZE; let h = biome.size.y as usize;
for y in 0..h { for y in 0..h {
for x in 0..w { for x in 0..w {
@@ -162,10 +168,12 @@ mod tests {
} }
biome.blend(8); biome.blend(8);
assert!(biome.chunks.iter().all(|f| f.tiles.len() == Chunk::AREA), "Data Lost");
} }
fn generate_chunk(x: usize, y: usize, biome: Vec<f32>) -> BiomeChunk { fn generate_chunk(x: usize, y: usize, biome: Vec<f32>) -> BiomeChunk {
let chunk = BiomeChunk { let chunk = BiomeChunk {
offset: UVec2::new(x as u32, y as u32),
data: [BiomeData::default(); Chunk::AREA], data: [BiomeData::default(); Chunk::AREA],
tiles: (0..Chunk::AREA).into_iter().map(|_| biome.clone()).collect(), tiles: (0..Chunk::AREA).into_iter().map(|_| biome.clone()).collect(),
}; };

View File

@@ -16,7 +16,7 @@ impl Plugin for BuildingPugin {
app.insert_resource(BuildQueue::default()); app.insert_resource(BuildQueue::default());
app.add_systems(Startup, init); app.add_systems(Startup, init);
app.add_systems(Update, hq_placement.run_if(in_state(GameplayState::PlaceHQ))); //app.add_systems(Update, hq_placement.run_if(in_state(GameplayState::PlaceHQ)));
app.add_systems(PreUpdate, process_build_queue.run_if(in_state(GameplayState::Playing))); app.add_systems(PreUpdate, process_build_queue.run_if(in_state(GameplayState::Playing)));
} }

View File

@@ -206,19 +206,19 @@ fn create_heightmap(
biome_painter: Res<BiomePainter>, biome_painter: Res<BiomePainter>,
) { ) {
let config = GenerationConfig { let config = GenerationConfig {
biome_blend: 3, biome_blend: 16,
continent_layer: NoiseConfig { continent_layer: NoiseConfig {
scale: 450., scale: 450.,
layers: vec![GeneratorLayer { layers: vec![GeneratorLayer {
base_roughness: 2.14, base_roughness: 2.14,
roughness: 0.87, roughness: 0.87,
strength: 100., strength: 100.,
min_value: -0.2, min_value: 0.,
persistence: 0.77, persistence: 0.77,
is_rigid: false, is_rigid: false,
weight: 0., weight: 0.,
weight_multi: 0., weight_multi: 0.,
layers: 4, layers: 1,
first_layer_mask: false, first_layer_mask: false,
}], }],
}, },
@@ -228,12 +228,12 @@ fn create_heightmap(
base_roughness: 2.14, base_roughness: 2.14,
roughness: 0.87, roughness: 0.87,
strength: 100., strength: 100.,
min_value: -0.2, min_value: 0.,
persistence: 0.77, persistence: 0.77,
is_rigid: false, is_rigid: false,
weight: 0., weight: 0.,
weight_multi: 0., weight_multi: 0.,
layers: 4, layers: 1,
first_layer_mask: false, first_layer_mask: false,
}], }],
}, },
@@ -243,18 +243,18 @@ fn create_heightmap(
base_roughness: 2.14, base_roughness: 2.14,
roughness: 0.87, roughness: 0.87,
strength: 100., strength: 100.,
min_value: -0.2, min_value: 0.,
persistence: 0.77, persistence: 0.77,
is_rigid: false, is_rigid: false,
weight: 0., weight: 0.,
weight_multi: 0., weight_multi: 0.,
layers: 4, layers: 1,
first_layer_mask: false, first_layer_mask: false,
}], }],
}, },
sea_level: 8.5, sea_level: 8.5,
border_size: 64., border_size: 64.,
size: UVec2::splat(1024 / Chunk::SIZE as u32), size: UVec2::splat(16),
// size: UVec2::splat(1), // size: UVec2::splat(1),
}; };
let heightmap = generate_heightmap(&config, 42069, &biome_painter); let heightmap = generate_heightmap(&config, 42069, &biome_painter);