Remove ViewVisibility from UI nodes (#17405)
# Objective The UI can only target a single view and doesn't support `RenderLayers`, so there doesn't seem to be any need for UI nodes to require `ViewVisibility` and `VisibilityClass`. Fixes #17400 ## Solution Remove the `ViewVisibility` and `VisibilityClass` component requires from `Node` and change the visibility queries to only query for `InheritedVisibility`. ## Testing ```cargo run --example many_buttons --release --features "trace_tracy"``` Yellow is this PR, red is main. `bevy_render::view::visibility::reset_view_visibility` <img width="531" alt="reset-view" src="https://github.com/user-attachments/assets/a44b215d-96bf-43ec-8669-31530ff98eae" /> `bevy_render::view::visibility::check_visibility` <img width="445" alt="view_visibility" src="https://github.com/user-attachments/assets/fa111757-da91-434d-88e4-80bdfa29374f" />
This commit is contained in:
parent
68c19defb6
commit
dd2d84b342
@ -12,7 +12,7 @@ use bevy_ecs::{
|
|||||||
use bevy_input::{mouse::MouseButton, touch::Touches, ButtonInput};
|
use bevy_input::{mouse::MouseButton, touch::Touches, ButtonInput};
|
||||||
use bevy_math::{Rect, Vec2};
|
use bevy_math::{Rect, Vec2};
|
||||||
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
|
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
|
||||||
use bevy_render::{camera::NormalizedRenderTarget, prelude::Camera, view::ViewVisibility};
|
use bevy_render::{camera::NormalizedRenderTarget, prelude::Camera, view::InheritedVisibility};
|
||||||
use bevy_transform::components::GlobalTransform;
|
use bevy_transform::components::GlobalTransform;
|
||||||
use bevy_utils::HashMap;
|
use bevy_utils::HashMap;
|
||||||
use bevy_window::{PrimaryWindow, Window};
|
use bevy_window::{PrimaryWindow, Window};
|
||||||
@ -28,9 +28,9 @@ use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
|
|||||||
///
|
///
|
||||||
/// Updated in [`ui_focus_system`].
|
/// Updated in [`ui_focus_system`].
|
||||||
///
|
///
|
||||||
/// If a UI node has both [`Interaction`] and [`ViewVisibility`] components,
|
/// If a UI node has both [`Interaction`] and [`InheritedVisibility`] components,
|
||||||
/// [`Interaction`] will always be [`Interaction::None`]
|
/// [`Interaction`] will always be [`Interaction::None`]
|
||||||
/// when [`ViewVisibility::get()`] is false.
|
/// when [`InheritedVisibility::get()`] is false.
|
||||||
/// This ensures that hidden UI nodes are not interactable,
|
/// This ensures that hidden UI nodes are not interactable,
|
||||||
/// and do not end up stuck in an active state if hidden at the wrong time.
|
/// and do not end up stuck in an active state if hidden at the wrong time.
|
||||||
///
|
///
|
||||||
@ -140,13 +140,13 @@ pub struct NodeQuery {
|
|||||||
relative_cursor_position: Option<&'static mut RelativeCursorPosition>,
|
relative_cursor_position: Option<&'static mut RelativeCursorPosition>,
|
||||||
focus_policy: Option<&'static FocusPolicy>,
|
focus_policy: Option<&'static FocusPolicy>,
|
||||||
calculated_clip: Option<&'static CalculatedClip>,
|
calculated_clip: Option<&'static CalculatedClip>,
|
||||||
view_visibility: Option<&'static ViewVisibility>,
|
inherited_visibility: Option<&'static InheritedVisibility>,
|
||||||
target_camera: Option<&'static UiTargetCamera>,
|
target_camera: Option<&'static UiTargetCamera>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The system that sets Interaction for all UI elements based on the mouse cursor activity
|
/// The system that sets Interaction for all UI elements based on the mouse cursor activity
|
||||||
///
|
///
|
||||||
/// Entities with a hidden [`ViewVisibility`] are always treated as released.
|
/// Entities with a hidden [`InheritedVisibility`] are always treated as released.
|
||||||
pub fn ui_focus_system(
|
pub fn ui_focus_system(
|
||||||
mut state: Local<State>,
|
mut state: Local<State>,
|
||||||
camera_query: Query<(Entity, &Camera)>,
|
camera_query: Query<(Entity, &Camera)>,
|
||||||
@ -227,9 +227,9 @@ pub fn ui_focus_system(
|
|||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
|
|
||||||
let view_visibility = node.view_visibility?;
|
let inherited_visibility = node.inherited_visibility?;
|
||||||
// Nodes that are not rendered should not be interactable
|
// Nodes that are not rendered should not be interactable
|
||||||
if !view_visibility.get() {
|
if !inherited_visibility.get() {
|
||||||
// Reset their interaction to None to avoid strange stuck state
|
// Reset their interaction to None to avoid strange stuck state
|
||||||
if let Some(mut interaction) = node.interaction {
|
if let Some(mut interaction) = node.interaction {
|
||||||
// We cannot simply set the interaction to None, as that will trigger change detection repeatedly
|
// We cannot simply set the interaction to None, as that will trigger change detection repeatedly
|
||||||
|
|||||||
@ -50,7 +50,7 @@ pub struct NodeQuery {
|
|||||||
global_transform: &'static GlobalTransform,
|
global_transform: &'static GlobalTransform,
|
||||||
pickable: Option<&'static Pickable>,
|
pickable: Option<&'static Pickable>,
|
||||||
calculated_clip: Option<&'static CalculatedClip>,
|
calculated_clip: Option<&'static CalculatedClip>,
|
||||||
view_visibility: Option<&'static ViewVisibility>,
|
inherited_visibility: Option<&'static InheritedVisibility>,
|
||||||
target_camera: Option<&'static UiTargetCamera>,
|
target_camera: Option<&'static UiTargetCamera>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,8 +124,8 @@ pub fn ui_picking(
|
|||||||
|
|
||||||
// Nodes that are not rendered should not be interactable
|
// Nodes that are not rendered should not be interactable
|
||||||
if node
|
if node
|
||||||
.view_visibility
|
.inherited_visibility
|
||||||
.map(|view_visibility| view_visibility.get())
|
.map(|inherited_visibility| inherited_visibility.get())
|
||||||
!= Some(true)
|
!= Some(true)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@ -243,7 +243,7 @@ pub fn extract_shadows(
|
|||||||
Entity,
|
Entity,
|
||||||
&ComputedNode,
|
&ComputedNode,
|
||||||
&GlobalTransform,
|
&GlobalTransform,
|
||||||
&ViewVisibility,
|
&InheritedVisibility,
|
||||||
&BoxShadow,
|
&BoxShadow,
|
||||||
Option<&CalculatedClip>,
|
Option<&CalculatedClip>,
|
||||||
Option<&UiTargetCamera>,
|
Option<&UiTargetCamera>,
|
||||||
@ -253,8 +253,7 @@ pub fn extract_shadows(
|
|||||||
) {
|
) {
|
||||||
let default_camera_entity = default_ui_camera.get();
|
let default_camera_entity = default_ui_camera.get();
|
||||||
|
|
||||||
for (entity, uinode, transform, view_visibility, box_shadow, clip, camera) in &box_shadow_query
|
for (entity, uinode, transform, visibility, box_shadow, clip, camera) in &box_shadow_query {
|
||||||
{
|
|
||||||
let Some(camera_entity) = camera.map(UiTargetCamera::entity).or(default_camera_entity)
|
let Some(camera_entity) = camera.map(UiTargetCamera::entity).or(default_camera_entity)
|
||||||
else {
|
else {
|
||||||
continue;
|
continue;
|
||||||
@ -265,7 +264,7 @@ pub fn extract_shadows(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Skip if no visible shadows
|
// Skip if no visible shadows
|
||||||
if !view_visibility.get() || box_shadow.is_empty() || uinode.is_empty() {
|
if !visibility.get() || box_shadow.is_empty() || uinode.is_empty() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -14,7 +14,7 @@ use bevy_math::Rect;
|
|||||||
use bevy_math::Vec2;
|
use bevy_math::Vec2;
|
||||||
use bevy_render::sync_world::RenderEntity;
|
use bevy_render::sync_world::RenderEntity;
|
||||||
use bevy_render::sync_world::TemporaryRenderEntity;
|
use bevy_render::sync_world::TemporaryRenderEntity;
|
||||||
use bevy_render::view::ViewVisibility;
|
use bevy_render::view::InheritedVisibility;
|
||||||
use bevy_render::Extract;
|
use bevy_render::Extract;
|
||||||
use bevy_sprite::BorderRect;
|
use bevy_sprite::BorderRect;
|
||||||
use bevy_transform::components::GlobalTransform;
|
use bevy_transform::components::GlobalTransform;
|
||||||
@ -63,7 +63,7 @@ pub fn extract_debug_overlay(
|
|||||||
Query<(
|
Query<(
|
||||||
Entity,
|
Entity,
|
||||||
&ComputedNode,
|
&ComputedNode,
|
||||||
&ViewVisibility,
|
&InheritedVisibility,
|
||||||
Option<&CalculatedClip>,
|
Option<&CalculatedClip>,
|
||||||
&GlobalTransform,
|
&GlobalTransform,
|
||||||
Option<&UiTargetCamera>,
|
Option<&UiTargetCamera>,
|
||||||
|
|||||||
@ -42,7 +42,7 @@ use bevy_render::{
|
|||||||
render_phase::{PhaseItem, PhaseItemExtraIndex},
|
render_phase::{PhaseItem, PhaseItemExtraIndex},
|
||||||
sync_world::{RenderEntity, TemporaryRenderEntity},
|
sync_world::{RenderEntity, TemporaryRenderEntity},
|
||||||
texture::GpuImage,
|
texture::GpuImage,
|
||||||
view::ViewVisibility,
|
view::InheritedVisibility,
|
||||||
ExtractSchedule, Render,
|
ExtractSchedule, Render,
|
||||||
};
|
};
|
||||||
use bevy_sprite::{BorderRect, SpriteAssetEvents};
|
use bevy_sprite::{BorderRect, SpriteAssetEvents};
|
||||||
@ -285,7 +285,7 @@ pub fn extract_uinode_background_colors(
|
|||||||
Entity,
|
Entity,
|
||||||
&ComputedNode,
|
&ComputedNode,
|
||||||
&GlobalTransform,
|
&GlobalTransform,
|
||||||
&ViewVisibility,
|
&InheritedVisibility,
|
||||||
Option<&CalculatedClip>,
|
Option<&CalculatedClip>,
|
||||||
Option<&UiTargetCamera>,
|
Option<&UiTargetCamera>,
|
||||||
&BackgroundColor,
|
&BackgroundColor,
|
||||||
@ -294,7 +294,7 @@ pub fn extract_uinode_background_colors(
|
|||||||
mapping: Extract<Query<RenderEntity>>,
|
mapping: Extract<Query<RenderEntity>>,
|
||||||
) {
|
) {
|
||||||
let default_camera_entity = default_ui_camera.get();
|
let default_camera_entity = default_ui_camera.get();
|
||||||
for (entity, uinode, transform, view_visibility, clip, camera, background_color) in
|
for (entity, uinode, transform, inherited_visibility, clip, camera, background_color) in
|
||||||
&uinode_query
|
&uinode_query
|
||||||
{
|
{
|
||||||
let Some(camera_entity) = camera.map(UiTargetCamera::entity).or(default_camera_entity)
|
let Some(camera_entity) = camera.map(UiTargetCamera::entity).or(default_camera_entity)
|
||||||
@ -307,7 +307,7 @@ pub fn extract_uinode_background_colors(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Skip invisible backgrounds
|
// Skip invisible backgrounds
|
||||||
if !view_visibility.get() || background_color.0.is_fully_transparent() {
|
if !inherited_visibility.get() || background_color.0.is_fully_transparent() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -348,7 +348,7 @@ pub fn extract_uinode_images(
|
|||||||
Entity,
|
Entity,
|
||||||
&ComputedNode,
|
&ComputedNode,
|
||||||
&GlobalTransform,
|
&GlobalTransform,
|
||||||
&ViewVisibility,
|
&InheritedVisibility,
|
||||||
Option<&CalculatedClip>,
|
Option<&CalculatedClip>,
|
||||||
Option<&UiTargetCamera>,
|
Option<&UiTargetCamera>,
|
||||||
&ImageNode,
|
&ImageNode,
|
||||||
@ -357,7 +357,7 @@ pub fn extract_uinode_images(
|
|||||||
mapping: Extract<Query<RenderEntity>>,
|
mapping: Extract<Query<RenderEntity>>,
|
||||||
) {
|
) {
|
||||||
let default_camera_entity = default_ui_camera.get();
|
let default_camera_entity = default_ui_camera.get();
|
||||||
for (entity, uinode, transform, view_visibility, clip, camera, image) in &uinode_query {
|
for (entity, uinode, transform, inherited_visibility, clip, camera, image) in &uinode_query {
|
||||||
let Some(camera_entity) = camera.map(UiTargetCamera::entity).or(default_camera_entity)
|
let Some(camera_entity) = camera.map(UiTargetCamera::entity).or(default_camera_entity)
|
||||||
else {
|
else {
|
||||||
continue;
|
continue;
|
||||||
@ -368,7 +368,7 @@ pub fn extract_uinode_images(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Skip invisible images
|
// Skip invisible images
|
||||||
if !view_visibility.get()
|
if !inherited_visibility.get()
|
||||||
|| image.color.is_fully_transparent()
|
|| image.color.is_fully_transparent()
|
||||||
|| image.image.id() == TRANSPARENT_IMAGE_HANDLE.id()
|
|| image.image.id() == TRANSPARENT_IMAGE_HANDLE.id()
|
||||||
|| image.image_mode.uses_slices()
|
|| image.image_mode.uses_slices()
|
||||||
@ -439,7 +439,7 @@ pub fn extract_uinode_borders(
|
|||||||
&Node,
|
&Node,
|
||||||
&ComputedNode,
|
&ComputedNode,
|
||||||
&GlobalTransform,
|
&GlobalTransform,
|
||||||
&ViewVisibility,
|
&InheritedVisibility,
|
||||||
Option<&CalculatedClip>,
|
Option<&CalculatedClip>,
|
||||||
Option<&UiTargetCamera>,
|
Option<&UiTargetCamera>,
|
||||||
AnyOf<(&BorderColor, &Outline)>,
|
AnyOf<(&BorderColor, &Outline)>,
|
||||||
@ -454,7 +454,7 @@ pub fn extract_uinode_borders(
|
|||||||
node,
|
node,
|
||||||
computed_node,
|
computed_node,
|
||||||
global_transform,
|
global_transform,
|
||||||
view_visibility,
|
inherited_visibility,
|
||||||
maybe_clip,
|
maybe_clip,
|
||||||
maybe_camera,
|
maybe_camera,
|
||||||
(maybe_border_color, maybe_outline),
|
(maybe_border_color, maybe_outline),
|
||||||
@ -472,7 +472,7 @@ pub fn extract_uinode_borders(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Skip invisible borders and removed nodes
|
// Skip invisible borders and removed nodes
|
||||||
if !view_visibility.get() || node.display == Display::None {
|
if !inherited_visibility.get() || node.display == Display::None {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -678,7 +678,7 @@ pub fn extract_text_sections(
|
|||||||
Entity,
|
Entity,
|
||||||
&ComputedNode,
|
&ComputedNode,
|
||||||
&GlobalTransform,
|
&GlobalTransform,
|
||||||
&ViewVisibility,
|
&InheritedVisibility,
|
||||||
Option<&CalculatedClip>,
|
Option<&CalculatedClip>,
|
||||||
Option<&UiTargetCamera>,
|
Option<&UiTargetCamera>,
|
||||||
&ComputedTextBlock,
|
&ComputedTextBlock,
|
||||||
@ -696,7 +696,7 @@ pub fn extract_text_sections(
|
|||||||
entity,
|
entity,
|
||||||
uinode,
|
uinode,
|
||||||
global_transform,
|
global_transform,
|
||||||
view_visibility,
|
inherited_visibility,
|
||||||
clip,
|
clip,
|
||||||
camera,
|
camera,
|
||||||
computed_block,
|
computed_block,
|
||||||
@ -708,7 +708,7 @@ pub fn extract_text_sections(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Skip if not visible or if size is set to zero (e.g. when a parent is set to `Display::None`)
|
// Skip if not visible or if size is set to zero (e.g. when a parent is set to `Display::None`)
|
||||||
if !view_visibility.get() || uinode.is_empty() {
|
if !inherited_visibility.get() || uinode.is_empty() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -369,7 +369,7 @@ pub fn extract_ui_material_nodes<M: UiMaterial>(
|
|||||||
&ComputedNode,
|
&ComputedNode,
|
||||||
&GlobalTransform,
|
&GlobalTransform,
|
||||||
&MaterialNode<M>,
|
&MaterialNode<M>,
|
||||||
&ViewVisibility,
|
&InheritedVisibility,
|
||||||
Option<&CalculatedClip>,
|
Option<&CalculatedClip>,
|
||||||
Option<&UiTargetCamera>,
|
Option<&UiTargetCamera>,
|
||||||
)>,
|
)>,
|
||||||
@ -379,7 +379,9 @@ pub fn extract_ui_material_nodes<M: UiMaterial>(
|
|||||||
// If there is only one camera, we use it as default
|
// If there is only one camera, we use it as default
|
||||||
let default_single_camera = default_ui_camera.get();
|
let default_single_camera = default_ui_camera.get();
|
||||||
|
|
||||||
for (entity, uinode, transform, handle, view_visibility, clip, camera) in uinode_query.iter() {
|
for (entity, uinode, transform, handle, inherited_visibility, clip, camera) in
|
||||||
|
uinode_query.iter()
|
||||||
|
{
|
||||||
let Some(camera_entity) = camera.map(UiTargetCamera::entity).or(default_single_camera)
|
let Some(camera_entity) = camera.map(UiTargetCamera::entity).or(default_single_camera)
|
||||||
else {
|
else {
|
||||||
continue;
|
continue;
|
||||||
@ -390,7 +392,7 @@ pub fn extract_ui_material_nodes<M: UiMaterial>(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// skip invisible nodes
|
// skip invisible nodes
|
||||||
if !view_visibility.get() {
|
if !inherited_visibility.get() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -254,7 +254,7 @@ pub fn extract_ui_texture_slices(
|
|||||||
Entity,
|
Entity,
|
||||||
&ComputedNode,
|
&ComputedNode,
|
||||||
&GlobalTransform,
|
&GlobalTransform,
|
||||||
&ViewVisibility,
|
&InheritedVisibility,
|
||||||
Option<&CalculatedClip>,
|
Option<&CalculatedClip>,
|
||||||
Option<&UiTargetCamera>,
|
Option<&UiTargetCamera>,
|
||||||
&ImageNode,
|
&ImageNode,
|
||||||
@ -264,7 +264,7 @@ pub fn extract_ui_texture_slices(
|
|||||||
) {
|
) {
|
||||||
let default_camera_entity = default_ui_camera.get();
|
let default_camera_entity = default_ui_camera.get();
|
||||||
|
|
||||||
for (entity, uinode, transform, view_visibility, clip, camera, image) in &slicers_query {
|
for (entity, uinode, transform, inherited_visibility, clip, camera, image) in &slicers_query {
|
||||||
let Some(camera_entity) = camera.map(UiTargetCamera::entity).or(default_camera_entity)
|
let Some(camera_entity) = camera.map(UiTargetCamera::entity).or(default_camera_entity)
|
||||||
else {
|
else {
|
||||||
continue;
|
continue;
|
||||||
@ -291,7 +291,7 @@ pub fn extract_ui_texture_slices(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Skip invisible images
|
// Skip invisible images
|
||||||
if !view_visibility.get()
|
if !inherited_visibility.get()
|
||||||
|| image.color.is_fully_transparent()
|
|| image.color.is_fully_transparent()
|
||||||
|| image.image.id() == TRANSPARENT_IMAGE_HANDLE.id()
|
|| image.image.id() == TRANSPARENT_IMAGE_HANDLE.id()
|
||||||
{
|
{
|
||||||
|
|||||||
@ -6,7 +6,7 @@ use bevy_math::{vec4, Rect, Vec2, Vec4Swizzles};
|
|||||||
use bevy_reflect::prelude::*;
|
use bevy_reflect::prelude::*;
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
camera::{Camera, RenderTarget},
|
camera::{Camera, RenderTarget},
|
||||||
view::{self, Visibility, VisibilityClass},
|
view::Visibility,
|
||||||
};
|
};
|
||||||
use bevy_sprite::BorderRect;
|
use bevy_sprite::BorderRect;
|
||||||
use bevy_transform::components::Transform;
|
use bevy_transform::components::Transform;
|
||||||
@ -329,11 +329,9 @@ impl From<Vec2> for ScrollPosition {
|
|||||||
ScrollPosition,
|
ScrollPosition,
|
||||||
Transform,
|
Transform,
|
||||||
Visibility,
|
Visibility,
|
||||||
VisibilityClass,
|
|
||||||
ZIndex
|
ZIndex
|
||||||
)]
|
)]
|
||||||
#[reflect(Component, Default, PartialEq, Debug)]
|
#[reflect(Component, Default, PartialEq, Debug)]
|
||||||
#[component(on_add = view::add_visibility_class::<Node>)]
|
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "serialize",
|
feature = "serialize",
|
||||||
derive(serde::Serialize, serde::Deserialize),
|
derive(serde::Serialize, serde::Deserialize),
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user