Skip to content

Commit

Permalink
Got lods to not rerender everything every time
Browse files Browse the repository at this point in the history
  • Loading branch information
AnthonyTornetta committed Sep 4, 2023
1 parent f078fc9 commit 2092e02
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 159 deletions.
134 changes: 36 additions & 98 deletions cosmos_client/src/rendering/lod_renderer.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use std::{f32::consts::PI, sync::Mutex};

use bevy::{pbr::NotShadowCaster, prelude::*, render::primitives::Aabb, utils::HashMap};
use bevy::{prelude::*, render::primitives::Aabb, utils::HashMap};
use cosmos_core::{
block::{Block, BlockFace},
registry::{identifiable::Identifiable, many_to_one::ManyToOneRegistry, Registry},
structure::{
block_storage::BlockStorer,
chunk::{CHUNK_DIMENSIONS, CHUNK_DIMENSIONSF},
coordinates::{ChunkBlockCoordinate, ChunkCoordinate},
coordinates::ChunkBlockCoordinate,
lod::Lod,
lod_chunk::LodChunk,
Structure,
Expand Down Expand Up @@ -423,11 +423,9 @@ fn find_non_dirty(lod: &Lod, offset: Vec3, to_process: &mut Vec<Vec3>, scale: f3
});
}
Lod::Single(_, dirty) => {
if *dirty {
return;
if !*dirty {
to_process.push(offset);
}

to_process.push(offset);
}
};
}
Expand All @@ -436,7 +434,6 @@ fn find_non_dirty(lod: &Lod, offset: Vec3, to_process: &mut Vec<Vec3>, scale: f3
fn monitor_lods_needs_rendered_system(
mut commands: Commands,
atlas: Res<MainAtlas>,
mesh_query: Query<Option<&Handle<Mesh>>>,
mut meshes: ResMut<Assets<Mesh>>,
blocks: Res<Registry<Block>>,
materials: Res<ManyToOneRegistry<Block, CosmosMaterial>>,
Expand All @@ -457,10 +454,8 @@ fn monitor_lods_needs_rendered_system(

// Render lods in parallel
todo.par_iter_mut().for_each(|(entity, lod, structure)| {
let scale = structure.chunk_dimensions().x as f32;

let mut non_dirty = vec![];
find_non_dirty(lod, Vec3::ZERO, &mut non_dirty, scale);
find_non_dirty(lod, Vec3::ZERO, &mut non_dirty, structure.block_dimensions().x as f32);

to_keep
.lock()
Expand All @@ -479,7 +474,7 @@ fn monitor_lods_needs_rendered_system(
&materials,
&meshes_registry,
&block_textures,
scale,
structure.chunk_dimensions().x as f32,
);
});

Expand All @@ -493,110 +488,53 @@ fn monitor_lods_needs_rendered_system(
ent_meshes.get_mut(&entity).expect("Just added").push((chunk_mesh, offset));
}

for (entity, mut lod_meshes) in ent_meshes {
let mut old_mesh_entities = Vec::new();
for (entity, lod_meshes) in ent_meshes {
let old_mesh_entities = chunk_meshes_query.get(entity).map(|x| x.0.clone()).unwrap_or_default();

let to_keep_locations = to_keep.lock().unwrap().take().unwrap_or_default();

let to_keep_locations = to_keep_locations.get(&entity);

if let Ok(chunk_meshes_component) = chunk_meshes_query.get(entity) {
for ent in chunk_meshes_component.0.iter() {
let old_mesh_handle = mesh_query.get(*ent).expect("This should have a mesh component.");

if let Some(old_mesh_handle) = old_mesh_handle {
meshes.remove(old_mesh_handle);
}

old_mesh_entities.push(*ent);
}
}

let mut entities_to_add = Vec::new();

// If the structure previously only had one chunk mesh, then it would be on
// the structure entity instead of child entities
commands
.entity(entity)
.remove::<Handle<Mesh>>()
.remove::<Handle<StandardMaterial>>();

let mut structure_meshes_component = LodMeshes::default();

let single = lod_meshes.len() == 1 && lod_meshes.first().map(|(x, _)| x.mesh_materials.len() == 1).unwrap_or(false);
for (lod_mesh, offset) in lod_meshes {
for mesh_material in lod_mesh.mesh_materials {
let mesh = meshes.add(mesh_material.mesh);

if !single {
for (lod_mesh, offset) in lod_meshes {
for mesh_material in lod_mesh.mesh_materials {
let mesh = meshes.add(mesh_material.mesh);
let s = (CHUNK_DIMENSIONS / 2) as f32 * lod_mesh.scale;

let s = (CHUNK_DIMENSIONS / 2) as f32 * lod_mesh.scale;

let ent = if let Some(ent) = old_mesh_entities.pop() {
commands.entity(ent).insert((
TransformBundle::from_transform(Transform::from_translation(offset)),
let ent = commands
.spawn((
PbrBundle {
mesh,
mesh_material.material,
// Remove this once https://github.com/bevyengine/bevy/issues/4294 is done (bevy 0.12 released)
Aabb::from_min_max(Vec3::new(-s, -s, -s), Vec3::new(s, s, s)),
));

ent
} else {
let s = (CHUNK_DIMENSIONS / 2) as f32 * lod_mesh.scale;

let ent = commands
.spawn((
PbrBundle {
mesh,
material: mesh_material.material,
transform: Transform::from_translation(offset),
..Default::default()
},
NotShadowCaster,
// Remove this once https://github.com/bevyengine/bevy/issues/4294 is done (bevy 0.12 released)
Aabb::from_min_max(Vec3::new(-s, -s, -s), Vec3::new(s, s, s)),
))
.id();

entities_to_add.push(ent);

ent
};

structure_meshes_component.0.push(ent);
}
material: mesh_material.material,
transform: Transform::from_translation(offset),
..Default::default()
},
// Remove this once https://github.com/bevyengine/bevy/issues/4294 is done (bevy 0.12 released)
Aabb::from_min_max(Vec3::new(-s, -s, -s), Vec3::new(s, s, s)),
))
.id();

entities_to_add.push(ent);

structure_meshes_component.0.push(ent);
}
} else {
// To avoid making too many entities (and tanking performance), if only one mesh
// is present, just stick the mesh info onto the chunk itself.

// offset (_) will always be Vec3::ZERO when there is just one
let (chunk_mesh, _) = &mut lod_meshes[0];
let mesh_material = chunk_mesh.mesh_materials.pop().expect("This has one element in it");

let mesh = meshes.add(mesh_material.mesh);
let s = (CHUNK_DIMENSIONS / 2) as f32 * chunk_mesh.scale;

commands.entity(entity).insert((
mesh,
mesh_material.material,
NotShadowCaster,
// Remove this once https://github.com/bevyengine/bevy/issues/4294 is done (bevy 0.12 released)
Aabb::from_min_max(Vec3::new(-s, -s, -s), Vec3::new(s, s, s)),
));
}

// Any leftover entities are useless now, so kill them
// Any dirty entities are useless now, so kill them
for mesh_entity in old_mesh_entities {
if let Ok(transform) = transform_query.get(mesh_entity) {
if to_keep_locations.map(|x| x.contains(&transform.translation)).unwrap_or(false) {
structure_meshes_component.0.push(mesh_entity);
continue;
}
let is_clean = transform_query
.get(mesh_entity)
.map(|transform| to_keep_locations.map(|x| x.contains(&transform.translation)).unwrap_or(false))
.unwrap_or(false);
if is_clean {
structure_meshes_component.0.push(mesh_entity);
} else {
commands.entity(mesh_entity).despawn_recursive();
}

commands.entity(mesh_entity).despawn_recursive();
}

let mut entity_commands = commands.entity(entity);
Expand Down
57 changes: 2 additions & 55 deletions cosmos_client/src/structure/planet/client_planet_builder.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,16 @@
//! Responsible for building planets for the client.
use bevy::{
ecs::system::EntityCommands,
pbr::NotShadowCaster,
prelude::{
shape::UVSphere, Added, App, Assets, Color, Commands, ComputedVisibility, Entity, Mesh, Query, Res, ResMut, StandardMaterial,
Update, Visibility,
},
};
use bevy::ecs::system::EntityCommands;
use cosmos_core::{
physics::location::Location,
registry::Registry,
structure::{
planet::{biosphere::BiosphereMarker, planet_builder::PlanetBuilder, planet_builder::TPlanetBuilder, Planet},
planet::{planet_builder::PlanetBuilder, planet_builder::TPlanetBuilder, Planet},
Structure,
},
};

use crate::structure::client_structure_builder::ClientStructureBuilder;

use super::biosphere::BiosphereColor;

/// Responsible for building planets for the client.
pub struct ClientPlanetBuilder {
planet_builder: PlanetBuilder<ClientStructureBuilder>,
Expand All @@ -39,46 +29,3 @@ impl TPlanetBuilder for ClientPlanetBuilder {
self.planet_builder.insert_planet(entity, location, structure, planet);
}
}

fn added_planet(
query: Query<(Entity, &Structure, &BiosphereMarker), Added<Planet>>,
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
color_registry: Res<Registry<BiosphereColor>>,
) {
for (ent, structure, marker) in query.iter() {
let Structure::Dynamic(structure) = structure else {
panic!("Invalid planet structure! It must be dynamic!");
};

let blocks_radius = structure.block_dimensions() as f32 / 2.0;

commands.entity(ent).insert((
meshes.add(
UVSphere {
radius: (blocks_radius * blocks_radius * 2.0).sqrt() * 1.1,
sectors: 128,
stacks: 128,
}
.into(),
),
materials.add(StandardMaterial {
base_color: color_registry
.from_id(marker.biosphere_name())
.map(|x| x.color())
.unwrap_or(Color::WHITE),

perceptual_roughness: 1.0,
..Default::default()
}),
Visibility::default(),
ComputedVisibility::default(),
NotShadowCaster,
));
}
}

pub(super) fn register(app: &mut App) {
app.add_systems(Update, added_planet);
}
2 changes: 0 additions & 2 deletions cosmos_client/src/structure/planet/lod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,7 @@ fn listen_for_new_lods(
if let Ok(mut cur_lod) = cur_lod {
delta_lod.apply_changes(&mut cur_lod);
} else {
println!("Creating delta: {delta_lod:?}");
ecmds.insert(delta_lod.create_lod());
ecmds.log_components();
}
}
}
Expand Down
1 change: 0 additions & 1 deletion cosmos_client/src/structure/planet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,6 @@ pub fn unload_chunks_far_from_players(

pub(super) fn register(app: &mut App) {
align_player::register(app);
client_planet_builder::register(app);
biosphere::register(app);
lod::register(app);

Expand Down
8 changes: 8 additions & 0 deletions cosmos_core/src/structure/lod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ pub enum LodDelta {
}

impl LodDelta {
/// Creates an lod based off this delta.
///
/// # Panics
/// if self contains any LodDelta::NoChange because these must have a corresponding lod.
pub fn create_lod(self) -> Lod {
match self {
LodDelta::Children(children) => {
Expand Down Expand Up @@ -88,6 +92,10 @@ impl LodDelta {
}
}

/// Applies the delta changes to a present lod
///
/// # Panics
/// if self contains any LodDelta::NoChange and there is no matching lod for that.
pub fn apply_changes(self, lod: &mut Lod) {
match self {
LodDelta::Children(children) => {
Expand Down
3 changes: 0 additions & 3 deletions cosmos_server/src/structure/planet/lods/generate_lods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,9 +157,6 @@ fn check_done_generating(
let cloned_delta = lod_delta.clone();

if let Some(Ok(mut current_lod)) = current_lod {
println!("{lod_delta:?}");
println!("==========================");
println!("{current_lod:?}");
cloned_delta.apply_changes(&mut current_lod.lod);
current_lod.deltas.push(lod_delta);
} else {
Expand Down

0 comments on commit 2092e02

Please sign in to comment.