mirror of
https://github.com/eliasstepanik/voxel-simulation.git
synced 2026-01-10 05:18:30 +00:00
Refactor octree recursion to iterative
This commit is contained in:
parent
9e2d294d69
commit
a87bb92183
@ -1,19 +1,18 @@
|
||||
use crate::plugins::big_space::big_space_plugin::RootGrid;
|
||||
use crate::plugins::environment::systems::voxels::structure::*;
|
||||
use rayon::prelude::*;
|
||||
use std::path::Path;
|
||||
use std::thread;
|
||||
use bevy::prelude::*;
|
||||
use bevy::render::mesh::*;
|
||||
use noise::{NoiseFn, Perlin};
|
||||
use rand::{Rng, thread_rng};
|
||||
use rand::{thread_rng, Rng};
|
||||
use rayon::prelude::*;
|
||||
use std::path::Path;
|
||||
use std::thread;
|
||||
|
||||
pub fn setup(mut commands: Commands, root: Res<RootGrid>) {
|
||||
|
||||
|
||||
let builder = thread::Builder::new()
|
||||
.name("octree-build".into())
|
||||
.stack_size(64 * 4096 * 4096);
|
||||
// Reduced stack size now that octree operations are iterative
|
||||
.stack_size(8 * 1024 * 1024);
|
||||
|
||||
let handle = builder
|
||||
.spawn(move || {
|
||||
@ -22,12 +21,9 @@ pub fn setup(mut commands: Commands, root: Res<RootGrid>) {
|
||||
let octree_base_size = 64.0 * unit_size;
|
||||
let octree_depth = 10;
|
||||
|
||||
|
||||
|
||||
let path = Path::new("octree.bin");
|
||||
|
||||
|
||||
let mut octree = if Path::new(path).exists() {
|
||||
let mut octree = if Path::new(path).exists() {
|
||||
match SparseVoxelOctree::load_from_file(path) {
|
||||
Ok(tree) => tree,
|
||||
Err(err) => {
|
||||
@ -36,7 +32,8 @@ pub fn setup(mut commands: Commands, root: Res<RootGrid>) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let mut tree = SparseVoxelOctree::new(octree_depth, octree_base_size, false, false, false);
|
||||
let mut tree =
|
||||
SparseVoxelOctree::new(octree_depth, octree_base_size, false, false, false);
|
||||
// How many random spheres?
|
||||
const NUM_SPHERES: usize = 5;
|
||||
let mut rng = thread_rng();
|
||||
@ -48,7 +45,7 @@ pub fn setup(mut commands: Commands, root: Res<RootGrid>) {
|
||||
rng.gen_range(-1000.0..1000.0),
|
||||
);
|
||||
|
||||
let radius = rng.gen_range(20..=150); // voxels
|
||||
let radius = rng.gen_range(20..=150); // voxels
|
||||
|
||||
generate_voxel_sphere_parallel(&mut tree, center, radius);
|
||||
}
|
||||
@ -57,7 +54,6 @@ pub fn setup(mut commands: Commands, root: Res<RootGrid>) {
|
||||
tree
|
||||
};
|
||||
|
||||
|
||||
octree
|
||||
})
|
||||
.expect("failed to spawn octree build thread")
|
||||
@ -65,16 +61,12 @@ pub fn setup(mut commands: Commands, root: Res<RootGrid>) {
|
||||
|
||||
let octree = handle.expect("Failed to join octree build thread");
|
||||
|
||||
|
||||
// Attach octree to the scene graph
|
||||
commands.entity(root.0).with_children(|parent| {
|
||||
parent.spawn((Transform::default(), octree));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
pub fn generate_voxel_sphere_parallel(octree: &mut SparseVoxelOctree, center: Vec3, radius: i32) {
|
||||
let step = octree.get_spacing_at_depth(octree.max_depth);
|
||||
let radius_sq = radius * radius;
|
||||
@ -146,7 +138,6 @@ fn generate_voxel_sphere(octree: &mut SparseVoxelOctree, center: Vec3, planet_ra
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Inserts a 16x256x16 "column" of voxels into the octree at (0,0,0) corner.
|
||||
/// If you want it offset or centered differently, just adjust the for-loop ranges or offsets.
|
||||
fn generate_voxel_rect(octree: &mut SparseVoxelOctree) {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use crate::plugins::environment::systems::voxels::structure::{
|
||||
AABB, CHUNK_SIZE, ChunkKey, DirtyVoxel, NEIGHBOR_OFFSETS, OctreeNode, Ray, SparseVoxelOctree,
|
||||
Voxel,
|
||||
ChunkKey, DirtyVoxel, OctreeNode, Ray, SparseVoxelOctree, Voxel, AABB, CHUNK_SIZE,
|
||||
NEIGHBOR_OFFSETS,
|
||||
};
|
||||
use bevy::asset::Assets;
|
||||
use bevy::math::{DQuat, DVec3};
|
||||
@ -57,39 +57,46 @@ impl SparseVoxelOctree {
|
||||
Self::insert_recursive(&mut self.root, aligned, voxel, self.max_depth);
|
||||
}
|
||||
|
||||
fn insert_recursive(node: &mut OctreeNode, position: Vec3, voxel: Voxel, depth: u32) {
|
||||
if depth == 0 {
|
||||
node.voxel = Some(voxel);
|
||||
node.is_leaf = true;
|
||||
return;
|
||||
}
|
||||
fn insert_recursive(
|
||||
mut node: &mut OctreeNode,
|
||||
mut position: Vec3,
|
||||
voxel: Voxel,
|
||||
mut depth: u32,
|
||||
) {
|
||||
let epsilon = 1e-6;
|
||||
// Determine octant index by comparing with 0.5
|
||||
let index = ((position.x >= 0.5 - epsilon) as usize)
|
||||
+ ((position.y >= 0.5 - epsilon) as usize * 2)
|
||||
+ ((position.z >= 0.5 - epsilon) as usize * 4);
|
||||
while depth > 0 {
|
||||
let index = ((position.x >= 0.5 - epsilon) as usize)
|
||||
+ ((position.y >= 0.5 - epsilon) as usize * 2)
|
||||
+ ((position.z >= 0.5 - epsilon) as usize * 4);
|
||||
|
||||
// If there are no children, create them.
|
||||
if node.children.is_none() {
|
||||
node.children = Some(Box::new(core::array::from_fn(|_| OctreeNode::new())));
|
||||
node.is_leaf = false;
|
||||
}
|
||||
if let Some(ref mut children) = node.children {
|
||||
// Adjust coordinate into the child’s [0, 1] range.
|
||||
let adjust_coord = |coord: f32| {
|
||||
if coord >= 0.5 - epsilon {
|
||||
(coord - 0.5) * 2.0
|
||||
} else {
|
||||
coord * 2.0
|
||||
}
|
||||
};
|
||||
let child_pos = Vec3::new(
|
||||
adjust_coord(position.x),
|
||||
adjust_coord(position.y),
|
||||
adjust_coord(position.z),
|
||||
);
|
||||
Self::insert_recursive(&mut children[index], child_pos, voxel, depth - 1);
|
||||
if node.children.is_none() {
|
||||
node.children = Some(Box::new(core::array::from_fn(|_| OctreeNode::new())));
|
||||
node.is_leaf = false;
|
||||
}
|
||||
|
||||
if let Some(ref mut children) = node.children {
|
||||
let adjust_coord = |coord: f32| {
|
||||
if coord >= 0.5 - epsilon {
|
||||
(coord - 0.5) * 2.0
|
||||
} else {
|
||||
coord * 2.0
|
||||
}
|
||||
};
|
||||
|
||||
position = Vec3::new(
|
||||
adjust_coord(position.x),
|
||||
adjust_coord(position.y),
|
||||
adjust_coord(position.z),
|
||||
);
|
||||
|
||||
node = &mut children[index];
|
||||
}
|
||||
|
||||
depth -= 1;
|
||||
}
|
||||
|
||||
node.voxel = Some(voxel);
|
||||
node.is_leaf = true;
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, position: Vec3) {
|
||||
@ -215,61 +222,71 @@ impl SparseVoxelOctree {
|
||||
}
|
||||
}
|
||||
|
||||
fn remove_recursive(node: &mut OctreeNode, x: f32, y: f32, z: f32, depth: u32) -> bool {
|
||||
if depth == 0 {
|
||||
if node.voxel.is_some() {
|
||||
node.voxel = None;
|
||||
node.is_leaf = false;
|
||||
return true;
|
||||
} else {
|
||||
fn remove_recursive(
|
||||
mut node: &mut OctreeNode,
|
||||
mut x: f32,
|
||||
mut y: f32,
|
||||
mut z: f32,
|
||||
mut depth: u32,
|
||||
) -> bool {
|
||||
let epsilon = 1e-6;
|
||||
let mut stack: Vec<(*mut OctreeNode, usize)> = Vec::new();
|
||||
|
||||
while depth > 0 {
|
||||
if node.children.is_none() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let index = ((x >= 0.5 - epsilon) as usize)
|
||||
+ ((y >= 0.5 - epsilon) as usize * 2)
|
||||
+ ((z >= 0.5 - epsilon) as usize * 4);
|
||||
|
||||
let adjust_coord = |coord: f32| {
|
||||
if coord >= 0.5 - epsilon {
|
||||
(coord - 0.5) * 2.0
|
||||
} else {
|
||||
coord * 2.0
|
||||
}
|
||||
};
|
||||
|
||||
stack.push((node as *mut _, index));
|
||||
let children = unsafe { node.children.as_mut().unwrap() };
|
||||
node = &mut children[index];
|
||||
x = adjust_coord(x);
|
||||
y = adjust_coord(y);
|
||||
z = adjust_coord(z);
|
||||
depth -= 1;
|
||||
}
|
||||
|
||||
if node.children.is_none() {
|
||||
if node.voxel.is_some() {
|
||||
node.voxel = None;
|
||||
node.is_leaf = false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
let epsilon = 1e-6;
|
||||
let index = ((x >= 0.5 - epsilon) as usize)
|
||||
+ ((y >= 0.5 - epsilon) as usize * 2)
|
||||
+ ((z >= 0.5 - epsilon) as usize * 4);
|
||||
|
||||
let adjust_coord = |coord: f32| {
|
||||
if coord >= 0.5 - epsilon {
|
||||
(coord - 0.5) * 2.0
|
||||
while let Some((parent_ptr, idx)) = stack.pop() {
|
||||
let parent = unsafe { &mut *parent_ptr };
|
||||
if parent.children.as_ref().unwrap()[idx].is_empty() {
|
||||
parent.children.as_mut().unwrap()[idx] = OctreeNode::new();
|
||||
} else {
|
||||
coord * 2.0
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
let child = &mut node.children.as_mut().unwrap()[index];
|
||||
let should_prune_child = Self::remove_recursive(
|
||||
child,
|
||||
adjust_coord(x),
|
||||
adjust_coord(y),
|
||||
adjust_coord(z),
|
||||
depth - 1,
|
||||
);
|
||||
|
||||
if should_prune_child {
|
||||
// remove the child node
|
||||
node.children.as_mut().unwrap()[index] = OctreeNode::new();
|
||||
if parent
|
||||
.children
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.all(|c| c.is_empty())
|
||||
{
|
||||
parent.children = None;
|
||||
parent.is_leaf = true;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if all children are empty
|
||||
let all_children_empty = node
|
||||
.children
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.all(|child| child.is_empty());
|
||||
|
||||
if all_children_empty {
|
||||
node.children = None;
|
||||
node.is_leaf = true;
|
||||
return node.voxel.is_none();
|
||||
}
|
||||
false
|
||||
true
|
||||
}
|
||||
|
||||
/// Grow the octree so that the given world-space point fits within the root.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user