 40d4992401
			
		
	
	
		40d4992401
		
	
	
	
	
		
			
			# Objective Fixes #4907. Fixes #838. Fixes #5089. Supersedes #5146. Supersedes #2087. Supersedes #865. Supersedes #5114 Visibility is currently entirely local. Set a parent entity to be invisible, and the children are still visible. This makes it hard for users to hide entire hierarchies of entities. Additionally, the semantics of `Visibility` vs `ComputedVisibility` are inconsistent across entity types. 3D meshes use `ComputedVisibility` as the "definitive" visibility component, with `Visibility` being just one data source. Sprites just use `Visibility`, which means they can't feed off of `ComputedVisibility` data, such as culling information, RenderLayers, and (added in this pr) visibility inheritance information. ## Solution Splits `ComputedVisibilty::is_visible` into `ComputedVisibilty::is_visible_in_view` and `ComputedVisibilty::is_visible_in_hierarchy`. For each visible entity, `is_visible_in_hierarchy` is computed by propagating visibility down the hierarchy. The `ComputedVisibility::is_visible()` function combines these two booleans for the canonical "is this entity visible" function. Additionally, all entities that have `Visibility` now also have `ComputedVisibility`. Sprites, Lights, and UI entities now use `ComputedVisibility` when appropriate. This means that in addition to visibility inheritance, everything using Visibility now also supports RenderLayers. Notably, Sprites (and other 2d objects) now support `RenderLayers` and work properly across multiple views. Also note that this does increase the amount of work done per sprite. Bevymark with 100,000 sprites on `main` runs in `0.017612` seconds and this runs in `0.01902`. That is certainly a gap, but I believe the api consistency and extra functionality this buys us is worth it. See [this thread](https://github.com/bevyengine/bevy/pull/5146#issuecomment-1182783452) for more info. Note that #5146 in combination with #5114 _are_ a viable alternative to this PR and _would_ perform better, but that comes at the cost of api inconsistencies and doing visibility calculations in the "wrong" place. The current visibility system does have potential for performance improvements. I would prefer to evolve that one system as a whole rather than doing custom hacks / different behaviors for each feature slice. Here is a "split screen" example where the left camera uses RenderLayers to filter out the blue sprite.  Note that this builds directly on #5146 and that @james7132 deserves the credit for the baseline visibility inheritance work. This pr moves the inherited visibility field into `ComputedVisibility`, then does the additional work of porting everything to `ComputedVisibility`. See my [comments here](https://github.com/bevyengine/bevy/pull/5146#issuecomment-1182783452) for rationale. ## Follow up work * Now that lights use ComputedVisibility, VisibleEntities now includes "visible lights" in the entity list. Functionally not a problem as we use queries to filter the list down in the desired context. But we should consider splitting this out into a separate`VisibleLights` collection for both clarity and performance reasons. And _maybe_ even consider scoping `VisibleEntities` down to `VisibleMeshes`?. * Investigate alternative sprite rendering impls (in combination with visibility system tweaks) that avoid re-generating a per-view fixedbitset of visible entities every frame, then checking each ExtractedEntity. This is where most of the performance overhead lives. Ex: we could generate ExtractedEntities per-view using the VisibleEntities list, avoiding the need for the bitset. * Should ComputedVisibility use bitflags under the hood? This would cut down on the size of the component, potentially speed up the `is_visible()` function, and allow us to cheaply expand ComputedVisibility with more data (ex: split out local visibility and parent visibility, add more culling classes, etc). --- ## Changelog * ComputedVisibility now takes hierarchy visibility into account. * 2D, UI and Light entities now use the ComputedVisibility component. ## Migration Guide If you were previously reading `Visibility::is_visible` as the "actual visibility" for sprites or lights, use `ComputedVisibilty::is_visible()` instead: ```rust // before (0.7) fn system(query: Query<&Visibility>) { for visibility in query.iter() { if visibility.is_visible { log!("found visible entity"); } } } // after (0.8) fn system(query: Query<&ComputedVisibility>) { for visibility in query.iter() { if visibility.is_visible() { log!("found visible entity"); } } } ``` Co-authored-by: Carter Anderson <mcanders1@gmail.com>
		
			
				
	
	
		
			107 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			107 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| use crate::{DirectionalLight, Material, PointLight, SpotLight, StandardMaterial};
 | |
| use bevy_asset::Handle;
 | |
| use bevy_ecs::{bundle::Bundle, component::Component, reflect::ReflectComponent};
 | |
| use bevy_reflect::Reflect;
 | |
| use bevy_render::{
 | |
|     mesh::Mesh,
 | |
|     primitives::{CubemapFrusta, Frustum},
 | |
|     view::{ComputedVisibility, Visibility, VisibleEntities},
 | |
| };
 | |
| use bevy_transform::components::{GlobalTransform, Transform};
 | |
| 
 | |
| /// A component bundle for PBR entities with a [`Mesh`] and a [`StandardMaterial`].
 | |
| pub type PbrBundle = MaterialMeshBundle<StandardMaterial>;
 | |
| 
 | |
| /// A component bundle for entities with a [`Mesh`] and a [`Material`].
 | |
| #[derive(Bundle, Clone)]
 | |
| pub struct MaterialMeshBundle<M: Material> {
 | |
|     pub mesh: Handle<Mesh>,
 | |
|     pub material: Handle<M>,
 | |
|     pub transform: Transform,
 | |
|     pub global_transform: GlobalTransform,
 | |
|     /// User indication of whether an entity is visible
 | |
|     pub visibility: Visibility,
 | |
|     /// Algorithmically-computed indication of whether an entity is visible and should be extracted for rendering
 | |
|     pub computed_visibility: ComputedVisibility,
 | |
| }
 | |
| 
 | |
| impl<M: Material> Default for MaterialMeshBundle<M> {
 | |
|     fn default() -> Self {
 | |
|         Self {
 | |
|             mesh: Default::default(),
 | |
|             material: Default::default(),
 | |
|             transform: Default::default(),
 | |
|             global_transform: Default::default(),
 | |
|             visibility: Default::default(),
 | |
|             computed_visibility: Default::default(),
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| #[derive(Component, Clone, Debug, Default, Reflect)]
 | |
| #[reflect(Component)]
 | |
| pub struct CubemapVisibleEntities {
 | |
|     #[reflect(ignore)]
 | |
|     data: [VisibleEntities; 6],
 | |
| }
 | |
| 
 | |
| impl CubemapVisibleEntities {
 | |
|     pub fn get(&self, i: usize) -> &VisibleEntities {
 | |
|         &self.data[i]
 | |
|     }
 | |
| 
 | |
|     pub fn get_mut(&mut self, i: usize) -> &mut VisibleEntities {
 | |
|         &mut self.data[i]
 | |
|     }
 | |
| 
 | |
|     pub fn iter(&self) -> impl DoubleEndedIterator<Item = &VisibleEntities> {
 | |
|         self.data.iter()
 | |
|     }
 | |
| 
 | |
|     pub fn iter_mut(&mut self) -> impl DoubleEndedIterator<Item = &mut VisibleEntities> {
 | |
|         self.data.iter_mut()
 | |
|     }
 | |
| }
 | |
| 
 | |
| /// A component bundle for [`PointLight`] entities.
 | |
| #[derive(Debug, Bundle, Default)]
 | |
| pub struct PointLightBundle {
 | |
|     pub point_light: PointLight,
 | |
|     pub cubemap_visible_entities: CubemapVisibleEntities,
 | |
|     pub cubemap_frusta: CubemapFrusta,
 | |
|     pub transform: Transform,
 | |
|     pub global_transform: GlobalTransform,
 | |
|     /// Enables or disables the light
 | |
|     pub visibility: Visibility,
 | |
|     /// Algorithmically-computed indication of whether an entity is visible and should be extracted for rendering
 | |
|     pub computed_visibility: ComputedVisibility,
 | |
| }
 | |
| 
 | |
| /// A component bundle for spot light entities
 | |
| #[derive(Debug, Bundle, Default)]
 | |
| pub struct SpotLightBundle {
 | |
|     pub spot_light: SpotLight,
 | |
|     pub visible_entities: VisibleEntities,
 | |
|     pub frustum: Frustum,
 | |
|     pub transform: Transform,
 | |
|     pub global_transform: GlobalTransform,
 | |
|     /// Enables or disables the light
 | |
|     pub visibility: Visibility,
 | |
|     /// Algorithmically-computed indication of whether an entity is visible and should be extracted for rendering
 | |
|     pub computed_visibility: ComputedVisibility,
 | |
| }
 | |
| 
 | |
| /// A component bundle for [`DirectionalLight`] entities.
 | |
| #[derive(Debug, Bundle, Default)]
 | |
| pub struct DirectionalLightBundle {
 | |
|     pub directional_light: DirectionalLight,
 | |
|     pub frustum: Frustum,
 | |
|     pub visible_entities: VisibleEntities,
 | |
|     pub transform: Transform,
 | |
|     pub global_transform: GlobalTransform,
 | |
|     /// Enables or disables the light
 | |
|     pub visibility: Visibility,
 | |
|     /// Algorithmically-computed indication of whether an entity is visible and should be extracted for rendering
 | |
|     pub computed_visibility: ComputedVisibility,
 | |
| }
 |