mirror of
https://github.com/eliasstepanik/voxel-simulation.git
synced 2026-01-10 21:38:29 +00:00
Optimize chunk visibility queue
This commit is contained in:
parent
4d4446f964
commit
9a74d8d0da
@ -7,7 +7,7 @@ use crate::plugins::environment::systems::voxels::queue_systems::{enqueue_visibl
|
||||
update_chunk_lods.after(process_chunk_queue),
|
||||
use crate::plugins::environment::systems::voxels::render_chunks::rebuild_dirty_chunks;
|
||||
use crate::plugins::environment::systems::voxels::lod::update_chunk_lods;
|
||||
use crate::plugins::environment::systems::voxels::structure::{ChunkBudget, ChunkCullingCfg, ChunkQueue, SparseVoxelOctree, SpawnedChunks};
|
||||
use crate::plugins::environment::systems::voxels::structure::{ChunkBudget, ChunkCullingCfg, ChunkQueue, SparseVoxelOctree, SpawnedChunks, ChunkOffsets, PrevCameraChunk};
|
||||
|
||||
pub struct EnvironmentPlugin;
|
||||
impl Plugin for EnvironmentPlugin {
|
||||
@ -23,8 +23,11 @@ impl Plugin for EnvironmentPlugin {
|
||||
),
|
||||
);
|
||||
|
||||
app.insert_resource(ChunkCullingCfg { view_distance_chunks: 10 });
|
||||
let view_distance_chunks = 10;
|
||||
app.insert_resource(ChunkCullingCfg { view_distance_chunks });
|
||||
app.insert_resource(ChunkBudget { per_frame: 20 });
|
||||
app.insert_resource(ChunkOffsets::new(view_distance_chunks));
|
||||
app.init_resource::<PrevCameraChunk>();
|
||||
app.add_systems(Update, log_mesh_count);
|
||||
app
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
@ -20,6 +20,7 @@ impl SparseVoxelOctree {
|
||||
show_chunks,
|
||||
dirty: Vec::new(),
|
||||
dirty_chunks: Default::default(),
|
||||
occupied_chunks: Default::default(),
|
||||
}
|
||||
}
|
||||
pub fn insert(&mut self, position: Vec3, voxel: Voxel) {
|
||||
@ -40,7 +41,9 @@ impl SparseVoxelOctree {
|
||||
};
|
||||
|
||||
self.dirty.push(dirty_voxel);
|
||||
self.dirty_chunks.insert(chunk_key_from_world(self, position));
|
||||
let key = chunk_key_from_world(self, position);
|
||||
self.dirty_chunks.insert(key);
|
||||
self.occupied_chunks.insert(key);
|
||||
|
||||
|
||||
Self::insert_recursive(&mut self.root, aligned, voxel, self.max_depth);
|
||||
@ -87,7 +90,8 @@ impl SparseVoxelOctree {
|
||||
self.dirty.push(DirtyVoxel { position: aligned });
|
||||
|
||||
// mark the chunk
|
||||
self.dirty_chunks.insert(chunk_key_from_world(self, position));
|
||||
let key = chunk_key_from_world(self, position);
|
||||
self.dirty_chunks.insert(key);
|
||||
|
||||
Self::remove_recursive(
|
||||
&mut self.root,
|
||||
@ -96,6 +100,10 @@ impl SparseVoxelOctree {
|
||||
aligned.z,
|
||||
self.max_depth,
|
||||
);
|
||||
|
||||
if !self.chunk_has_any_voxel(key) {
|
||||
self.occupied_chunks.remove(&key);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clear_dirty_flags(&mut self) {
|
||||
|
||||
@ -9,6 +9,8 @@ use crate::plugins::environment::systems::voxels::structure::*;
|
||||
pub fn enqueue_visible_chunks(
|
||||
mut queue : ResMut<ChunkQueue>,
|
||||
spawned : Res<SpawnedChunks>,
|
||||
mut prev_cam : ResMut<PrevCameraChunk>,
|
||||
offsets : Res<ChunkOffsets>,
|
||||
cfg : Res<ChunkCullingCfg>,
|
||||
cam_q : Query<&GlobalTransform, With<Camera>>,
|
||||
tree_q : Query<&SparseVoxelOctree>,
|
||||
@ -16,35 +18,17 @@ pub fn enqueue_visible_chunks(
|
||||
let tree = tree_q.single();
|
||||
let cam_pos = cam_q.single().translation();
|
||||
let centre = world_to_chunk(tree, cam_pos);
|
||||
let r = cfg.view_distance_chunks;
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// 1. gather every *new* candidate chunk together with its distance²
|
||||
// ------------------------------------------------------------------
|
||||
let mut candidates: Vec<(i32 /*dist²*/, ChunkKey)> = Vec::new();
|
||||
|
||||
for dx in -r..=r {
|
||||
for dy in -r..=r {
|
||||
for dz in -r..=r {
|
||||
let key = ChunkKey(centre.0 + dx, centre.1 + dy, centre.2 + dz);
|
||||
|
||||
if spawned.0.contains_key(&key) { continue; } // already spawned
|
||||
if queue.0.contains(&key) { continue; } // already queued
|
||||
if !tree.chunk_has_any_voxel(key) { continue; } // empty air
|
||||
|
||||
let dist2 = dx*dx + dy*dy + dz*dz; // squared distance
|
||||
candidates.push((dist2, key));
|
||||
}
|
||||
}
|
||||
if prev_cam.0 == Some(centre) {
|
||||
return;
|
||||
}
|
||||
prev_cam.0 = Some(centre);
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// 2. sort by distance so nearest chunks enter the queue first
|
||||
// ------------------------------------------------------------------
|
||||
candidates.sort_by_key(|&(d2, _)| d2);
|
||||
|
||||
// push into FIFO queue in that order
|
||||
for (_, key) in candidates {
|
||||
for offset in &offsets.0 {
|
||||
let key = ChunkKey(centre.0 + offset.x, centre.1 + offset.y, centre.2 + offset.z);
|
||||
if spawned.0.contains_key(&key) { continue; }
|
||||
if queue.0.contains(&key) { continue; }
|
||||
if !tree.occupied_chunks.contains(&key) { continue; }
|
||||
queue.0.push_back(key);
|
||||
}
|
||||
}
|
||||
|
||||
@ -36,6 +36,7 @@ pub struct SparseVoxelOctree {
|
||||
|
||||
pub dirty: Vec<DirtyVoxel>,
|
||||
pub dirty_chunks: HashSet<ChunkKey>,
|
||||
pub occupied_chunks: HashSet<ChunkKey>,
|
||||
}
|
||||
|
||||
impl OctreeNode {
|
||||
@ -126,4 +127,25 @@ pub struct SpawnedChunks(pub HashMap<ChunkKey, Entity>);
|
||||
/// how big the cube around the player is, measured in chunks
|
||||
#[derive(Resource)]
|
||||
pub struct ChunkCullingCfg { pub view_distance_chunks: i32 }
|
||||
impl Default for ChunkCullingCfg { fn default() -> Self { Self { view_distance_chunks: 6 } } }
|
||||
impl Default for ChunkCullingCfg { fn default() -> Self { Self { view_distance_chunks: 6 } } }
|
||||
|
||||
#[derive(Resource, Default)]
|
||||
pub struct PrevCameraChunk(pub Option<ChunkKey>);
|
||||
|
||||
#[derive(Resource, Clone)]
|
||||
pub struct ChunkOffsets(pub Vec<IVec3>);
|
||||
|
||||
impl ChunkOffsets {
|
||||
pub fn new(radius: i32) -> Self {
|
||||
let mut offsets = Vec::new();
|
||||
for dx in -radius..=radius {
|
||||
for dy in -radius..=radius {
|
||||
for dz in -radius..=radius {
|
||||
offsets.push(IVec3::new(dx, dy, dz));
|
||||
}
|
||||
}
|
||||
}
|
||||
offsets.sort_by_key(|v| v.x * v.x + v.y * v.y + v.z * v.z);
|
||||
Self(offsets)
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user