From 20622a7c09141de5c785d013a7b080b57983575f Mon Sep 17 00:00:00 2001 From: Elias Stepanik <40958815+eliasstepanik@users.noreply.github.com> Date: Sun, 15 Jun 2025 02:54:30 +0200 Subject: [PATCH] Parallelize chunk systems --- .../systems/voxels/queue_systems.rs | 57 ++++++++------ .../systems/voxels/render_chunks.rs | 77 +++++++++++-------- 2 files changed, 77 insertions(+), 57 deletions(-) diff --git a/client/src/plugins/environment/systems/voxels/queue_systems.rs b/client/src/plugins/environment/systems/voxels/queue_systems.rs index 3a13630..462bb90 100644 --- a/client/src/plugins/environment/systems/voxels/queue_systems.rs +++ b/client/src/plugins/environment/systems/voxels/queue_systems.rs @@ -1,23 +1,26 @@ -use bevy::prelude::*; use crate::plugins::environment::systems::voxels::helper::world_to_chunk; use crate::plugins::environment::systems::voxels::structure::*; - - +use bevy::prelude::*; +use rayon::prelude::*; /// enqueue chunks that *should* be visible but are not yet spawned /// enqueue chunks that *should* be visible but are not yet spawned pub fn enqueue_visible_chunks( - mut queue : ResMut, - spawned : Res, - mut prev_cam : ResMut, - cfg : Res, - cam_q : Query<&GlobalTransform, With>, - tree_q : Query<&SparseVoxelOctree>, + mut queue: ResMut, + spawned: Res, + mut prev_cam: ResMut, + cfg: Res, + cam_q: Query<&GlobalTransform, With>, + tree_q: Query<&SparseVoxelOctree>, ) { - let Ok(tree) = tree_q.get_single() else { return }; - let Ok(cam_tf) = cam_q.get_single() else { return }; - let cam_pos = cam_tf.translation(); - let centre = world_to_chunk(tree, cam_pos); + let Ok(tree) = tree_q.get_single() else { + return; + }; + let Ok(cam_tf) = cam_q.get_single() else { + return; + }; + let cam_pos = cam_tf.translation(); + let centre = world_to_chunk(tree, cam_pos); if prev_cam.0 == Some(centre) { return; @@ -28,14 +31,18 @@ pub fn enqueue_visible_chunks( let mut keys: Vec<(ChunkKey, i32)> = tree .occupied_chunks - .iter() + .par_iter() .filter_map(|key| { let dx = key.0 - centre.0; let dy = key.1 - centre.1; let dz = key.2 - centre.2; - if dx.abs() > r || dy.abs() > r || dz.abs() > r { return None; } - if spawned.0.contains_key(key) { return None; } - Some((*key, dx*dx + dy*dy + dz*dz)) + if dx.abs() > r || dy.abs() > r || dz.abs() > r { + return None; + } + if spawned.0.contains_key(key) { + return None; + } + Some((*key, dx * dx + dy * dy + dz * dz)) }) .collect(); @@ -51,15 +58,19 @@ pub fn enqueue_visible_chunks( /// move a limited number of keys from the queue into the octree’s dirty set pub fn process_chunk_queue( - mut queue : ResMut, - budget : Res, - mut tree_q : Query<&mut SparseVoxelOctree>, + mut queue: ResMut, + budget: Res, + mut tree_q: Query<&mut SparseVoxelOctree>, ) { - let Ok(mut tree) = tree_q.get_single_mut() else { return }; + let Ok(mut tree) = tree_q.get_single_mut() else { + return; + }; for _ in 0..budget.per_frame { if let Some(key) = queue.keys.pop_front() { queue.set.remove(&key); tree.dirty_chunks.insert(key); - } else { break; } + } else { + break; + } } -} \ No newline at end of file +} diff --git a/client/src/plugins/environment/systems/voxels/render_chunks.rs b/client/src/plugins/environment/systems/voxels/render_chunks.rs index acb268e..cc2573d 100644 --- a/client/src/plugins/environment/systems/voxels/render_chunks.rs +++ b/client/src/plugins/environment/systems/voxels/render_chunks.rs @@ -1,12 +1,13 @@ use crate::plugins::big_space::big_space_plugin::RootGrid; +use crate::plugins::environment::systems::voxels::atlas::VoxelTextureAtlas; use crate::plugins::environment::systems::voxels::meshing::mesh_chunk; use crate::plugins::environment::systems::voxels::structure::*; -use crate::plugins::environment::systems::voxels::atlas::VoxelTextureAtlas; use bevy::pbr::wireframe::Wireframe; use bevy::prelude::*; use bevy::render::mesh::Mesh; use big_space::prelude::GridCell; use itertools::Itertools; +use rayon::prelude::*; use std::collections::HashMap; use std::fmt::format; @@ -41,38 +42,46 @@ pub fn rebuild_dirty_chunks( } //------------------------------------------------ collect voxel data - let mut bufs = Vec::new(); - for key in tree.dirty_chunks.iter().copied() { - let lod = existing.get(&key).map(|v| v.3).unwrap_or(0); - let mut buf = [[[None; CHUNK_SIZE as usize]; CHUNK_SIZE as usize]; CHUNK_SIZE as usize]; + let tree_ref = &*tree; + let bufs: Vec<_> = tree + .dirty_chunks + .par_iter() + .copied() + .map(|key| { + let lod = existing.get(&key).map(|v| v.3).unwrap_or(0); + let mut buf = + [[[None; CHUNK_SIZE as usize]; CHUNK_SIZE as usize]; CHUNK_SIZE as usize]; - let half = tree.size * 0.5; - let step = tree.get_spacing_at_depth(tree.max_depth); - let origin = Vec3::new( - key.0 as f32 * CHUNK_SIZE as f32 * step - half, - key.1 as f32 * CHUNK_SIZE as f32 * step - half, - key.2 as f32 * CHUNK_SIZE as f32 * step - half, - ); + let half = tree_ref.size * 0.5; + let step = tree_ref.get_spacing_at_depth(tree_ref.max_depth); + let origin = Vec3::new( + key.0 as f32 * CHUNK_SIZE as f32 * step - half, + key.1 as f32 * CHUNK_SIZE as f32 * step - half, + key.2 as f32 * CHUNK_SIZE as f32 * step - half, + ); - let mult = 1 << lod; - for gx in (0..CHUNK_SIZE).step_by(mult as usize) { - for gy in (0..CHUNK_SIZE).step_by(mult as usize) { - for gz in (0..CHUNK_SIZE).step_by(mult as usize) { - let center = origin - + Vec3::new( - (gx + mult / 2) as f32 * step, - (gy + mult / 2) as f32 * step, - (gz + mult / 2) as f32 * step, - ); - if let Some(v) = tree.get_voxel_at_world_coords(center) { - for lx in 0..mult { - for ly in 0..mult { - for lz in 0..mult { - let ix = gx + lx; - let iy = gy + ly; - let iz = gz + lz; - if ix < CHUNK_SIZE && iy < CHUNK_SIZE && iz < CHUNK_SIZE { - buf[ix as usize][iy as usize][iz as usize] = Some(*v); + let mult = 1 << lod; + for gx in (0..CHUNK_SIZE).step_by(mult as usize) { + for gy in (0..CHUNK_SIZE).step_by(mult as usize) { + for gz in (0..CHUNK_SIZE).step_by(mult as usize) { + let center = origin + + Vec3::new( + (gx + mult / 2) as f32 * step, + (gy + mult / 2) as f32 * step, + (gz + mult / 2) as f32 * step, + ); + if let Some(v) = tree_ref.get_voxel_at_world_coords(center) { + for lx in 0..mult { + for ly in 0..mult { + for lz in 0..mult { + let ix = gx + lx; + let iy = gy + ly; + let iz = gz + lz; + if ix < CHUNK_SIZE && iy < CHUNK_SIZE && iz < CHUNK_SIZE + { + buf[ix as usize][iy as usize][iz as usize] = + Some(*v); + } } } } @@ -80,10 +89,10 @@ pub fn rebuild_dirty_chunks( } } } - } - bufs.push((key, buf, origin, step, lod)); - } + (key, buf, origin, step, lod) + }) + .collect(); //------------------------------------------------ create / update for (key, buf, origin, step, lod) in bufs {