From 9a765d5e12aa658ca584280941ca74d47233c511 Mon Sep 17 00:00:00 2001 From: Mark Moissette Date: Sat, 25 Nov 2023 02:35:48 +0100 Subject: [PATCH] feat(bevy_gltf_blueprints): added ability to generate blueprint/scene aabbs automatically (#57) * settable via a config flag & systems won't run if the flag is not set * caches aabbs per blueprint name so they do not need to be recomputed multiple time for the same blueprint * closes #56 --- Cargo.lock | 2 +- crates/bevy_gltf_blueprints/Cargo.toml | 2 +- crates/bevy_gltf_blueprints/README.md | 2 + crates/bevy_gltf_blueprints/src/aabb.rs | 61 +++++++++++++++++++ crates/bevy_gltf_blueprints/src/lib.rs | 36 ++++++++--- .../src/spawn_from_blueprints.rs | 3 +- .../basic/src/core/mod.rs | 1 + 7 files changed, 94 insertions(+), 13 deletions(-) create mode 100644 crates/bevy_gltf_blueprints/src/aabb.rs diff --git a/Cargo.lock b/Cargo.lock index 0d1ea58..5c74ee6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -755,7 +755,7 @@ dependencies = [ [[package]] name = "bevy_gltf_blueprints" -version = "0.3.1" +version = "0.3.2" dependencies = [ "bevy", "bevy_gltf_components 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/crates/bevy_gltf_blueprints/Cargo.toml b/crates/bevy_gltf_blueprints/Cargo.toml index 2ccec3b..43ac2b4 100644 --- a/crates/bevy_gltf_blueprints/Cargo.toml +++ b/crates/bevy_gltf_blueprints/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_gltf_blueprints" -version = "0.3.1" +version = "0.3.2" authors = ["Mark 'kaosat-dev' Moissette"] description = "Adds the ability to define Blueprints/Prefabs for [Bevy](https://bevyengine.org/) inside gltf files and spawn them in Bevy." homepage = "https://github.com/kaosat-dev/Blender_bevy_components_workflow" diff --git a/crates/bevy_gltf_blueprints/README.md b/crates/bevy_gltf_blueprints/README.md index 7fb7fe4..7ce434f 100644 --- a/crates/bevy_gltf_blueprints/README.md +++ b/crates/bevy_gltf_blueprints/README.md @@ -102,6 +102,8 @@ fn main() { BlueprintsPlugin{ library_folder: "advanced/models/library".into() // replace this with your blueprints library path , relative to the assets folder, format: GltfFormat::GLB,// optional, use either format: GltfFormat::GLB, or format: GltfFormat::GLTF, or ..Default::default() if you want to keep the default .glb extension, this sets what extensions/ gltf files will be looked for by the library + aabbs: true, // defaults to false, enable this to automatically calculate aabb for the scene/blueprint + ..Default::default() } ) .run(); diff --git a/crates/bevy_gltf_blueprints/src/aabb.rs b/crates/bevy_gltf_blueprints/src/aabb.rs new file mode 100644 index 0000000..b3e0d58 --- /dev/null +++ b/crates/bevy_gltf_blueprints/src/aabb.rs @@ -0,0 +1,61 @@ +use bevy::{math::Vec3A, prelude::*, render::primitives::Aabb}; + +use crate::{BluePrintsConfig, BlueprintName, SpawnedRoot}; + +/// helper system that computes the compound aabbs of the scenes/blueprints +pub fn compute_scene_aabbs( + root_entities: Query< + (Entity, &Name, &Children, &BlueprintName), + (With, Without), + >, + children: Query<&Children>, + existing_aabbs: Query<&Aabb>, + + mut blueprints_config: ResMut, + mut commands: Commands, +) { + // compute compound aabb + for root_entity in root_entities.iter() { + let name = &root_entity.3 .0; + + let root_entity = root_entity.2.first().unwrap(); + + // only recompute aabb if it has not already been done before + if !blueprints_config.aabb_cache.contains_key(&name.to_string()) { + let aabb = compute_descendant_aabb(*root_entity, &children, &existing_aabbs); + commands.entity(*root_entity).insert(aabb); + + blueprints_config.aabb_cache.insert(name.to_string(), aabb); + } + } +} + +pub fn compute_descendant_aabb( + root_entity: Entity, + children: &Query<&Children>, + existing_aabbs: &Query<&Aabb>, +) -> Aabb { + if let Ok(children_list) = children.get(root_entity) { + let mut chilren_aabbs: Vec = vec![]; + for child in children_list.iter() { + if let Ok(aabb) = existing_aabbs.get(*child) { + chilren_aabbs.push(*aabb); + } else { + let aabb = compute_descendant_aabb(*child, children, &existing_aabbs); + chilren_aabbs.push(aabb); + } + } + + let mut min = Vec3A::splat(f32::MAX); + let mut max = Vec3A::splat(f32::MIN); + for aabb in chilren_aabbs.iter() { + min = min.min(aabb.min()); + max = max.max(aabb.max()); + } + let aabb = Aabb::from_min_max(Vec3::from(min), Vec3::from(max)); + + return aabb; + } + + return Aabb::default(); +} diff --git a/crates/bevy_gltf_blueprints/src/lib.rs b/crates/bevy_gltf_blueprints/src/lib.rs index a085279..9e0903f 100644 --- a/crates/bevy_gltf_blueprints/src/lib.rs +++ b/crates/bevy_gltf_blueprints/src/lib.rs @@ -7,13 +7,16 @@ pub(crate) use spawn_post_process::*; pub mod animation; pub use animation::*; +pub mod aabb; +pub use aabb::*; + pub mod clone_entity; pub use clone_entity::*; use core::fmt; use std::path::PathBuf; -use bevy::prelude::*; +use bevy::{prelude::*, render::primitives::Aabb, utils::HashMap}; use bevy_gltf_components::{ComponentsFromGltfPlugin, GltfComponentsSet}; #[derive(SystemSet, Debug, Hash, PartialEq, Eq, Clone)] @@ -40,37 +43,41 @@ impl Default for BluePrintBundle { } #[derive(Clone, Resource)] -pub(crate) struct BluePrintsConfig { +pub struct BluePrintsConfig { pub(crate) format: GltfFormat, pub(crate) library_folder: PathBuf, + pub(crate) aabbs: bool, + + pub(crate) aabb_cache: HashMap, // cache for aabbs } #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Default)] pub enum GltfFormat { #[default] GLB, - GLTF + GLTF, } impl fmt::Display for GltfFormat { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { GltfFormat::GLB => { - write!(f, "glb", ) + write!(f, "glb",) } - GltfFormat::GLTF => { + GltfFormat::GLTF => { write!(f, "gltf") } } } } - #[derive(Debug, Clone)] +/// Plugin for gltf blueprints pub struct BlueprintsPlugin { pub format: GltfFormat, /// The base folder where library/blueprints assets are loaded from, relative to the executable. pub library_folder: PathBuf, + pub aabbs: bool, } impl Default for BlueprintsPlugin { @@ -78,10 +85,15 @@ impl Default for BlueprintsPlugin { Self { format: GltfFormat::GLB, library_folder: PathBuf::from("models/library"), + aabbs: false, } } } +fn aabbs_enabled(blueprints_config: Res) -> bool { + blueprints_config.aabbs +} + impl Plugin for BlueprintsPlugin { fn build(&self, app: &mut App) { app.add_plugins(ComponentsFromGltfPlugin) @@ -91,6 +103,8 @@ impl Plugin for BlueprintsPlugin { .insert_resource(BluePrintsConfig { format: self.format.clone(), library_folder: self.library_folder.clone(), + aabbs: self.aabbs, + aabb_cache: HashMap::new(), }) .configure_sets( Update, @@ -100,21 +114,23 @@ impl Plugin for BlueprintsPlugin { ) .add_systems( Update, - (spawn_from_blueprints) - // .run_if(in_state(AppState::AppRunning).or_else(in_state(AppState::LoadingGame))) // FIXME: how to replace this with a crate compatible version ? + ( + spawn_from_blueprints, + compute_scene_aabbs.run_if(aabbs_enabled), + apply_deferred.run_if(aabbs_enabled), + ) + .chain() .in_set(GltfBlueprintsSet::Spawn), ) .add_systems( Update, ( - // spawn_entities, update_spawned_root_first_child, apply_deferred, cleanup_scene_instances, apply_deferred, ) .chain() - // .run_if(in_state(AppState::LoadingGame).or_else(in_state(AppState::AppRunning))) // FIXME: how to replace this with a crate compatible version ? .in_set(GltfBlueprintsSet::AfterSpawn), ); } diff --git a/crates/bevy_gltf_blueprints/src/spawn_from_blueprints.rs b/crates/bevy_gltf_blueprints/src/spawn_from_blueprints.rs index 7cb7200..322d066 100644 --- a/crates/bevy_gltf_blueprints/src/spawn_from_blueprints.rs +++ b/crates/bevy_gltf_blueprints/src/spawn_from_blueprints.rs @@ -82,9 +82,10 @@ pub(crate) fn spawn_from_blueprints( transform: transform.clone(), ..Default::default() }, - bevy::prelude::Name::from(["scene_wrapper", &name.clone()].join("_")), + bevy::prelude::Name::from(["scene_wrapper", &name.clone()].join("_")), //TODO: remove this convoluted bit // Parent(world) // FIXME/ would be good if this worked directly SpawnedRoot, + BlueprintName(blupeprint_name.0.clone()), Original(entity), Animations { named_animations: gltf.named_animations.clone(), diff --git a/examples/bevy_gltf_blueprints/basic/src/core/mod.rs b/examples/bevy_gltf_blueprints/basic/src/core/mod.rs index 080e18f..f914563 100644 --- a/examples/bevy_gltf_blueprints/basic/src/core/mod.rs +++ b/examples/bevy_gltf_blueprints/basic/src/core/mod.rs @@ -27,6 +27,7 @@ impl Plugin for CorePlugin { BlueprintsPlugin { library_folder: "models/library".into(), format: GltfFormat::GLB, + aabbs: true, ..Default::default() }, ));