chunk gen now tries nodes first, also messed around a lot w rendering
This commit is contained in:
+3
-115
@@ -1,17 +1,10 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
use bevy_ecs::{entity::Entity, system::Commands};
|
||||
use nalgebra::Vector3;
|
||||
use ndarray::{s, Array3, Axis};
|
||||
use simdnoise::NoiseBuilder;
|
||||
|
||||
use crate::{
|
||||
client::render::voxel::VoxelColor,
|
||||
common::component::{chunk, ChunkBundle, ChunkData, ChunkMesh, ChunkPos},
|
||||
util::{
|
||||
oct_tree::OctTree,
|
||||
thread::{ExitType, ThreadChannel, ThreadHandle},
|
||||
},
|
||||
common::component::{ChunkBundle, ChunkData, ChunkMesh, ChunkPos}, server::generation::generate_tree, util::
|
||||
thread::{ExitType, ThreadChannel, ThreadHandle}
|
||||
};
|
||||
|
||||
pub struct ChunkManager {
|
||||
@@ -114,32 +107,7 @@ fn chunk_loader_main(channel: ThreadChannel<ServerChunkMsg, ChunkLoaderMsg>) {
|
||||
let tree = ChunkData::from_tree(generate_tree(pos));
|
||||
let tree_time = std::time::Instant::now() - start;
|
||||
|
||||
// let start = std::time::Instant::now();
|
||||
// let mut data = generate(pos);
|
||||
// let data_time = std::time::Instant::now() - start;
|
||||
//
|
||||
// let start = std::time::Instant::now();
|
||||
// let shape = s![
|
||||
// 1..data.len_of(Axis(0)) - 1,
|
||||
// 1..data.len_of(Axis(1)) - 1,
|
||||
// 1..data.len_of(Axis(2)) - 1
|
||||
// ];
|
||||
// let mut slice = data.slice_mut(shape);
|
||||
// let mut iter = tree.into_iter();
|
||||
// slice.assign(&Array3::from_shape_fn(chunk::SHAPE, |_| {
|
||||
// iter.next().unwrap()
|
||||
// }));
|
||||
// let convert_time = std::time::Instant::now() - start;
|
||||
//
|
||||
// let start = std::time::Instant::now();
|
||||
// let mesh = ChunkMesh::from_data(data.map(|i| COLOR_MAP[*i as usize]).view());
|
||||
// let mesh_time = std::time::Instant::now() - start;
|
||||
//
|
||||
// println!(
|
||||
// "data: {:<5?} mesh: {:<5?} convert: {:<5?} tree: {:<5?}",
|
||||
// data_time, mesh_time, convert_time, tree_time
|
||||
// );
|
||||
println!("gen time: {:<5?}", tree_time);
|
||||
println!("gen time: {:<5?}; size: {}", tree_time, tree.raw().len());
|
||||
|
||||
channel.send(ServerChunkMsg::ChunkGenerated(GeneratedChunk {
|
||||
pos,
|
||||
@@ -154,83 +122,3 @@ fn chunk_loader_main(channel: ThreadChannel<ServerChunkMsg, ChunkLoaderMsg>) {
|
||||
}
|
||||
}
|
||||
|
||||
fn generate(pos: ChunkPos) -> Array3<u32> {
|
||||
let shape = [chunk::SIDE_LENGTH + 2; 3];
|
||||
if pos.y > 0 || pos.y < -1 {
|
||||
return Array3::from_elem(shape, 0);
|
||||
}
|
||||
let posf: Vector3<f32> = (pos.cast() * chunk::SIDE_LENGTH as f32) - Vector3::from_element(1.0);
|
||||
let (noise, min, max) = NoiseBuilder::gradient_2d_offset(
|
||||
posf.x,
|
||||
chunk::SIDE_LENGTH + 2,
|
||||
posf.z,
|
||||
chunk::SIDE_LENGTH + 2,
|
||||
)
|
||||
.with_seed(0)
|
||||
.with_freq(0.005)
|
||||
.generate();
|
||||
Array3::from_shape_fn(shape, |(x, y, z)| {
|
||||
generate_at(Vector3::new(x, y, z), posf, &noise, min, max)
|
||||
})
|
||||
}
|
||||
|
||||
fn generate_tree(pos: ChunkPos) -> OctTree {
|
||||
if pos.y > 0 || pos.y < -1 {
|
||||
return OctTree::from_leaf(0, 8);
|
||||
}
|
||||
let posf: Vector3<f32> = pos.cast() * chunk::SIDE_LENGTH as f32;
|
||||
let (noise, min, max) =
|
||||
NoiseBuilder::gradient_2d_offset(posf.x, chunk::SIDE_LENGTH, posf.z, chunk::SIDE_LENGTH)
|
||||
.with_seed(0)
|
||||
.with_freq(1.0 / (chunk::SIDE_LENGTH as f32))
|
||||
.generate();
|
||||
OctTree::from_fn_rec(&mut |p| generate_at(p, posf, &noise, min, max), chunk::SCALE)
|
||||
}
|
||||
|
||||
fn generate_at(p: Vector3<usize>, posf: Vector3<f32>, noise: &[f32], min: f32, max: f32) -> u32 {
|
||||
// 0 air 1 stone 2 "sand" 3 water
|
||||
let y = p.y as f32 + posf.y;
|
||||
// highest heights, 0.0 .. 1.0 relative to chunk size
|
||||
let [water, grass, top] = [0.18, 0.35, 0.5].map(|f| chunk::SIDE_LENGTH as f32 * f);
|
||||
let n = ((noise[p.x + p.z * chunk::SIDE_LENGTH] - min) / (max - min) * 2.0).exp2() * top * 0.25;
|
||||
if y < n {
|
||||
if y < water {
|
||||
1
|
||||
} else if y < grass {
|
||||
2
|
||||
} else {
|
||||
1
|
||||
}
|
||||
} else if y <= water {
|
||||
3
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
const COLOR_MAP: [VoxelColor; 4] = [
|
||||
VoxelColor {
|
||||
r: 0,
|
||||
g: 0,
|
||||
b: 0,
|
||||
a: 0,
|
||||
},
|
||||
VoxelColor {
|
||||
r: 150,
|
||||
g: 150,
|
||||
b: 150,
|
||||
a: 255,
|
||||
},
|
||||
VoxelColor {
|
||||
r: 100,
|
||||
g: 255,
|
||||
b: 100,
|
||||
a: 255,
|
||||
},
|
||||
VoxelColor {
|
||||
r: 100,
|
||||
g: 100,
|
||||
b: 255,
|
||||
a: 200,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
use nalgebra::Vector3;
|
||||
use simdnoise::NoiseBuilder;
|
||||
|
||||
use crate::{
|
||||
common::component::{chunk, ChunkPos},
|
||||
util::oct_tree::OctTree,
|
||||
};
|
||||
|
||||
pub fn generate_tree(pos: ChunkPos) -> OctTree {
|
||||
if pos.y > 0 || pos.y < -1 {
|
||||
return OctTree::from_leaf(0, 8);
|
||||
}
|
||||
let posf: Vector3<f32> = pos.cast() * chunk::SIDE_LENGTH as f32;
|
||||
let noise1 = generate_noise_map(0, 1.0, posf, chunk::SCALE, &mut |v: f32| {
|
||||
(v * 2.0).exp2() * TOP * 0.25
|
||||
});
|
||||
let noise2 = generate_noise_map(1, 50.0, posf, chunk::SCALE, &mut |v: f32| v * 20.0 + GRASS);
|
||||
OctTree::from_fn_rec(
|
||||
&mut |p| generate_leaf(p, posf, (&noise1.base, &noise2.base)),
|
||||
&mut |p, lvl| generate_node(p, lvl, posf, (&noise1, &noise2)),
|
||||
chunk::SCALE,
|
||||
)
|
||||
}
|
||||
|
||||
const WATER: f32 = 0.18 * chunk::SIDE_LENGTH as f32;
|
||||
const GRASS: f32 = 0.35 * chunk::SIDE_LENGTH as f32;
|
||||
const TOP: f32 = 0.5 * chunk::SIDE_LENGTH as f32;
|
||||
|
||||
// 0 air 1 stone 2 grass 3 water
|
||||
fn generate_leaf(p: Vector3<usize>, posf: Vector3<f32>, noise: (&[f32], &[f32])) -> u32 {
|
||||
let y = p.y as f32 + posf.y;
|
||||
let n = noise.0[p.x + p.z * chunk::SIDE_LENGTH];
|
||||
let n2 = noise.1[p.x + p.z * chunk::SIDE_LENGTH];
|
||||
if y < n {
|
||||
if y < WATER {
|
||||
1
|
||||
} else if y < n2 {
|
||||
2
|
||||
} else {
|
||||
1
|
||||
}
|
||||
} else if y <= WATER {
|
||||
3
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
// 0 air 1 stone 2 grass 3 water
|
||||
fn generate_node(
|
||||
p: Vector3<usize>,
|
||||
scale: u32,
|
||||
posf: Vector3<f32>,
|
||||
noise: (&NoiseMap, &NoiseMap),
|
||||
) -> Option<u32> {
|
||||
let side_len = 2usize.pow(scale);
|
||||
let y = NumRange {
|
||||
min: p.y as f32 + posf.y,
|
||||
max: (p.y + side_len - 1) as f32 + posf.y,
|
||||
};
|
||||
let l = scale as usize - 1;
|
||||
let i = (p.x >> scale) + (p.z >> scale) * (chunk::SIDE_LENGTH / side_len);
|
||||
let n = &noise.0.levels[l][i];
|
||||
let n2 = &noise.1.levels[l][i];
|
||||
Some(if y.max < n.min {
|
||||
if y.max < WATER {
|
||||
1
|
||||
} else if y.max < n2.min && y.min >= WATER {
|
||||
2
|
||||
} else if y.min > n2.max {
|
||||
1
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
} else if y.max <= WATER && y.min > n.max {
|
||||
3
|
||||
} else if y.min > WATER && y.min > n.max {
|
||||
0
|
||||
} else {
|
||||
return None;
|
||||
})
|
||||
}
|
||||
|
||||
fn generate_noise_map(
|
||||
seed: i32,
|
||||
freq: f32,
|
||||
posf: Vector3<f32>,
|
||||
levels: u32,
|
||||
adjust: &mut impl FnMut(f32) -> f32,
|
||||
) -> NoiseMap {
|
||||
let mut size = 2usize.pow(levels);
|
||||
let (mut base, min, max) = NoiseBuilder::gradient_2d_offset(posf.x, size, posf.z, size)
|
||||
.with_seed(seed)
|
||||
.with_freq(freq / (size as f32))
|
||||
.generate();
|
||||
for v in &mut base {
|
||||
*v = adjust((*v - min) / (max - min));
|
||||
}
|
||||
let first_len = base.len() / 4;
|
||||
let mut first = Vec::with_capacity(first_len);
|
||||
for y in (0..size).step_by(2) {
|
||||
for x in (0..size).step_by(2) {
|
||||
let a = base[x + y * size];
|
||||
let b = base[x + 1 + y * size];
|
||||
let c = base[x + (y + 1) * size];
|
||||
let d = base[x + 1 + (y + 1) * size];
|
||||
first.push(NumRange {
|
||||
min: a.min(b).min(c).min(d),
|
||||
max: a.max(b).max(c).max(d),
|
||||
})
|
||||
}
|
||||
}
|
||||
let mut arr = vec![first];
|
||||
for l in 1..levels as usize {
|
||||
size /= 2;
|
||||
let prev = &arr[l - 1];
|
||||
let mut new = Vec::with_capacity(prev.len() / 4);
|
||||
for y in (0..size).step_by(2) {
|
||||
for x in (0..size).step_by(2) {
|
||||
let a = &prev[x + y * size];
|
||||
let b = &prev[x + 1 + y * size];
|
||||
let c = &prev[x + (y + 1) * size];
|
||||
let d = &prev[x + 1 + (y + 1) * size];
|
||||
new.push(NumRange {
|
||||
min: a.min.min(b.min).min(c.min).min(d.min),
|
||||
max: a.max.max(b.max).max(c.max).max(d.max),
|
||||
})
|
||||
}
|
||||
}
|
||||
arr.push(new);
|
||||
}
|
||||
NoiseMap { base, levels: arr }
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct NoiseMap {
|
||||
levels: Vec<Vec<NumRange>>,
|
||||
base: Vec<f32>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct NumRange {
|
||||
min: f32,
|
||||
max: f32,
|
||||
}
|
||||
@@ -3,6 +3,7 @@ mod client;
|
||||
mod rsc;
|
||||
mod system;
|
||||
mod test;
|
||||
mod generation;
|
||||
|
||||
pub use client::*;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user