From 9fc4594b9ad0a5393c5897ce79a5f246d6ec6252 Mon Sep 17 00:00:00 2001 From: Jarrod Doyle Date: Sat, 13 Apr 2024 21:25:27 +0100 Subject: [PATCH] Experiment with using ndarray to represent chunk voxels --- src/voxel/world/chunk.rs | 143 +++++++++++++++++++++++++++------------ 1 file changed, 98 insertions(+), 45 deletions(-) diff --git a/src/voxel/world/chunk.rs b/src/voxel/world/chunk.rs index b6a1017..031aef9 100644 --- a/src/voxel/world/chunk.rs +++ b/src/voxel/world/chunk.rs @@ -1,3 +1,6 @@ +use ndarray::{s, Array3}; +use wgpu::naga::FastHashSet; + use crate::math; use super::{GenerationSettings, Voxel}; @@ -11,8 +14,9 @@ pub struct ChunkSettings { #[derive(Debug)] pub struct Chunk { settings: ChunkSettings, + genned_blocks: FastHashSet<(usize, usize, usize)>, noise: Vec, - blocks: Vec>, + blocks: Array3, } impl Chunk { @@ -42,13 +46,21 @@ impl Chunk { .generate() .0; - let num_blocks = dims.x * dims.y * dims.z; - let blocks = vec![vec![]; num_blocks as usize]; + let genned_blocks = FastHashSet::default(); + + let shape = chunk_settings.dimensions * chunk_settings.block_dimensions; + let num_voxels = shape.x * shape.y * shape.z; + let blocks = Array3::from_shape_vec( + (shape.x as usize, shape.y as usize, shape.z as usize), + vec![Voxel::Empty; num_voxels as usize], + ) + .unwrap(); Self { settings: chunk_settings, noise, blocks, + genned_blocks, } } @@ -57,57 +69,84 @@ impl Chunk { region_start: glam::UVec3, region_dims: glam::UVec3, ) -> Vec { - let mut voxels = vec![]; - let start = region_start; let end = region_start + region_dims; let dims = self.settings.dimensions * self.settings.block_dimensions; assert!(end.x <= dims.x && end.y <= dims.y && end.z <= dims.z); - for z in (start.z)..(end.z) { - for y in (start.y)..(end.y) { - for x in (start.x)..(end.x) { - voxels.push(self.get_voxel(glam::uvec3(x, y, z))); + // Check that all the blocks needed are generated and generated them if needed + // TODO: Don't hardcode this division!! + let start_block = start / 8; + let end_block = end / 8; + for z in start_block.z..(end_block.z) { + for y in (start_block.y)..(end_block.y) { + for x in (start_block.x)..(end_block.x) { + if !self + .genned_blocks + .contains(&(x as usize, y as usize, z as usize)) + { + self.gen_block(glam::uvec3(x, y, z)); + } } } } - voxels + // + let region = self + .blocks + .slice(s![ + (start.x as usize)..(end.x as usize), + (start.y as usize)..(end.y as usize), + (start.z as usize)..(end.z as usize) + ]) + .to_owned() + .into_raw_vec(); + // dbg!(®ion); + region } - pub fn get_voxel(&mut self, pos: glam::UVec3) -> Voxel { - let dims = self.settings.dimensions * self.settings.block_dimensions; - debug_assert!(pos.x < dims.x && pos.y < dims.y && pos.z < dims.z); + // pub fn get_voxel(&mut self, pos: glam::UVec3) -> Voxel { + // let dims = self.settings.dimensions * self.settings.block_dimensions; + // debug_assert!(pos.x < dims.x && pos.y < dims.y && pos.z < dims.z); - let block_pos = pos / self.settings.block_dimensions; - let block_idx = math::to_1d_index(block_pos, self.settings.dimensions); - let mut block = &self.blocks[block_idx]; - if block.is_empty() { - self.gen_block(block_pos, block_idx); - block = &self.blocks[block_idx] - } + // let block_pos = pos / self.settings.block_dimensions; + // let block_idx = math::to_1d_index(block_pos, self.settings.dimensions); + // let mut block = &self.blocks[block_idx]; + // if block.is_empty() { + // self.gen_block(block_pos, block_idx); + // block = &self.blocks[block_idx] + // } - let local_pos = pos % self.settings.block_dimensions; - let local_idx = math::to_1d_index(local_pos, self.settings.block_dimensions); - block[local_idx] - } + // let local_pos = pos % self.settings.block_dimensions; + // let local_idx = math::to_1d_index(local_pos, self.settings.block_dimensions); + // block[local_idx] + // } pub fn get_block(&mut self, pos: glam::UVec3) -> Vec { let dims = self.settings.dimensions; assert!(pos.x < dims.x && pos.y < dims.y && pos.z < dims.z); - let block_idx = math::to_1d_index(pos, dims); - let mut block = &self.blocks[block_idx]; - if block.is_empty() { - self.gen_block(pos, block_idx); - block = &self.blocks[block_idx] + let gen_key = &(pos.x as usize, pos.y as usize, pos.z as usize); + if !self.genned_blocks.contains(gen_key) { + self.gen_block(pos); } - block.to_owned() + let block_dims = self.settings.block_dimensions; + let start = pos * block_dims; + let end = start + block_dims; + let region = self + .blocks + .slice(s![ + (start.x as usize)..(end.x as usize), + (start.y as usize)..(end.y as usize), + (start.z as usize)..(end.z as usize) + ]) + .to_owned() + .into_raw_vec(); + region } - pub fn gen_block(&mut self, block_pos: glam::UVec3, block_idx: usize) { - let block = &mut self.blocks[block_idx]; + pub fn gen_block(&mut self, block_pos: glam::UVec3) { let noise_dims = self.settings.dimensions + glam::uvec3(1, 1, 1); // Extract relevant noise values from the chunk @@ -126,32 +165,46 @@ impl Chunk { } // If all the corners are negative, then all the interpolated values - // will be negative too. In that case we can just fill with empty. - if block_sign == -8.0 { - block.resize(512, Voxel::Empty); - } else { + // will be negative too. The chunk voxels are initialised as empty already + // so we only need to modify them if we have at least one positive corner + if block_sign != -8.0 { let mut vals = [0.0f32; 512]; math::tri_lerp_block(&noise_vals, &[8, 8, 8], &mut vals); + let block_dims = self.settings.block_dimensions; + let start = block_pos * block_dims; + let end = start + block_dims; + let mut block = self.blocks.slice_mut(s![ + (start.x as usize)..(end.x as usize), + (start.y as usize)..(end.y as usize), + (start.z as usize)..(end.z as usize) + ]); + // TODO: Better voxel colours - let mut idx = 0; - for z in 0..8 { - for y in 0..8 { - for x in 0..8 { - let val = vals[idx]; - idx += 1; + let mut val_idx = 0; + for z in 0..block_dims.z { + for y in 0..block_dims.y { + for x in 0..block_dims.x { + let val = vals[val_idx]; + val_idx += 1; if val > 0.0 { let r = ((x + 1) * 32 - 1) as u8; let g = ((y + 1) * 32 - 1) as u8; let b = ((z + 1) * 32 - 1) as u8; - block.push(Voxel::Color(r, g, b)); - } else { - block.push(Voxel::Empty); + let block_idx = [z as usize, y as usize, x as usize]; + block[block_idx] = Voxel::Color(r, g, b); } } } } } + + let key = ( + block_pos.x as usize, + block_pos.y as usize, + block_pos.z as usize, + ); + self.genned_blocks.insert(key); } }