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
This commit is contained in:
parent
8e67f76d28
commit
9a765d5e12
|
@ -755,7 +755,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bevy_gltf_blueprints"
|
name = "bevy_gltf_blueprints"
|
||||||
version = "0.3.1"
|
version = "0.3.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bevy",
|
"bevy",
|
||||||
"bevy_gltf_components 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bevy_gltf_components 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "bevy_gltf_blueprints"
|
name = "bevy_gltf_blueprints"
|
||||||
version = "0.3.1"
|
version = "0.3.2"
|
||||||
authors = ["Mark 'kaosat-dev' Moissette"]
|
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."
|
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"
|
homepage = "https://github.com/kaosat-dev/Blender_bevy_components_workflow"
|
||||||
|
|
|
@ -102,6 +102,8 @@ fn main() {
|
||||||
BlueprintsPlugin{
|
BlueprintsPlugin{
|
||||||
library_folder: "advanced/models/library".into() // replace this with your blueprints library path , relative to the assets folder,
|
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
|
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();
|
.run();
|
||||||
|
|
|
@ -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<SpawnedRoot>, Without<Aabb>),
|
||||||
|
>,
|
||||||
|
children: Query<&Children>,
|
||||||
|
existing_aabbs: Query<&Aabb>,
|
||||||
|
|
||||||
|
mut blueprints_config: ResMut<BluePrintsConfig>,
|
||||||
|
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<Aabb> = 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();
|
||||||
|
}
|
|
@ -7,13 +7,16 @@ pub(crate) use spawn_post_process::*;
|
||||||
pub mod animation;
|
pub mod animation;
|
||||||
pub use animation::*;
|
pub use animation::*;
|
||||||
|
|
||||||
|
pub mod aabb;
|
||||||
|
pub use aabb::*;
|
||||||
|
|
||||||
pub mod clone_entity;
|
pub mod clone_entity;
|
||||||
pub use clone_entity::*;
|
pub use clone_entity::*;
|
||||||
|
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use bevy::prelude::*;
|
use bevy::{prelude::*, render::primitives::Aabb, utils::HashMap};
|
||||||
use bevy_gltf_components::{ComponentsFromGltfPlugin, GltfComponentsSet};
|
use bevy_gltf_components::{ComponentsFromGltfPlugin, GltfComponentsSet};
|
||||||
|
|
||||||
#[derive(SystemSet, Debug, Hash, PartialEq, Eq, Clone)]
|
#[derive(SystemSet, Debug, Hash, PartialEq, Eq, Clone)]
|
||||||
|
@ -40,37 +43,41 @@ impl Default for BluePrintBundle {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Resource)]
|
#[derive(Clone, Resource)]
|
||||||
pub(crate) struct BluePrintsConfig {
|
pub struct BluePrintsConfig {
|
||||||
pub(crate) format: GltfFormat,
|
pub(crate) format: GltfFormat,
|
||||||
pub(crate) library_folder: PathBuf,
|
pub(crate) library_folder: PathBuf,
|
||||||
|
pub(crate) aabbs: bool,
|
||||||
|
|
||||||
|
pub(crate) aabb_cache: HashMap<String, Aabb>, // cache for aabbs
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Default)]
|
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Default)]
|
||||||
pub enum GltfFormat {
|
pub enum GltfFormat {
|
||||||
#[default]
|
#[default]
|
||||||
GLB,
|
GLB,
|
||||||
GLTF
|
GLTF,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for GltfFormat {
|
impl fmt::Display for GltfFormat {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
GltfFormat::GLB => {
|
GltfFormat::GLB => {
|
||||||
write!(f, "glb", )
|
write!(f, "glb",)
|
||||||
}
|
}
|
||||||
GltfFormat::GLTF => {
|
GltfFormat::GLTF => {
|
||||||
write!(f, "gltf")
|
write!(f, "gltf")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
/// Plugin for gltf blueprints
|
||||||
pub struct BlueprintsPlugin {
|
pub struct BlueprintsPlugin {
|
||||||
pub format: GltfFormat,
|
pub format: GltfFormat,
|
||||||
/// The base folder where library/blueprints assets are loaded from, relative to the executable.
|
/// The base folder where library/blueprints assets are loaded from, relative to the executable.
|
||||||
pub library_folder: PathBuf,
|
pub library_folder: PathBuf,
|
||||||
|
pub aabbs: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for BlueprintsPlugin {
|
impl Default for BlueprintsPlugin {
|
||||||
|
@ -78,10 +85,15 @@ impl Default for BlueprintsPlugin {
|
||||||
Self {
|
Self {
|
||||||
format: GltfFormat::GLB,
|
format: GltfFormat::GLB,
|
||||||
library_folder: PathBuf::from("models/library"),
|
library_folder: PathBuf::from("models/library"),
|
||||||
|
aabbs: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn aabbs_enabled(blueprints_config: Res<BluePrintsConfig>) -> bool {
|
||||||
|
blueprints_config.aabbs
|
||||||
|
}
|
||||||
|
|
||||||
impl Plugin for BlueprintsPlugin {
|
impl Plugin for BlueprintsPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.add_plugins(ComponentsFromGltfPlugin)
|
app.add_plugins(ComponentsFromGltfPlugin)
|
||||||
|
@ -91,6 +103,8 @@ impl Plugin for BlueprintsPlugin {
|
||||||
.insert_resource(BluePrintsConfig {
|
.insert_resource(BluePrintsConfig {
|
||||||
format: self.format.clone(),
|
format: self.format.clone(),
|
||||||
library_folder: self.library_folder.clone(),
|
library_folder: self.library_folder.clone(),
|
||||||
|
aabbs: self.aabbs,
|
||||||
|
aabb_cache: HashMap::new(),
|
||||||
})
|
})
|
||||||
.configure_sets(
|
.configure_sets(
|
||||||
Update,
|
Update,
|
||||||
|
@ -100,21 +114,23 @@ impl Plugin for BlueprintsPlugin {
|
||||||
)
|
)
|
||||||
.add_systems(
|
.add_systems(
|
||||||
Update,
|
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),
|
.in_set(GltfBlueprintsSet::Spawn),
|
||||||
)
|
)
|
||||||
.add_systems(
|
.add_systems(
|
||||||
Update,
|
Update,
|
||||||
(
|
(
|
||||||
// spawn_entities,
|
|
||||||
update_spawned_root_first_child,
|
update_spawned_root_first_child,
|
||||||
apply_deferred,
|
apply_deferred,
|
||||||
cleanup_scene_instances,
|
cleanup_scene_instances,
|
||||||
apply_deferred,
|
apply_deferred,
|
||||||
)
|
)
|
||||||
.chain()
|
.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),
|
.in_set(GltfBlueprintsSet::AfterSpawn),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,9 +82,10 @@ pub(crate) fn spawn_from_blueprints(
|
||||||
transform: transform.clone(),
|
transform: transform.clone(),
|
||||||
..Default::default()
|
..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
|
// Parent(world) // FIXME/ would be good if this worked directly
|
||||||
SpawnedRoot,
|
SpawnedRoot,
|
||||||
|
BlueprintName(blupeprint_name.0.clone()),
|
||||||
Original(entity),
|
Original(entity),
|
||||||
Animations {
|
Animations {
|
||||||
named_animations: gltf.named_animations.clone(),
|
named_animations: gltf.named_animations.clone(),
|
||||||
|
|
|
@ -27,6 +27,7 @@ impl Plugin for CorePlugin {
|
||||||
BlueprintsPlugin {
|
BlueprintsPlugin {
|
||||||
library_folder: "models/library".into(),
|
library_folder: "models/library".into(),
|
||||||
format: GltfFormat::GLB,
|
format: GltfFormat::GLB,
|
||||||
|
aabbs: true,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
|
|
Loading…
Reference in New Issue