From 4affc8cd93942f91f62ed1c5f9a2107864eb9319 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois?= Date: Mon, 18 Jul 2022 23:27:30 +0000 Subject: [PATCH] add a SpatialBundle with visibility and transform components (#5344) # Objective - Help user when they need to add both a `TransformBundle` and a `VisibilityBundle` ## Solution - Add a `SpatialBundle` adding all components --- crates/bevy_gltf/src/loader.rs | 11 ++-- crates/bevy_render/src/lib.rs | 2 + crates/bevy_render/src/spatial_bundle.rs | 59 +++++++++++++++++++ crates/bevy_render/src/view/visibility/mod.rs | 23 +++++++- .../src/components/global_transform.rs | 2 +- .../src/components/transform.rs | 2 +- crates/bevy_transform/src/lib.rs | 2 +- examples/animation/animated_transform.rs | 3 +- 8 files changed, 92 insertions(+), 12 deletions(-) create mode 100644 crates/bevy_render/src/spatial_bundle.rs diff --git a/crates/bevy_gltf/src/loader.rs b/crates/bevy_gltf/src/loader.rs index 5be5526d62..19a626a9f7 100644 --- a/crates/bevy_gltf/src/loader.rs +++ b/crates/bevy_gltf/src/loader.rs @@ -22,16 +22,17 @@ use bevy_render::{ skinning::{SkinnedMesh, SkinnedMeshInverseBindposes}, Indices, Mesh, VertexAttributeValues, }, + prelude::SpatialBundle, primitives::{Aabb, Frustum}, render_resource::{AddressMode, Face, FilterMode, PrimitiveTopology, SamplerDescriptor}, renderer::RenderDevice, texture::{CompressedImageFormats, Image, ImageSampler, ImageType, TextureError}, - view::{VisibilityBundle, VisibleEntities}, + view::VisibleEntities, }; use bevy_scene::Scene; #[cfg(not(target_arch = "wasm32"))] use bevy_tasks::IoTaskPool; -use bevy_transform::{components::Transform, TransformBundle}; +use bevy_transform::components::Transform; use bevy_utils::{HashMap, HashSet}; use gltf::{ @@ -465,8 +466,7 @@ async fn load_gltf<'a, 'b>( world .spawn() - .insert_bundle(TransformBundle::identity()) - .insert_bundle(VisibilityBundle::default()) + .insert_bundle(SpatialBundle::visible_identity()) .with_children(|parent| { for node in scene.nodes() { let result = load_node( @@ -705,10 +705,9 @@ fn load_node( ) -> Result<(), GltfError> { let transform = gltf_node.transform(); let mut gltf_error = None; - let mut node = world_builder.spawn_bundle(TransformBundle::from(Transform::from_matrix( + let mut node = world_builder.spawn_bundle(SpatialBundle::from(Transform::from_matrix( Mat4::from_cols_array_2d(&transform.matrix()), ))); - node.insert_bundle(VisibilityBundle::default()); node.insert(node_name(gltf_node)); diff --git a/crates/bevy_render/src/lib.rs b/crates/bevy_render/src/lib.rs index d0ebc02b9c..bebf80dde2 100644 --- a/crates/bevy_render/src/lib.rs +++ b/crates/bevy_render/src/lib.rs @@ -14,6 +14,7 @@ pub mod render_phase; pub mod render_resource; pub mod renderer; pub mod settings; +mod spatial_bundle; pub mod texture; pub mod view; @@ -26,6 +27,7 @@ pub mod prelude { color::Color, mesh::{shape, Mesh}, render_resource::Shader, + spatial_bundle::SpatialBundle, texture::Image, view::{ComputedVisibility, Msaa, Visibility, VisibilityBundle}, }; diff --git a/crates/bevy_render/src/spatial_bundle.rs b/crates/bevy_render/src/spatial_bundle.rs new file mode 100644 index 0000000000..152a14ebf2 --- /dev/null +++ b/crates/bevy_render/src/spatial_bundle.rs @@ -0,0 +1,59 @@ +use bevy_ecs::prelude::Bundle; +use bevy_transform::prelude::{GlobalTransform, Transform}; + +use crate::view::{ComputedVisibility, Visibility}; + +/// A [`Bundle`] with the following [`Component`](bevy_ecs::component::Component)s: +/// * [`Visibility`] and [`ComputedVisibility`], which describe the visibility of an entity +/// * [`Transform`] and [`GlobalTransform`], which describe the position of an entity +/// +/// * To show or hide an entity, you should set its [`Visibility`]. +/// * To get the computed visibility of an entity, you should get its [`ComputedVisibility`]. +/// * To place or move an entity, you should set its [`Transform`]. +/// * To get the global transform of an entity, you should get its [`GlobalTransform`]. +/// * For hierarchies to work correctly, you must have all four components. +/// * You may use the [`SpatialBundle`] to guarantee this. +#[derive(Bundle, Debug, Default)] +pub struct SpatialBundle { + /// The visibility of the entity. + pub visibility: Visibility, + /// The computed visibility of the entity. + pub computed: ComputedVisibility, + /// The transform of the entity. + pub transform: Transform, + /// The global transform of the entity. + pub global_transform: GlobalTransform, +} + +impl SpatialBundle { + /// Creates a new [`SpatialBundle`] from a [`Transform`]. + /// + /// This initializes [`GlobalTransform`] as identity, and visibility as visible + #[inline] + pub const fn from_transform(transform: Transform) -> Self { + SpatialBundle { + transform, + // Note: `..Default::default()` cannot be used here, because it isn't const + ..Self::visible_identity() + } + } + + /// Creates a new identity [`SpatialBundle`], with no translation, rotation, and a scale of 1 + /// on all axes. + #[inline] + pub const fn visible_identity() -> Self { + SpatialBundle { + transform: Transform::identity(), + global_transform: GlobalTransform::identity(), + visibility: Visibility::visible(), + computed: ComputedVisibility::not_visible(), + } + } +} + +impl From for SpatialBundle { + #[inline] + fn from(transform: Transform) -> Self { + Self::from_transform(transform) + } +} diff --git a/crates/bevy_render/src/view/visibility/mod.rs b/crates/bevy_render/src/view/visibility/mod.rs index 1e5621215a..eb14f94f1a 100644 --- a/crates/bevy_render/src/view/visibility/mod.rs +++ b/crates/bevy_render/src/view/visibility/mod.rs @@ -34,19 +34,40 @@ pub struct Visibility { impl Default for Visibility { fn default() -> Self { + Self::visible() + } +} + +impl Visibility { + /// Creates a new [`Visibility`], set as visible + pub const fn visible() -> Self { Self { is_visible: true } } } /// Algorithmically-computed indication of whether an entity is visible and should be extracted for rendering -#[derive(Component, Clone, Reflect, Debug, Eq, PartialEq, Default)] +#[derive(Component, Clone, Reflect, Debug, Eq, PartialEq)] #[reflect(Component)] pub struct ComputedVisibility { is_visible_in_hierarchy: bool, is_visible_in_view: bool, } +impl Default for ComputedVisibility { + fn default() -> Self { + Self::not_visible() + } +} + impl ComputedVisibility { + /// Creates a new [`ComputedVisibility`], set as not visible + pub const fn not_visible() -> Self { + Self { + is_visible_in_hierarchy: false, + is_visible_in_view: false, + } + } + /// Whether this entity is visible to something this frame. This is true if and only if [`Self::is_visible_in_hierarchy`] and [`Self::is_visible_in_view`] /// are true. This is the canonical method to call to determine if an entity should be drawn. /// This value is updated in [`CoreStage::PostUpdate`] during the [`VisibilitySystems::CheckVisibility`] system label. Reading it from the diff --git a/crates/bevy_transform/src/components/global_transform.rs b/crates/bevy_transform/src/components/global_transform.rs index 96e7c24637..39fa42914c 100644 --- a/crates/bevy_transform/src/components/global_transform.rs +++ b/crates/bevy_transform/src/components/global_transform.rs @@ -8,7 +8,7 @@ use bevy_reflect::Reflect; /// Describe the position of an entity relative to the reference frame. /// /// * To place or move an entity, you should set its [`Transform`]. -/// * To get the global position of an entity, you should get its [`GlobalTransform`]. +/// * To get the global transform of an entity, you should get its [`GlobalTransform`]. /// * For transform hierarchies to work correctly, you must have both a [`Transform`] and a [`GlobalTransform`]. /// * You may use the [`TransformBundle`](crate::TransformBundle) to guarantee this. /// diff --git a/crates/bevy_transform/src/components/transform.rs b/crates/bevy_transform/src/components/transform.rs index 667850a1eb..f43d8b323c 100644 --- a/crates/bevy_transform/src/components/transform.rs +++ b/crates/bevy_transform/src/components/transform.rs @@ -9,7 +9,7 @@ use std::ops::Mul; /// to its parent position. /// /// * To place or move an entity, you should set its [`Transform`]. -/// * To get the global position of an entity, you should get its [`GlobalTransform`]. +/// * To get the global transform of an entity, you should get its [`GlobalTransform`]. /// * To be displayed, an entity must have both a [`Transform`] and a [`GlobalTransform`]. /// * You may use the [`TransformBundle`](crate::TransformBundle) to guarantee this. /// diff --git a/crates/bevy_transform/src/lib.rs b/crates/bevy_transform/src/lib.rs index 1488278398..e9ce79bc67 100644 --- a/crates/bevy_transform/src/lib.rs +++ b/crates/bevy_transform/src/lib.rs @@ -20,7 +20,7 @@ use prelude::{GlobalTransform, Transform}; /// [`Component`](bevy_ecs::component::Component)s, which describe the position of an entity. /// /// * To place or move an entity, you should set its [`Transform`]. -/// * To get the global position of an entity, you should get its [`GlobalTransform`]. +/// * To get the global transform of an entity, you should get its [`GlobalTransform`]. /// * For transform hierarchies to work correctly, you must have both a [`Transform`] and a [`GlobalTransform`]. /// * You may use the [`TransformBundle`] to guarantee this. /// diff --git a/examples/animation/animated_transform.rs b/examples/animation/animated_transform.rs index f57b3224e0..f5c6444f41 100644 --- a/examples/animation/animated_transform.rs +++ b/examples/animation/animated_transform.rs @@ -125,8 +125,7 @@ fn setup( .insert_bundle((planet, player)) .with_children(|p| { // This entity is just used for animation, but doesn't display anything - p.spawn_bundle(TransformBundle::default()) - .insert_bundle(VisibilityBundle::default()) + p.spawn_bundle(SpatialBundle::default()) // Add the Name component .insert(orbit_controller) .with_children(|p| {