2022-11-05 20:48:15 +00:00
|
|
|
//! This module contains basic node bundles used to build UIs
|
2022-01-07 22:20:34 +00:00
|
|
|
|
2020-07-18 21:08:46 +00:00
|
|
|
use crate::{
|
2022-11-18 21:16:32 +00:00
|
|
|
widget::Button, BackgroundColor, CalculatedSize, FocusPolicy, Interaction, Node, Style,
|
|
|
|
UiImage, ZIndex,
|
2020-07-18 21:08:46 +00:00
|
|
|
};
|
2022-11-05 20:48:15 +00:00
|
|
|
use bevy_ecs::bundle::Bundle;
|
Visibilty Inheritance, universal ComputedVisibility and RenderLayers support (#5310)
# 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.
![image](https://user-images.githubusercontent.com/2694663/178814868-2e9a2173-bf8c-4c79-8815-633899d492c3.png)
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>
2022-07-15 23:24:42 +00:00
|
|
|
use bevy_render::{
|
2022-10-09 21:03:05 +00:00
|
|
|
prelude::{Color, ComputedVisibility},
|
Visibilty Inheritance, universal ComputedVisibility and RenderLayers support (#5310)
# 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.
![image](https://user-images.githubusercontent.com/2694663/178814868-2e9a2173-bf8c-4c79-8815-633899d492c3.png)
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>
2022-07-15 23:24:42 +00:00
|
|
|
view::Visibility,
|
|
|
|
};
|
2023-02-24 02:21:07 +00:00
|
|
|
#[cfg(feature = "bevy_text")]
|
2022-07-20 14:14:29 +00:00
|
|
|
use bevy_text::{Text, TextAlignment, TextSection, TextStyle};
|
2020-09-14 21:00:32 +00:00
|
|
|
use bevy_transform::prelude::{GlobalTransform, Transform};
|
2020-04-06 21:20:53 +00:00
|
|
|
|
2022-01-07 22:20:34 +00:00
|
|
|
/// The basic UI node
|
2022-11-05 20:48:15 +00:00
|
|
|
///
|
|
|
|
/// Useful as a container for a variety of child nodes.
|
2022-10-09 21:03:05 +00:00
|
|
|
#[derive(Bundle, Clone, Debug)]
|
2020-11-16 04:32:23 +00:00
|
|
|
pub struct NodeBundle {
|
2022-01-07 22:20:34 +00:00
|
|
|
/// Describes the size of the node
|
2020-04-06 21:20:53 +00:00
|
|
|
pub node: Node,
|
2022-01-07 22:20:34 +00:00
|
|
|
/// Describes the style including flexbox settings
|
2020-07-26 19:27:09 +00:00
|
|
|
pub style: Style,
|
2022-09-25 00:39:17 +00:00
|
|
|
/// The background color, which serves as a "fill" for this node
|
|
|
|
pub background_color: BackgroundColor,
|
2022-02-15 22:31:51 +00:00
|
|
|
/// Whether this node should block interaction with lower nodes
|
|
|
|
pub focus_policy: FocusPolicy,
|
2022-01-07 22:20:34 +00:00
|
|
|
/// The transform of the node
|
2022-09-26 01:31:22 +00:00
|
|
|
///
|
|
|
|
/// This field is automatically managed by the UI layout system.
|
|
|
|
/// To alter the position of the `nodebundle`, use the properties of the [`Style`] component.
|
2020-06-25 17:13:00 +00:00
|
|
|
pub transform: Transform,
|
2022-01-07 22:20:34 +00:00
|
|
|
/// The global transform of the node
|
2022-09-26 01:31:22 +00:00
|
|
|
///
|
|
|
|
/// This field is automatically managed by the UI layout system.
|
|
|
|
/// To alter the position of the `NodeBundle`, use the properties of the [`Style`] component.
|
2020-09-14 21:00:32 +00:00
|
|
|
pub global_transform: GlobalTransform,
|
2022-01-07 22:20:34 +00:00
|
|
|
/// Describes the visibility properties of the node
|
2021-12-24 07:10:12 +00:00
|
|
|
pub visibility: Visibility,
|
Visibilty Inheritance, universal ComputedVisibility and RenderLayers support (#5310)
# 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.
![image](https://user-images.githubusercontent.com/2694663/178814868-2e9a2173-bf8c-4c79-8815-633899d492c3.png)
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>
2022-07-15 23:24:42 +00:00
|
|
|
/// Algorithmically-computed indication of whether an entity is visible and should be extracted for rendering
|
|
|
|
pub computed_visibility: ComputedVisibility,
|
Add z-index support with a predictable UI stack (#5877)
# Objective
Add consistent UI rendering and interaction where deep nodes inside two different hierarchies will never render on top of one-another by default and offer an escape hatch (z-index) for nodes to change their depth.
## The problem with current implementation
The current implementation of UI rendering is broken in that regard, mainly because [it sets the Z value of the `Transform` component based on a "global Z" space](https://github.com/bevyengine/bevy/blob/main/crates/bevy_ui/src/update.rs#L43) shared by all nodes in the UI. This doesn't account for the fact that each node's final `GlobalTransform` value will be relative to its parent. This effectively makes the depth unpredictable when two deep trees are rendered on top of one-another.
At the moment, it's also up to each part of the UI code to sort all of the UI nodes. The solution that's offered here does the full sorting of UI node entities once and offers the result through a resource so that all systems can use it.
## Solution
### New ZIndex component
This adds a new optional `ZIndex` enum component for nodes which offers two mechanism:
- `ZIndex::Local(i32)`: Overrides the depth of the node relative to its siblings.
- `ZIndex::Global(i32)`: Overrides the depth of the node relative to the UI root. This basically allows any node in the tree to "escape" the parent and be ordered relative to the entire UI.
Note that in the current implementation, omitting `ZIndex` on a node has the same result as adding `ZIndex::Local(0)`. Additionally, the "global" stacking context is essentially a way to add your node to the root stacking context, so using `ZIndex::Local(n)` on a root node (one without parent) will share that space with all nodes using `Index::Global(n)`.
### New UiStack resource
This adds a new `UiStack` resource which is calculated from both hierarchy and `ZIndex` during UI update and contains a vector of all node entities in the UI, ordered by depth (from farthest from camera to closest). This is exposed publicly by the bevy_ui crate with the hope that it can be used for consistent ordering and to reduce the amount of sorting that needs to be done by UI systems (i.e. instead of sorting everything by `global_transform.z` in every system, this array can be iterated over).
### New z_index example
This also adds a new z_index example that showcases the new `ZIndex` component. It's also a good general demo of the new UI stack system, because making this kind of UI was very broken with the old system (e.g. nodes would render on top of each other, not respecting hierarchy or insert order at all).
![image](https://user-images.githubusercontent.com/1060971/189015985-8ea8f989-0e9d-4601-a7e0-4a27a43a53f9.png)
---
## Changelog
- Added the `ZIndex` component to bevy_ui.
- Added the `UiStack` resource to bevy_ui, and added implementation in a new `stack.rs` module.
- Removed the previous Z updating system from bevy_ui, because it was replaced with the above.
- Changed bevy_ui rendering to use UiStack instead of z ordering.
- Changed bevy_ui focus/interaction system to use UiStack instead of z ordering.
- Added a new z_index example.
## ZIndex demo
Here's a demo I wrote to test these features
https://user-images.githubusercontent.com/1060971/188329295-d7beebd6-9aee-43ab-821e-d437df5dbe8a.mp4
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-11-02 22:06:04 +00:00
|
|
|
/// Indicates the depth at which the node should appear in the UI
|
|
|
|
pub z_index: ZIndex,
|
2020-04-06 21:20:53 +00:00
|
|
|
}
|
2020-05-03 19:35:07 +00:00
|
|
|
|
2022-10-09 21:03:05 +00:00
|
|
|
impl Default for NodeBundle {
|
|
|
|
fn default() -> Self {
|
|
|
|
NodeBundle {
|
|
|
|
// Transparent background
|
|
|
|
background_color: Color::NONE.into(),
|
|
|
|
node: Default::default(),
|
|
|
|
style: Default::default(),
|
|
|
|
focus_policy: Default::default(),
|
|
|
|
transform: Default::default(),
|
|
|
|
global_transform: Default::default(),
|
|
|
|
visibility: Default::default(),
|
|
|
|
computed_visibility: Default::default(),
|
Add z-index support with a predictable UI stack (#5877)
# Objective
Add consistent UI rendering and interaction where deep nodes inside two different hierarchies will never render on top of one-another by default and offer an escape hatch (z-index) for nodes to change their depth.
## The problem with current implementation
The current implementation of UI rendering is broken in that regard, mainly because [it sets the Z value of the `Transform` component based on a "global Z" space](https://github.com/bevyengine/bevy/blob/main/crates/bevy_ui/src/update.rs#L43) shared by all nodes in the UI. This doesn't account for the fact that each node's final `GlobalTransform` value will be relative to its parent. This effectively makes the depth unpredictable when two deep trees are rendered on top of one-another.
At the moment, it's also up to each part of the UI code to sort all of the UI nodes. The solution that's offered here does the full sorting of UI node entities once and offers the result through a resource so that all systems can use it.
## Solution
### New ZIndex component
This adds a new optional `ZIndex` enum component for nodes which offers two mechanism:
- `ZIndex::Local(i32)`: Overrides the depth of the node relative to its siblings.
- `ZIndex::Global(i32)`: Overrides the depth of the node relative to the UI root. This basically allows any node in the tree to "escape" the parent and be ordered relative to the entire UI.
Note that in the current implementation, omitting `ZIndex` on a node has the same result as adding `ZIndex::Local(0)`. Additionally, the "global" stacking context is essentially a way to add your node to the root stacking context, so using `ZIndex::Local(n)` on a root node (one without parent) will share that space with all nodes using `Index::Global(n)`.
### New UiStack resource
This adds a new `UiStack` resource which is calculated from both hierarchy and `ZIndex` during UI update and contains a vector of all node entities in the UI, ordered by depth (from farthest from camera to closest). This is exposed publicly by the bevy_ui crate with the hope that it can be used for consistent ordering and to reduce the amount of sorting that needs to be done by UI systems (i.e. instead of sorting everything by `global_transform.z` in every system, this array can be iterated over).
### New z_index example
This also adds a new z_index example that showcases the new `ZIndex` component. It's also a good general demo of the new UI stack system, because making this kind of UI was very broken with the old system (e.g. nodes would render on top of each other, not respecting hierarchy or insert order at all).
![image](https://user-images.githubusercontent.com/1060971/189015985-8ea8f989-0e9d-4601-a7e0-4a27a43a53f9.png)
---
## Changelog
- Added the `ZIndex` component to bevy_ui.
- Added the `UiStack` resource to bevy_ui, and added implementation in a new `stack.rs` module.
- Removed the previous Z updating system from bevy_ui, because it was replaced with the above.
- Changed bevy_ui rendering to use UiStack instead of z ordering.
- Changed bevy_ui focus/interaction system to use UiStack instead of z ordering.
- Added a new z_index example.
## ZIndex demo
Here's a demo I wrote to test these features
https://user-images.githubusercontent.com/1060971/188329295-d7beebd6-9aee-43ab-821e-d437df5dbe8a.mp4
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-11-02 22:06:04 +00:00
|
|
|
z_index: Default::default(),
|
2022-10-09 21:03:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-07 22:20:34 +00:00
|
|
|
/// A UI node that is an image
|
2021-12-14 03:58:23 +00:00
|
|
|
#[derive(Bundle, Clone, Debug, Default)]
|
2020-11-16 04:32:23 +00:00
|
|
|
pub struct ImageBundle {
|
2022-01-07 22:20:34 +00:00
|
|
|
/// Describes the size of the node
|
2020-07-28 07:37:25 +00:00
|
|
|
pub node: Node,
|
2022-01-07 22:20:34 +00:00
|
|
|
/// Describes the style including flexbox settings
|
2020-07-28 07:37:25 +00:00
|
|
|
pub style: Style,
|
2022-01-07 22:20:34 +00:00
|
|
|
/// The calculated size based on the given image
|
2020-07-28 07:37:25 +00:00
|
|
|
pub calculated_size: CalculatedSize,
|
2022-09-25 00:39:17 +00:00
|
|
|
/// The background color, which serves as a "fill" for this node
|
|
|
|
///
|
2022-12-20 16:17:14 +00:00
|
|
|
/// Combines with `UiImage` to tint the provided image.
|
2022-09-25 00:39:17 +00:00
|
|
|
pub background_color: BackgroundColor,
|
2022-01-07 22:20:34 +00:00
|
|
|
/// The image of the node
|
2021-12-14 03:58:23 +00:00
|
|
|
pub image: UiImage,
|
2022-02-15 22:31:51 +00:00
|
|
|
/// Whether this node should block interaction with lower nodes
|
|
|
|
pub focus_policy: FocusPolicy,
|
2022-01-07 22:20:34 +00:00
|
|
|
/// The transform of the node
|
2022-09-26 01:31:22 +00:00
|
|
|
///
|
|
|
|
/// This field is automatically managed by the UI layout system.
|
|
|
|
/// To alter the position of the `NodeBundle`, use the properties of the [`Style`] component.
|
2020-07-28 07:37:25 +00:00
|
|
|
pub transform: Transform,
|
2022-01-07 22:20:34 +00:00
|
|
|
/// The global transform of the node
|
2022-09-26 01:31:22 +00:00
|
|
|
///
|
|
|
|
/// This field is automatically managed by the UI layout system.
|
|
|
|
/// To alter the position of the `NodeBundle`, use the properties of the [`Style`] component.
|
2020-09-14 21:00:32 +00:00
|
|
|
pub global_transform: GlobalTransform,
|
2022-01-07 22:20:34 +00:00
|
|
|
/// Describes the visibility properties of the node
|
2021-12-24 07:10:12 +00:00
|
|
|
pub visibility: Visibility,
|
Visibilty Inheritance, universal ComputedVisibility and RenderLayers support (#5310)
# 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.
![image](https://user-images.githubusercontent.com/2694663/178814868-2e9a2173-bf8c-4c79-8815-633899d492c3.png)
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>
2022-07-15 23:24:42 +00:00
|
|
|
/// Algorithmically-computed indication of whether an entity is visible and should be extracted for rendering
|
|
|
|
pub computed_visibility: ComputedVisibility,
|
Add z-index support with a predictable UI stack (#5877)
# Objective
Add consistent UI rendering and interaction where deep nodes inside two different hierarchies will never render on top of one-another by default and offer an escape hatch (z-index) for nodes to change their depth.
## The problem with current implementation
The current implementation of UI rendering is broken in that regard, mainly because [it sets the Z value of the `Transform` component based on a "global Z" space](https://github.com/bevyengine/bevy/blob/main/crates/bevy_ui/src/update.rs#L43) shared by all nodes in the UI. This doesn't account for the fact that each node's final `GlobalTransform` value will be relative to its parent. This effectively makes the depth unpredictable when two deep trees are rendered on top of one-another.
At the moment, it's also up to each part of the UI code to sort all of the UI nodes. The solution that's offered here does the full sorting of UI node entities once and offers the result through a resource so that all systems can use it.
## Solution
### New ZIndex component
This adds a new optional `ZIndex` enum component for nodes which offers two mechanism:
- `ZIndex::Local(i32)`: Overrides the depth of the node relative to its siblings.
- `ZIndex::Global(i32)`: Overrides the depth of the node relative to the UI root. This basically allows any node in the tree to "escape" the parent and be ordered relative to the entire UI.
Note that in the current implementation, omitting `ZIndex` on a node has the same result as adding `ZIndex::Local(0)`. Additionally, the "global" stacking context is essentially a way to add your node to the root stacking context, so using `ZIndex::Local(n)` on a root node (one without parent) will share that space with all nodes using `Index::Global(n)`.
### New UiStack resource
This adds a new `UiStack` resource which is calculated from both hierarchy and `ZIndex` during UI update and contains a vector of all node entities in the UI, ordered by depth (from farthest from camera to closest). This is exposed publicly by the bevy_ui crate with the hope that it can be used for consistent ordering and to reduce the amount of sorting that needs to be done by UI systems (i.e. instead of sorting everything by `global_transform.z` in every system, this array can be iterated over).
### New z_index example
This also adds a new z_index example that showcases the new `ZIndex` component. It's also a good general demo of the new UI stack system, because making this kind of UI was very broken with the old system (e.g. nodes would render on top of each other, not respecting hierarchy or insert order at all).
![image](https://user-images.githubusercontent.com/1060971/189015985-8ea8f989-0e9d-4601-a7e0-4a27a43a53f9.png)
---
## Changelog
- Added the `ZIndex` component to bevy_ui.
- Added the `UiStack` resource to bevy_ui, and added implementation in a new `stack.rs` module.
- Removed the previous Z updating system from bevy_ui, because it was replaced with the above.
- Changed bevy_ui rendering to use UiStack instead of z ordering.
- Changed bevy_ui focus/interaction system to use UiStack instead of z ordering.
- Added a new z_index example.
## ZIndex demo
Here's a demo I wrote to test these features
https://user-images.githubusercontent.com/1060971/188329295-d7beebd6-9aee-43ab-821e-d437df5dbe8a.mp4
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-11-02 22:06:04 +00:00
|
|
|
/// Indicates the depth at which the node should appear in the UI
|
|
|
|
pub z_index: ZIndex,
|
2020-07-28 07:37:25 +00:00
|
|
|
}
|
|
|
|
|
2023-02-24 02:21:07 +00:00
|
|
|
#[cfg(feature = "bevy_text")]
|
2022-01-07 22:20:34 +00:00
|
|
|
/// A UI node that is text
|
2023-02-20 22:42:46 +00:00
|
|
|
#[derive(Bundle, Clone, Debug)]
|
2020-11-16 04:32:23 +00:00
|
|
|
pub struct TextBundle {
|
2022-01-07 22:20:34 +00:00
|
|
|
/// Describes the size of the node
|
2020-05-18 01:09:29 +00:00
|
|
|
pub node: Node,
|
2022-01-07 22:20:34 +00:00
|
|
|
/// Describes the style including flexbox settings
|
2020-07-26 19:27:09 +00:00
|
|
|
pub style: Style,
|
2022-01-07 22:20:34 +00:00
|
|
|
/// Contains the text of the node
|
2020-07-20 03:33:55 +00:00
|
|
|
pub text: Text,
|
2022-01-07 22:20:34 +00:00
|
|
|
/// The calculated size based on the given image
|
2020-07-28 04:04:04 +00:00
|
|
|
pub calculated_size: CalculatedSize,
|
2022-01-07 22:20:34 +00:00
|
|
|
/// Whether this node should block interaction with lower nodes
|
2020-07-19 00:03:37 +00:00
|
|
|
pub focus_policy: FocusPolicy,
|
2022-01-07 22:20:34 +00:00
|
|
|
/// The transform of the node
|
2022-09-26 01:31:22 +00:00
|
|
|
///
|
|
|
|
/// This field is automatically managed by the UI layout system.
|
|
|
|
/// To alter the position of the `NodeBundle`, use the properties of the [`Style`] component.
|
2020-06-25 17:13:00 +00:00
|
|
|
pub transform: Transform,
|
2022-01-07 22:20:34 +00:00
|
|
|
/// The global transform of the node
|
2022-09-26 01:31:22 +00:00
|
|
|
///
|
|
|
|
/// This field is automatically managed by the UI layout system.
|
|
|
|
/// To alter the position of the `NodeBundle`, use the properties of the [`Style`] component.
|
2020-09-14 21:00:32 +00:00
|
|
|
pub global_transform: GlobalTransform,
|
2022-01-07 22:20:34 +00:00
|
|
|
/// Describes the visibility properties of the node
|
2021-12-24 07:10:12 +00:00
|
|
|
pub visibility: Visibility,
|
Visibilty Inheritance, universal ComputedVisibility and RenderLayers support (#5310)
# 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.
![image](https://user-images.githubusercontent.com/2694663/178814868-2e9a2173-bf8c-4c79-8815-633899d492c3.png)
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>
2022-07-15 23:24:42 +00:00
|
|
|
/// Algorithmically-computed indication of whether an entity is visible and should be extracted for rendering
|
|
|
|
pub computed_visibility: ComputedVisibility,
|
Add z-index support with a predictable UI stack (#5877)
# Objective
Add consistent UI rendering and interaction where deep nodes inside two different hierarchies will never render on top of one-another by default and offer an escape hatch (z-index) for nodes to change their depth.
## The problem with current implementation
The current implementation of UI rendering is broken in that regard, mainly because [it sets the Z value of the `Transform` component based on a "global Z" space](https://github.com/bevyengine/bevy/blob/main/crates/bevy_ui/src/update.rs#L43) shared by all nodes in the UI. This doesn't account for the fact that each node's final `GlobalTransform` value will be relative to its parent. This effectively makes the depth unpredictable when two deep trees are rendered on top of one-another.
At the moment, it's also up to each part of the UI code to sort all of the UI nodes. The solution that's offered here does the full sorting of UI node entities once and offers the result through a resource so that all systems can use it.
## Solution
### New ZIndex component
This adds a new optional `ZIndex` enum component for nodes which offers two mechanism:
- `ZIndex::Local(i32)`: Overrides the depth of the node relative to its siblings.
- `ZIndex::Global(i32)`: Overrides the depth of the node relative to the UI root. This basically allows any node in the tree to "escape" the parent and be ordered relative to the entire UI.
Note that in the current implementation, omitting `ZIndex` on a node has the same result as adding `ZIndex::Local(0)`. Additionally, the "global" stacking context is essentially a way to add your node to the root stacking context, so using `ZIndex::Local(n)` on a root node (one without parent) will share that space with all nodes using `Index::Global(n)`.
### New UiStack resource
This adds a new `UiStack` resource which is calculated from both hierarchy and `ZIndex` during UI update and contains a vector of all node entities in the UI, ordered by depth (from farthest from camera to closest). This is exposed publicly by the bevy_ui crate with the hope that it can be used for consistent ordering and to reduce the amount of sorting that needs to be done by UI systems (i.e. instead of sorting everything by `global_transform.z` in every system, this array can be iterated over).
### New z_index example
This also adds a new z_index example that showcases the new `ZIndex` component. It's also a good general demo of the new UI stack system, because making this kind of UI was very broken with the old system (e.g. nodes would render on top of each other, not respecting hierarchy or insert order at all).
![image](https://user-images.githubusercontent.com/1060971/189015985-8ea8f989-0e9d-4601-a7e0-4a27a43a53f9.png)
---
## Changelog
- Added the `ZIndex` component to bevy_ui.
- Added the `UiStack` resource to bevy_ui, and added implementation in a new `stack.rs` module.
- Removed the previous Z updating system from bevy_ui, because it was replaced with the above.
- Changed bevy_ui rendering to use UiStack instead of z ordering.
- Changed bevy_ui focus/interaction system to use UiStack instead of z ordering.
- Added a new z_index example.
## ZIndex demo
Here's a demo I wrote to test these features
https://user-images.githubusercontent.com/1060971/188329295-d7beebd6-9aee-43ab-821e-d437df5dbe8a.mp4
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-11-02 22:06:04 +00:00
|
|
|
/// Indicates the depth at which the node should appear in the UI
|
|
|
|
pub z_index: ZIndex,
|
2023-02-20 22:42:46 +00:00
|
|
|
/// The background color that will fill the containing node
|
|
|
|
pub background_color: BackgroundColor,
|
|
|
|
}
|
|
|
|
|
2023-02-24 02:21:07 +00:00
|
|
|
#[cfg(feature = "bevy_text")]
|
2023-02-20 22:42:46 +00:00
|
|
|
impl Default for TextBundle {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
|
|
|
text: Default::default(),
|
|
|
|
calculated_size: Default::default(),
|
|
|
|
// Transparent background
|
|
|
|
background_color: BackgroundColor(Color::NONE),
|
|
|
|
node: Default::default(),
|
|
|
|
style: Default::default(),
|
|
|
|
focus_policy: Default::default(),
|
|
|
|
transform: Default::default(),
|
|
|
|
global_transform: Default::default(),
|
|
|
|
visibility: Default::default(),
|
|
|
|
computed_visibility: Default::default(),
|
|
|
|
z_index: Default::default(),
|
|
|
|
}
|
|
|
|
}
|
2020-05-18 01:09:29 +00:00
|
|
|
}
|
|
|
|
|
2023-02-24 02:21:07 +00:00
|
|
|
#[cfg(feature = "bevy_text")]
|
2022-07-20 14:14:29 +00:00
|
|
|
impl TextBundle {
|
|
|
|
/// Create a [`TextBundle`] from a single section.
|
|
|
|
///
|
|
|
|
/// See [`Text::from_section`] for usage.
|
|
|
|
pub fn from_section(value: impl Into<String>, style: TextStyle) -> Self {
|
|
|
|
Self {
|
|
|
|
text: Text::from_section(value, style),
|
|
|
|
..Default::default()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Create a [`TextBundle`] from a list of sections.
|
|
|
|
///
|
|
|
|
/// See [`Text::from_sections`] for usage.
|
|
|
|
pub fn from_sections(sections: impl IntoIterator<Item = TextSection>) -> Self {
|
|
|
|
Self {
|
|
|
|
text: Text::from_sections(sections),
|
|
|
|
..Default::default()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns this [`TextBundle`] with a new [`TextAlignment`] on [`Text`].
|
|
|
|
pub const fn with_text_alignment(mut self, alignment: TextAlignment) -> Self {
|
|
|
|
self.text.alignment = alignment;
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns this [`TextBundle`] with a new [`Style`].
|
|
|
|
pub const fn with_style(mut self, style: Style) -> Self {
|
|
|
|
self.style = style;
|
|
|
|
self
|
|
|
|
}
|
2023-02-20 22:42:46 +00:00
|
|
|
|
|
|
|
/// Returns this [`TextBundle`] with a new [`BackgroundColor`].
|
|
|
|
pub const fn with_background_color(mut self, color: Color) -> Self {
|
|
|
|
self.background_color = BackgroundColor(color);
|
|
|
|
self
|
|
|
|
}
|
2022-07-20 14:14:29 +00:00
|
|
|
}
|
|
|
|
|
2022-01-07 22:20:34 +00:00
|
|
|
/// A UI node that is a button
|
2023-01-12 17:15:20 +00:00
|
|
|
#[derive(Bundle, Clone, Debug)]
|
2020-11-16 04:32:23 +00:00
|
|
|
pub struct ButtonBundle {
|
2022-01-07 22:20:34 +00:00
|
|
|
/// Describes the size of the node
|
2020-07-18 21:08:46 +00:00
|
|
|
pub node: Node,
|
2022-01-07 22:20:34 +00:00
|
|
|
/// Marker component that signals this node is a button
|
2020-07-18 21:08:46 +00:00
|
|
|
pub button: Button,
|
2022-01-07 22:20:34 +00:00
|
|
|
/// Describes the style including flexbox settings
|
2020-07-26 19:27:09 +00:00
|
|
|
pub style: Style,
|
2022-01-07 22:20:34 +00:00
|
|
|
/// Describes whether and how the button has been interacted with by the input
|
2020-07-28 08:20:19 +00:00
|
|
|
pub interaction: Interaction,
|
2022-01-07 22:20:34 +00:00
|
|
|
/// Whether this node should block interaction with lower nodes
|
2020-07-18 21:08:46 +00:00
|
|
|
pub focus_policy: FocusPolicy,
|
2022-09-25 00:39:17 +00:00
|
|
|
/// The background color, which serves as a "fill" for this node
|
|
|
|
///
|
|
|
|
/// When combined with `UiImage`, tints the provided image.
|
|
|
|
pub background_color: BackgroundColor,
|
2022-01-07 22:20:34 +00:00
|
|
|
/// The image of the node
|
2021-12-14 03:58:23 +00:00
|
|
|
pub image: UiImage,
|
2022-01-07 22:20:34 +00:00
|
|
|
/// The transform of the node
|
2022-09-26 01:31:22 +00:00
|
|
|
///
|
|
|
|
/// This field is automatically managed by the UI layout system.
|
|
|
|
/// To alter the position of the `NodeBundle`, use the properties of the [`Style`] component.
|
2020-07-18 21:08:46 +00:00
|
|
|
pub transform: Transform,
|
2022-01-07 22:20:34 +00:00
|
|
|
/// The global transform of the node
|
2022-09-26 01:31:22 +00:00
|
|
|
///
|
|
|
|
/// This field is automatically managed by the UI layout system.
|
|
|
|
/// To alter the position of the `NodeBundle`, use the properties of the [`Style`] component.
|
2020-09-14 21:00:32 +00:00
|
|
|
pub global_transform: GlobalTransform,
|
2022-01-07 22:20:34 +00:00
|
|
|
/// Describes the visibility properties of the node
|
2021-12-24 07:10:12 +00:00
|
|
|
pub visibility: Visibility,
|
Visibilty Inheritance, universal ComputedVisibility and RenderLayers support (#5310)
# 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.
![image](https://user-images.githubusercontent.com/2694663/178814868-2e9a2173-bf8c-4c79-8815-633899d492c3.png)
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>
2022-07-15 23:24:42 +00:00
|
|
|
/// Algorithmically-computed indication of whether an entity is visible and should be extracted for rendering
|
|
|
|
pub computed_visibility: ComputedVisibility,
|
Add z-index support with a predictable UI stack (#5877)
# Objective
Add consistent UI rendering and interaction where deep nodes inside two different hierarchies will never render on top of one-another by default and offer an escape hatch (z-index) for nodes to change their depth.
## The problem with current implementation
The current implementation of UI rendering is broken in that regard, mainly because [it sets the Z value of the `Transform` component based on a "global Z" space](https://github.com/bevyengine/bevy/blob/main/crates/bevy_ui/src/update.rs#L43) shared by all nodes in the UI. This doesn't account for the fact that each node's final `GlobalTransform` value will be relative to its parent. This effectively makes the depth unpredictable when two deep trees are rendered on top of one-another.
At the moment, it's also up to each part of the UI code to sort all of the UI nodes. The solution that's offered here does the full sorting of UI node entities once and offers the result through a resource so that all systems can use it.
## Solution
### New ZIndex component
This adds a new optional `ZIndex` enum component for nodes which offers two mechanism:
- `ZIndex::Local(i32)`: Overrides the depth of the node relative to its siblings.
- `ZIndex::Global(i32)`: Overrides the depth of the node relative to the UI root. This basically allows any node in the tree to "escape" the parent and be ordered relative to the entire UI.
Note that in the current implementation, omitting `ZIndex` on a node has the same result as adding `ZIndex::Local(0)`. Additionally, the "global" stacking context is essentially a way to add your node to the root stacking context, so using `ZIndex::Local(n)` on a root node (one without parent) will share that space with all nodes using `Index::Global(n)`.
### New UiStack resource
This adds a new `UiStack` resource which is calculated from both hierarchy and `ZIndex` during UI update and contains a vector of all node entities in the UI, ordered by depth (from farthest from camera to closest). This is exposed publicly by the bevy_ui crate with the hope that it can be used for consistent ordering and to reduce the amount of sorting that needs to be done by UI systems (i.e. instead of sorting everything by `global_transform.z` in every system, this array can be iterated over).
### New z_index example
This also adds a new z_index example that showcases the new `ZIndex` component. It's also a good general demo of the new UI stack system, because making this kind of UI was very broken with the old system (e.g. nodes would render on top of each other, not respecting hierarchy or insert order at all).
![image](https://user-images.githubusercontent.com/1060971/189015985-8ea8f989-0e9d-4601-a7e0-4a27a43a53f9.png)
---
## Changelog
- Added the `ZIndex` component to bevy_ui.
- Added the `UiStack` resource to bevy_ui, and added implementation in a new `stack.rs` module.
- Removed the previous Z updating system from bevy_ui, because it was replaced with the above.
- Changed bevy_ui rendering to use UiStack instead of z ordering.
- Changed bevy_ui focus/interaction system to use UiStack instead of z ordering.
- Added a new z_index example.
## ZIndex demo
Here's a demo I wrote to test these features
https://user-images.githubusercontent.com/1060971/188329295-d7beebd6-9aee-43ab-821e-d437df5dbe8a.mp4
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-11-02 22:06:04 +00:00
|
|
|
/// Indicates the depth at which the node should appear in the UI
|
|
|
|
pub z_index: ZIndex,
|
2020-07-18 21:08:46 +00:00
|
|
|
}
|
2023-01-12 17:15:20 +00:00
|
|
|
|
|
|
|
impl Default for ButtonBundle {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
|
|
|
focus_policy: FocusPolicy::Block,
|
|
|
|
node: Default::default(),
|
|
|
|
button: Default::default(),
|
|
|
|
style: Default::default(),
|
|
|
|
interaction: Default::default(),
|
|
|
|
background_color: Default::default(),
|
|
|
|
image: Default::default(),
|
|
|
|
transform: Default::default(),
|
|
|
|
global_transform: Default::default(),
|
|
|
|
visibility: Default::default(),
|
|
|
|
computed_visibility: Default::default(),
|
|
|
|
z_index: Default::default(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|