mirror of
https://github.com/eliasstepanik/voxel-simulation.git
synced 2026-01-11 13:58:30 +00:00
Merge pull request #41 from eliasstepanik/codex/find-and-fix-stack-overflow-issues
Fix potential octree stack overflow
This commit is contained in:
commit
d24606594d
@ -1,19 +1,18 @@
|
|||||||
use crate::plugins::big_space::big_space_plugin::RootGrid;
|
use crate::plugins::big_space::big_space_plugin::RootGrid;
|
||||||
use crate::plugins::environment::systems::voxels::structure::*;
|
use crate::plugins::environment::systems::voxels::structure::*;
|
||||||
use rayon::prelude::*;
|
|
||||||
use std::path::Path;
|
|
||||||
use std::thread;
|
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy::render::mesh::*;
|
use bevy::render::mesh::*;
|
||||||
use noise::{NoiseFn, Perlin};
|
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>) {
|
pub fn setup(mut commands: Commands, root: Res<RootGrid>) {
|
||||||
|
|
||||||
|
|
||||||
let builder = thread::Builder::new()
|
let builder = thread::Builder::new()
|
||||||
.name("octree-build".into())
|
.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
|
let handle = builder
|
||||||
.spawn(move || {
|
.spawn(move || {
|
||||||
@ -22,11 +21,8 @@ pub fn setup(mut commands: Commands, root: Res<RootGrid>) {
|
|||||||
let octree_base_size = 64.0 * unit_size;
|
let octree_base_size = 64.0 * unit_size;
|
||||||
let octree_depth = 10;
|
let octree_depth = 10;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
let path = Path::new("octree.bin");
|
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) {
|
match SparseVoxelOctree::load_from_file(path) {
|
||||||
Ok(tree) => tree,
|
Ok(tree) => tree,
|
||||||
@ -36,7 +32,8 @@ pub fn setup(mut commands: Commands, root: Res<RootGrid>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} 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?
|
// How many random spheres?
|
||||||
const NUM_SPHERES: usize = 5;
|
const NUM_SPHERES: usize = 5;
|
||||||
let mut rng = thread_rng();
|
let mut rng = thread_rng();
|
||||||
@ -57,7 +54,6 @@ pub fn setup(mut commands: Commands, root: Res<RootGrid>) {
|
|||||||
tree
|
tree
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
octree
|
octree
|
||||||
})
|
})
|
||||||
.expect("failed to spawn octree build thread")
|
.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");
|
let octree = handle.expect("Failed to join octree build thread");
|
||||||
|
|
||||||
|
|
||||||
// Attach octree to the scene graph
|
// Attach octree to the scene graph
|
||||||
commands.entity(root.0).with_children(|parent| {
|
commands.entity(root.0).with_children(|parent| {
|
||||||
parent.spawn((Transform::default(), octree));
|
parent.spawn((Transform::default(), octree));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
pub fn generate_voxel_sphere_parallel(octree: &mut SparseVoxelOctree, center: Vec3, radius: i32) {
|
pub fn generate_voxel_sphere_parallel(octree: &mut SparseVoxelOctree, center: Vec3, radius: i32) {
|
||||||
let step = octree.get_spacing_at_depth(octree.max_depth);
|
let step = octree.get_spacing_at_depth(octree.max_depth);
|
||||||
let radius_sq = radius * radius;
|
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.
|
/// 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.
|
/// If you want it offset or centered differently, just adjust the for-loop ranges or offsets.
|
||||||
fn generate_voxel_rect(octree: &mut SparseVoxelOctree) {
|
fn generate_voxel_rect(octree: &mut SparseVoxelOctree) {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
use crate::plugins::environment::systems::voxels::structure::{
|
use crate::plugins::environment::systems::voxels::structure::{
|
||||||
AABB, CHUNK_SIZE, ChunkKey, DirtyVoxel, NEIGHBOR_OFFSETS, OctreeNode, Ray, SparseVoxelOctree,
|
ChunkKey, DirtyVoxel, OctreeNode, Ray, SparseVoxelOctree, Voxel, AABB, CHUNK_SIZE,
|
||||||
Voxel,
|
NEIGHBOR_OFFSETS,
|
||||||
};
|
};
|
||||||
use bevy::asset::Assets;
|
use bevy::asset::Assets;
|
||||||
use bevy::math::{DQuat, DVec3};
|
use bevy::math::{DQuat, DVec3};
|
||||||
@ -57,25 +57,24 @@ impl SparseVoxelOctree {
|
|||||||
Self::insert_recursive(&mut self.root, aligned, voxel, self.max_depth);
|
Self::insert_recursive(&mut self.root, aligned, voxel, self.max_depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_recursive(node: &mut OctreeNode, position: Vec3, voxel: Voxel, depth: u32) {
|
fn insert_recursive(
|
||||||
if depth == 0 {
|
mut node: &mut OctreeNode,
|
||||||
node.voxel = Some(voxel);
|
mut position: Vec3,
|
||||||
node.is_leaf = true;
|
voxel: Voxel,
|
||||||
return;
|
mut depth: u32,
|
||||||
}
|
) {
|
||||||
let epsilon = 1e-6;
|
let epsilon = 1e-6;
|
||||||
// Determine octant index by comparing with 0.5
|
while depth > 0 {
|
||||||
let index = ((position.x >= 0.5 - epsilon) as usize)
|
let index = ((position.x >= 0.5 - epsilon) as usize)
|
||||||
+ ((position.y >= 0.5 - epsilon) as usize * 2)
|
+ ((position.y >= 0.5 - epsilon) as usize * 2)
|
||||||
+ ((position.z >= 0.5 - epsilon) as usize * 4);
|
+ ((position.z >= 0.5 - epsilon) as usize * 4);
|
||||||
|
|
||||||
// If there are no children, create them.
|
|
||||||
if node.children.is_none() {
|
if node.children.is_none() {
|
||||||
node.children = Some(Box::new(core::array::from_fn(|_| OctreeNode::new())));
|
node.children = Some(Box::new(core::array::from_fn(|_| OctreeNode::new())));
|
||||||
node.is_leaf = false;
|
node.is_leaf = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ref mut children) = node.children {
|
if let Some(ref mut children) = node.children {
|
||||||
// Adjust coordinate into the child’s [0, 1] range.
|
|
||||||
let adjust_coord = |coord: f32| {
|
let adjust_coord = |coord: f32| {
|
||||||
if coord >= 0.5 - epsilon {
|
if coord >= 0.5 - epsilon {
|
||||||
(coord - 0.5) * 2.0
|
(coord - 0.5) * 2.0
|
||||||
@ -83,13 +82,21 @@ impl SparseVoxelOctree {
|
|||||||
coord * 2.0
|
coord * 2.0
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let child_pos = Vec3::new(
|
|
||||||
|
position = Vec3::new(
|
||||||
adjust_coord(position.x),
|
adjust_coord(position.x),
|
||||||
adjust_coord(position.y),
|
adjust_coord(position.y),
|
||||||
adjust_coord(position.z),
|
adjust_coord(position.z),
|
||||||
);
|
);
|
||||||
Self::insert_recursive(&mut children[index], child_pos, voxel, depth - 1);
|
|
||||||
|
node = &mut children[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
depth -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
node.voxel = Some(voxel);
|
||||||
|
node.is_leaf = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove(&mut self, position: Vec3) {
|
pub fn remove(&mut self, position: Vec3) {
|
||||||
@ -215,21 +222,21 @@ impl SparseVoxelOctree {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_recursive(node: &mut OctreeNode, x: f32, y: f32, z: f32, depth: u32) -> bool {
|
fn remove_recursive(
|
||||||
if depth == 0 {
|
mut node: &mut OctreeNode,
|
||||||
if node.voxel.is_some() {
|
mut x: f32,
|
||||||
node.voxel = None;
|
mut y: f32,
|
||||||
node.is_leaf = false;
|
mut z: f32,
|
||||||
return true;
|
mut depth: u32,
|
||||||
} else {
|
) -> bool {
|
||||||
return false;
|
let epsilon = 1e-6;
|
||||||
}
|
let mut stack: Vec<(*mut OctreeNode, usize)> = Vec::new();
|
||||||
}
|
|
||||||
|
|
||||||
|
while depth > 0 {
|
||||||
if node.children.is_none() {
|
if node.children.is_none() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let epsilon = 1e-6;
|
|
||||||
let index = ((x >= 0.5 - epsilon) as usize)
|
let index = ((x >= 0.5 - epsilon) as usize)
|
||||||
+ ((y >= 0.5 - epsilon) as usize * 2)
|
+ ((y >= 0.5 - epsilon) as usize * 2)
|
||||||
+ ((z >= 0.5 - epsilon) as usize * 4);
|
+ ((z >= 0.5 - epsilon) as usize * 4);
|
||||||
@ -242,34 +249,44 @@ impl SparseVoxelOctree {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let child = &mut node.children.as_mut().unwrap()[index];
|
stack.push((node as *mut _, index));
|
||||||
let should_prune_child = Self::remove_recursive(
|
let children = unsafe { node.children.as_mut().unwrap() };
|
||||||
child,
|
node = &mut children[index];
|
||||||
adjust_coord(x),
|
x = adjust_coord(x);
|
||||||
adjust_coord(y),
|
y = adjust_coord(y);
|
||||||
adjust_coord(z),
|
z = adjust_coord(z);
|
||||||
depth - 1,
|
depth -= 1;
|
||||||
);
|
|
||||||
|
|
||||||
if should_prune_child {
|
|
||||||
// remove the child node
|
|
||||||
node.children.as_mut().unwrap()[index] = OctreeNode::new();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if all children are empty
|
if node.voxel.is_some() {
|
||||||
let all_children_empty = node
|
node.voxel = None;
|
||||||
|
node.is_leaf = false;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if parent
|
||||||
.children
|
.children
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.iter()
|
.iter()
|
||||||
.all(|child| child.is_empty());
|
.all(|c| c.is_empty())
|
||||||
|
{
|
||||||
if all_children_empty {
|
parent.children = None;
|
||||||
node.children = None;
|
parent.is_leaf = true;
|
||||||
node.is_leaf = true;
|
} else {
|
||||||
return node.voxel.is_none();
|
break;
|
||||||
}
|
}
|
||||||
false
|
}
|
||||||
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Grow the octree so that the given world-space point fits within the root.
|
/// Grow the octree so that the given world-space point fits within the root.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user