diff --git a/client/src/plugins/environment/systems/voxel_system.rs b/client/src/plugins/environment/systems/voxel_system.rs index 1bacfdd..66948e5 100644 --- a/client/src/plugins/environment/systems/voxel_system.rs +++ b/client/src/plugins/environment/systems/voxel_system.rs @@ -19,7 +19,7 @@ pub fn setup( // 2. Generate sphere in parallel, dropping the cloned Arc inside the function let color = Color::rgb(0.2, 0.8, 0.2); - generate_voxel_sphere(&mut octree, 100, color); + generate_voxel_sphere(&mut octree, 110, color); // 4. Spawn entity with both Transform and the real octree component commands.entity(root.0).with_children(|parent| { diff --git a/client/src/plugins/environment/systems/voxels/octree.rs b/client/src/plugins/environment/systems/voxels/octree.rs index 16cc86a..da16ba0 100644 --- a/client/src/plugins/environment/systems/voxels/octree.rs +++ b/client/src/plugins/environment/systems/voxels/octree.rs @@ -6,7 +6,7 @@ use bevy::prelude::*; use bevy::render::mesh::{Indices, PrimitiveTopology, VertexAttributeValues}; use bevy::render::render_asset::RenderAssetUsages; use crate::plugins::environment::systems::voxels::helper::chunk_key_from_world; -use crate::plugins::environment::systems::voxels::structure::{DirtyVoxel, OctreeNode, Ray, SparseVoxelOctree, Voxel, AABB, NEIGHBOR_OFFSETS}; +use crate::plugins::environment::systems::voxels::structure::{DirtyVoxel, OctreeNode, Ray, SparseVoxelOctree, Voxel, AABB, NEIGHBOR_OFFSETS, CHUNK_SIZE, ChunkKey}; impl SparseVoxelOctree { /// Creates a new octree with the specified max depth, size, and wireframe visibility. @@ -43,6 +43,7 @@ impl SparseVoxelOctree { self.dirty.push(dirty_voxel); let key = chunk_key_from_world(self, position); self.dirty_chunks.insert(key); + self.mark_neighbor_chunks_dirty(position); self.occupied_chunks.insert(key); @@ -92,6 +93,7 @@ impl SparseVoxelOctree { // mark the chunk let key = chunk_key_from_world(self, position); self.dirty_chunks.insert(key); + self.mark_neighbor_chunks_dirty(position); Self::remove_recursive( &mut self.root, @@ -111,6 +113,50 @@ impl SparseVoxelOctree { self.dirty_chunks.clear(); } + fn mark_neighbor_chunks_dirty(&mut self, position: Vec3) { + let key = chunk_key_from_world(self, position); + let step = self.get_spacing_at_depth(self.max_depth); + let half = self.size * 0.5; + + let gx = ((position.x + half) / step).floor() as i32; + let gy = ((position.y + half) / step).floor() as i32; + let gz = ((position.z + half) / step).floor() as i32; + + let lx = gx - key.0 * CHUNK_SIZE; + let ly = gy - key.1 * CHUNK_SIZE; + let lz = gz - key.2 * CHUNK_SIZE; + + let mut neighbors = [ + (lx == 0, ChunkKey(key.0 - 1, key.1, key.2)), + (lx == CHUNK_SIZE - 1, ChunkKey(key.0 + 1, key.1, key.2)), + (ly == 0, ChunkKey(key.0, key.1 - 1, key.2)), + (ly == CHUNK_SIZE - 1, ChunkKey(key.0, key.1 + 1, key.2)), + (lz == 0, ChunkKey(key.0, key.1, key.2 - 1)), + (lz == CHUNK_SIZE - 1, ChunkKey(key.0, key.1, key.2 + 1)), + ]; + + for (cond, n) in neighbors.iter() { + if *cond && self.occupied_chunks.contains(n) { + self.dirty_chunks.insert(*n); + } + } + } + + /// Mark all six neighbor chunks of the given key as dirty if they exist. + pub fn mark_neighbors_dirty_from_key(&mut self, key: ChunkKey) { + let offsets = [ + (-1, 0, 0), (1, 0, 0), + (0, -1, 0), (0, 1, 0), + (0, 0, -1), (0, 0, 1), + ]; + for (dx, dy, dz) in offsets { + let neighbor = ChunkKey(key.0 + dx, key.1 + dy, key.2 + dz); + if self.occupied_chunks.contains(&neighbor) { + self.dirty_chunks.insert(neighbor); + } + } + } + fn remove_recursive( node: &mut OctreeNode, x: f32,