mirror of
https://github.com/eliasstepanik/voxel-simulation.git
synced 2026-01-11 05:48:29 +00:00
223 lines
7.1 KiB
Rust
223 lines
7.1 KiB
Rust
use crate::plugins::big_space::big_space_plugin::RootGrid;
|
|
use crate::plugins::environment::systems::voxels::structure::*;
|
|
use rayon::prelude::*;
|
|
use std::path::Path;
|
|
|
|
use bevy::prelude::*;
|
|
use bevy::render::mesh::*;
|
|
use noise::{NoiseFn, Perlin};
|
|
use rand::{Rng, thread_rng};
|
|
|
|
pub fn setup(mut commands: Commands, root: Res<RootGrid>) {
|
|
// Octree parameters
|
|
let unit_size = 1.0_f32;
|
|
let octree_base_size = 64.0 * unit_size;
|
|
let octree_depth = 10;
|
|
|
|
let path = Path::new("octree.bin");
|
|
|
|
let mut octree = if path.exists() {
|
|
match SparseVoxelOctree::load_from_file(path) {
|
|
Ok(tree) => tree,
|
|
Err(err) => {
|
|
error!("failed to load octree: {err}");
|
|
SparseVoxelOctree::new(octree_depth, octree_base_size, false, false, false)
|
|
}
|
|
}
|
|
} else {
|
|
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 = threald_rng();
|
|
|
|
for _ in 0..NUM_SPHERES {
|
|
let center = Vec3::new(
|
|
rng.gen_range(-1000.0..1000.0),
|
|
rng.gen_range(-1000.0..1000.0),
|
|
rng.gen_range(-1000.0..1000.0),
|
|
);
|
|
|
|
let radius = rng.gen_range(20..=150); // voxels
|
|
|
|
generate_voxel_sphere_parallel(&mut tree, center, radius);
|
|
}*/
|
|
|
|
generate_voxel_sphere(&mut tree, 200);
|
|
tree
|
|
};
|
|
|
|
// 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;
|
|
|
|
// 1. Collect voxel positions in parallel
|
|
let voxels: Vec<(Vec3, Voxel)> = (-radius..=radius)
|
|
.into_par_iter()
|
|
.flat_map_iter(|ix| {
|
|
let dx2 = ix * ix;
|
|
(-radius..=radius).flat_map(move |iy| {
|
|
let dy2 = iy * iy;
|
|
let r2_xy = dx2 + dy2;
|
|
|
|
if r2_xy > radius_sq {
|
|
return Vec::new(); // this (x,y) column is outside
|
|
}
|
|
|
|
let max_z = ((radius_sq - r2_xy) as f32).sqrt() as i32;
|
|
(-max_z..=max_z)
|
|
.map(move |iz| {
|
|
let pos = Vec3::new(
|
|
center.x + ix as f32 * step,
|
|
center.y + iy as f32 * step,
|
|
center.z + iz as f32 * step,
|
|
);
|
|
(pos, Voxel::random_sides())
|
|
})
|
|
.collect::<Vec<_>>()
|
|
})
|
|
})
|
|
.collect();
|
|
|
|
// 2. Single-threaded insert (keeps `SparseVoxelOctree` API unchanged)
|
|
for (pos, voxel) in voxels {
|
|
octree.insert(pos, voxel);
|
|
}
|
|
}
|
|
|
|
fn generate_voxel_sphere(octree: &mut SparseVoxelOctree, planet_radius: i32) {
|
|
// For simplicity, we center the sphere around (0,0,0).
|
|
// We'll loop over a cubic region [-planet_radius, +planet_radius] in x, y, z
|
|
let min = -planet_radius;
|
|
let max = planet_radius;
|
|
|
|
let step = octree.get_spacing_at_depth(octree.max_depth);
|
|
|
|
for ix in min..=max {
|
|
let x = ix;
|
|
for iy in min..=max {
|
|
let y = iy;
|
|
for iz in min..=max {
|
|
let z = iz;
|
|
|
|
// Check if within sphere of radius `planet_radius`
|
|
let dist2 = x * x + y * y + z * z;
|
|
if dist2 <= planet_radius * planet_radius {
|
|
// Convert (x,y,z) to world space, stepping by `voxel_step`.
|
|
let wx = x as f32 * step;
|
|
let wy = y as f32 * step;
|
|
let wz = z as f32 * step;
|
|
let position = Vec3::new(wx, wy, wz);
|
|
|
|
// Insert the voxel
|
|
let voxel = Voxel::random_sides();
|
|
octree.insert(position, voxel);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// 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) {
|
|
// The dimensions of our rectangle: 16 x 256 x 16
|
|
let size_x = 16;
|
|
let size_y = 256;
|
|
let size_z = 16;
|
|
|
|
// We'll get the voxel spacing (size at the deepest level), same as in your sphere code.
|
|
let step = octree.get_spacing_at_depth(octree.max_depth);
|
|
|
|
// Triple-nested loop for each voxel in [0..16, 0..256, 0..16]
|
|
for ix in 0..size_x {
|
|
let x = ix as f32;
|
|
for iy in 0..size_y {
|
|
let y = iy as f32;
|
|
for iz in 0..size_z {
|
|
let z = iz as f32;
|
|
|
|
// Convert (x,y,z) to world coordinates
|
|
let wx = x * step;
|
|
let wy = y * step;
|
|
let wz = z * step;
|
|
|
|
let position = Vec3::new(wx, wy, wz);
|
|
|
|
// Insert the voxel
|
|
let voxel = Voxel::random_sides();
|
|
octree.insert(position, voxel);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn generate_large_plane(octree: &mut SparseVoxelOctree, width: usize, depth: usize) {
|
|
// We'll get the voxel spacing (size at the deepest level).
|
|
let step = octree.get_spacing_at_depth(octree.max_depth);
|
|
|
|
// Double-nested loop for each voxel in [0..width, 0..depth],
|
|
// with y=0.
|
|
for ix in 0..width {
|
|
let x = ix as f32;
|
|
for iz in 0..depth {
|
|
let z = iz as f32;
|
|
// y is always 0.
|
|
let y = 0.0;
|
|
|
|
// Convert (x,0,z) to world coordinates
|
|
let wx = x * step;
|
|
let wy = y * step;
|
|
let wz = z * step;
|
|
|
|
let position = Vec3::new(wx, wy, wz);
|
|
|
|
// Insert the voxel
|
|
let voxel = Voxel::random_sides();
|
|
octree.insert(position, voxel);
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn generate_solid_plane_with_noise(
|
|
octree: &mut SparseVoxelOctree,
|
|
width: usize,
|
|
depth: usize,
|
|
noise: &Perlin,
|
|
frequency: f32,
|
|
amplitude: f32,
|
|
) {
|
|
// Size of one voxel at the deepest level
|
|
let step = octree.get_spacing_at_depth(octree.max_depth);
|
|
|
|
for ix in 0..width {
|
|
let x = ix as f32;
|
|
for iz in 0..depth {
|
|
let z = iz as f32;
|
|
|
|
// Sample Perlin noise at scaled coordinates
|
|
let sample_x = x * frequency;
|
|
let sample_z = z * frequency;
|
|
let noise_val = noise.get([sample_x as f64, sample_z as f64]) as f32;
|
|
|
|
// Height in world units
|
|
let height_world = noise_val * amplitude;
|
|
// Convert height to number of voxel layers
|
|
let max_layer = (height_world / step).ceil() as usize;
|
|
|
|
// Fill from layer 0 up to max_layer
|
|
for iy in 0..=max_layer {
|
|
let position = Vec3::new(x * step, iy as f32 * step, z * step);
|
|
|
|
let voxel = Voxel::random_sides();
|
|
octree.insert(position, voxel);
|
|
}
|
|
}
|
|
}
|
|
}
|