mirror of
https://github.com/eliasstepanik/voxel-simulation.git
synced 2026-01-23 19:48:29 +00:00
Add octree serialization and sorted chunk loading
This commit is contained in:
parent
2f7128c55f
commit
78ee3483d7
@ -20,3 +20,4 @@ bitvec = "1.0.1"
|
|||||||
smallvec = "1.14.0"
|
smallvec = "1.14.0"
|
||||||
once_cell = "1.21.3"
|
once_cell = "1.21.3"
|
||||||
rayon = "1.10.0"
|
rayon = "1.10.0"
|
||||||
|
bincode = "1.3"
|
||||||
|
|||||||
@ -1,4 +1,7 @@
|
|||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
use std::path::Path;
|
||||||
|
use std::io;
|
||||||
|
use bincode;
|
||||||
use bevy::asset::Assets;
|
use bevy::asset::Assets;
|
||||||
use bevy::color::Color;
|
use bevy::color::Color;
|
||||||
use bevy::math::{DQuat, DVec3};
|
use bevy::math::{DQuat, DVec3};
|
||||||
@ -458,7 +461,32 @@ impl SparseVoxelOctree {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Save the octree to a file using bincode serialization.
|
||||||
|
pub fn save_to_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
|
||||||
|
let data = bincode::serialize(self)
|
||||||
|
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
|
||||||
|
std::fs::write(path, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Load an octree from a file and rebuild runtime caches.
|
||||||
|
pub fn load_from_file<P: AsRef<Path>>(path: P) -> io::Result<Self> {
|
||||||
|
let bytes = std::fs::read(path)?;
|
||||||
|
let mut tree: Self = bincode::deserialize(&bytes)
|
||||||
|
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
|
||||||
|
tree.rebuild_cache();
|
||||||
|
Ok(tree)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Rebuild runtime caches like occupied_chunks after loading.
|
||||||
|
pub fn rebuild_cache(&mut self) {
|
||||||
|
self.dirty.clear();
|
||||||
|
self.dirty_chunks.clear();
|
||||||
|
self.occupied_chunks.clear();
|
||||||
|
let voxels = Self::collect_voxels_from_node(&self.root, self.size);
|
||||||
|
for (pos, _voxel, _depth) in voxels {
|
||||||
|
let key = chunk_key_from_world(self, pos);
|
||||||
|
self.occupied_chunks.insert(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -24,15 +24,27 @@ pub fn enqueue_visible_chunks(
|
|||||||
prev_cam.0 = Some(centre);
|
prev_cam.0 = Some(centre);
|
||||||
|
|
||||||
let r = cfg.view_distance_chunks;
|
let r = cfg.view_distance_chunks;
|
||||||
for key in &tree.occupied_chunks {
|
|
||||||
let dx = key.0 - centre.0;
|
let mut keys: Vec<(ChunkKey, i32)> = tree
|
||||||
let dy = key.1 - centre.1;
|
.occupied_chunks
|
||||||
let dz = key.2 - centre.2;
|
.iter()
|
||||||
if dx.abs() > r || dy.abs() > r || dz.abs() > r { continue; }
|
.filter_map(|key| {
|
||||||
if spawned.0.contains_key(key) { continue; }
|
let dx = key.0 - centre.0;
|
||||||
if queue.set.contains(key) { continue; }
|
let dy = key.1 - centre.1;
|
||||||
queue.keys.push_back(*key);
|
let dz = key.2 - centre.2;
|
||||||
queue.set.insert(*key);
|
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();
|
||||||
|
|
||||||
|
keys.sort_by_key(|(_, d)| *d);
|
||||||
|
|
||||||
|
queue.keys.clear();
|
||||||
|
queue.set.clear();
|
||||||
|
for (key, _) in keys {
|
||||||
|
queue.keys.push_back(key);
|
||||||
|
queue.set.insert(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +1,29 @@
|
|||||||
use std::collections::{HashMap, HashSet, VecDeque};
|
use std::collections::{HashMap, HashSet, VecDeque};
|
||||||
use bevy::color::Color;
|
use bevy::color::Color;
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
|
use serde::{Serialize, Deserialize, Serializer, Deserializer};
|
||||||
|
|
||||||
|
fn serialize_color<S>(color: &Color, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
let [r, g, b, a] = color.as_linear_rgba_f32();
|
||||||
|
[r, g, b, a].serialize(serializer)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_color<'de, D>(deserializer: D) -> Result<Color, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let arr: [f32; 4] = Deserialize::deserialize(deserializer)?;
|
||||||
|
Ok(Color::rgba_linear(arr[0], arr[1], arr[2], arr[3]))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Represents a single voxel with a color.
|
/// Represents a single voxel with a color.
|
||||||
#[derive(Debug, Clone, Copy, Component, PartialEq, Default)]
|
#[derive(Debug, Clone, Copy, Component, PartialEq, Default, Serialize, Deserialize)]
|
||||||
pub struct Voxel {
|
pub struct Voxel {
|
||||||
|
#[serde(serialize_with = "serialize_color", deserialize_with = "deserialize_color")]
|
||||||
pub color: Color,
|
pub color: Color,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -16,7 +34,7 @@ pub struct DirtyVoxel {
|
|||||||
|
|
||||||
/// Represents a node in the sparse voxel octree.
|
/// Represents a node in the sparse voxel octree.
|
||||||
|
|
||||||
#[derive(Debug, Component, Clone)]
|
#[derive(Debug, Component, Clone, Serialize, Deserialize)]
|
||||||
pub struct OctreeNode {
|
pub struct OctreeNode {
|
||||||
pub children: Option<Box<[OctreeNode; 8]>>,
|
pub children: Option<Box<[OctreeNode; 8]>>,
|
||||||
pub voxel: Option<Voxel>,
|
pub voxel: Option<Voxel>,
|
||||||
@ -24,7 +42,7 @@ pub struct OctreeNode {
|
|||||||
}
|
}
|
||||||
/// Represents the root of the sparse voxel octree.
|
/// Represents the root of the sparse voxel octree.
|
||||||
/// Represents the root of the sparse voxel octree.
|
/// Represents the root of the sparse voxel octree.
|
||||||
#[derive(Debug, Component)]
|
#[derive(Debug, Component, Serialize, Deserialize)]
|
||||||
pub struct SparseVoxelOctree {
|
pub struct SparseVoxelOctree {
|
||||||
|
|
||||||
pub root: OctreeNode,
|
pub root: OctreeNode,
|
||||||
@ -34,8 +52,11 @@ pub struct SparseVoxelOctree {
|
|||||||
pub show_world_grid: bool,
|
pub show_world_grid: bool,
|
||||||
pub show_chunks: bool,
|
pub show_chunks: bool,
|
||||||
|
|
||||||
|
#[serde(skip)]
|
||||||
pub dirty: Vec<DirtyVoxel>,
|
pub dirty: Vec<DirtyVoxel>,
|
||||||
|
#[serde(skip)]
|
||||||
pub dirty_chunks: HashSet<ChunkKey>,
|
pub dirty_chunks: HashSet<ChunkKey>,
|
||||||
|
#[serde(skip)]
|
||||||
pub occupied_chunks: HashSet<ChunkKey>,
|
pub occupied_chunks: HashSet<ChunkKey>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,7 +122,7 @@ pub struct Chunk {
|
|||||||
pub struct ChunkLod(pub u32);
|
pub struct ChunkLod(pub u32);
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub struct ChunkKey(pub i32, pub i32, pub i32);
|
pub struct ChunkKey(pub i32, pub i32, pub i32);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user