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]]
|
||||
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)",
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 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<String, Aabb>, // 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<BluePrintsConfig>) -> 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),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -27,6 +27,7 @@ impl Plugin for CorePlugin {
|
|||
BlueprintsPlugin {
|
||||
library_folder: "models/library".into(),
|
||||
format: GltfFormat::GLB,
|
||||
aabbs: true,
|
||||
..Default::default()
|
||||
},
|
||||
));
|
||||
|
|
Loading…
Reference in New Issue