fixed blending
Implementing noise blending
This commit is contained in:
@@ -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!(
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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(),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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)));
|
||||||
}
|
}
|
||||||
|
|||||||
Submodule game/main/assets updated: f809b7232a...2f1fb1ba3b
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user