Skip to content

Commit

Permalink
Add user control of UI cameras
Browse files Browse the repository at this point in the history
Add fields to UiCameraConfig to control the UI camera scale and
position.

Fixes #5242. It is again possible to manipulate the ui camera.

An alternative design was considered, where instead of having a
component that controls all of the UI camera settings, the component
would only hold an Entity referencing another camera.

That design was abandoned in favor of the current one because the
viewport is tightly bound to the "actual" camera the UI camera is
attached to. So it would be awkward to maintain independently two
different cameras.
  • Loading branch information
nicopap committed Jul 21, 2022
1 parent 17153b6 commit 60c29b8
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 20 deletions.
33 changes: 32 additions & 1 deletion crates/bevy_ui/src/entity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@

use crate::{
widget::{Button, ImageMode},
CalculatedSize, FocusPolicy, Interaction, Node, Style, UiColor, UiImage,
CalculatedSize, FocusPolicy, Interaction, Node, Style, UiColor, UiImage, UI_CAMERA_FAR,
};
use bevy_ecs::{bundle::Bundle, prelude::Component};
use bevy_math::Vec2;
use bevy_render::{
camera::{DepthCalculation, OrthographicProjection, WindowOrigin},
prelude::ComputedVisibility,
view::{RenderLayers, Visibility},
};
Expand Down Expand Up @@ -186,13 +188,42 @@ pub struct UiCameraConfig {
pub show_ui: bool,
/// The ui camera layers this camera can see.
pub ui_render_layers: RenderLayers,
/// The position of the UI camera in UI space.
pub position: Vec2,
/// The projection data for the UI camera.
///
/// The code relies on this not being set,
/// please use [`UiCameraConfig::scale_mut`] and [`UiCameraConfig::projection`]
/// instead.
/// This is only public so it is possible to use the struct update syntax.
#[doc(hidden)]
pub projection: OrthographicProjection,
}

impl UiCameraConfig {
/// Get mutably the scale of the UI camera, useful for zoom effects.
pub fn scale_mut(&mut self) -> &mut f32 {
&mut self.projection.scale
}

/// The projection data for the UI camera.
pub fn projection(&self) -> &OrthographicProjection {
&self.projection
}
}

impl Default for UiCameraConfig {
fn default() -> Self {
Self {
show_ui: true,
ui_render_layers: Default::default(),
position: Vec2::ZERO,
projection: OrthographicProjection {
far: UI_CAMERA_FAR,
window_origin: WindowOrigin::BottomLeft,
depth_calculation: DepthCalculation::ZDifference,
..Default::default()
},
}
}
}
10 changes: 9 additions & 1 deletion crates/bevy_ui/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ use bevy_input::InputSystem;
use bevy_render::view::VisibilitySystems;
use bevy_transform::TransformSystem;
use bevy_window::ModifiesWindows;
use update::{ui_z_system, update_clipping_system, update_layer_visibility};
use update::{
ui_z_system, update_clipping_system, update_layer_visibility, update_ui_camera_perspective,
};

/// The basic plugin for Bevy UI
#[derive(Default)]
Expand All @@ -48,6 +50,8 @@ pub enum UiSystem {
///
/// [`ComputedVisibility`]: bevy_render::view::ComputedVisibility
LayerVisibility,
/// Update Ui camera perspective to fit new viewport logical size.
UpdateUiCameraPerspective,
}

impl Plugin for UiPlugin {
Expand Down Expand Up @@ -93,6 +97,10 @@ impl Plugin for UiPlugin {
CoreStage::PostUpdate,
widget::image_node_system.before(UiSystem::Flex),
)
.add_system_to_stage(
CoreStage::Last,
update_ui_camera_perspective.label(UiSystem::UpdateUiCameraPerspective),
)
.add_system_to_stage(
CoreStage::PostUpdate,
flex_node_system
Expand Down
22 changes: 5 additions & 17 deletions crates/bevy_ui/src/render/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use bevy_ecs::prelude::*;
use bevy_math::{Mat4, Vec2, Vec3, Vec4Swizzles};
use bevy_reflect::TypeUuid;
use bevy_render::{
camera::{Camera, CameraProjection, DepthCalculation, OrthographicProjection, WindowOrigin},
camera::{Camera, CameraProjection},
color::Color,
render_asset::RenderAssets,
render_graph::{RenderGraph, RunGraphOnViewNode, SlotInfo, SlotType},
Expand Down Expand Up @@ -219,7 +219,7 @@ pub fn extract_uinodes(
/// as ui elements are "stacked on top of each other", they are within the camera's view
/// and have room to grow.
// TODO: Consider computing this value at runtime based on the maximum z-value.
const UI_CAMERA_FAR: f32 = 1000.0;
pub(crate) const UI_CAMERA_FAR: f32 = 1000.0;

// This value is subtracted from the far distance for the camera's z-position to ensure nodes at z == 0.0 are rendered
// TODO: Evaluate if we still need this.
Expand Down Expand Up @@ -251,26 +251,14 @@ pub fn extract_default_ui_camera_view<T: Component>(
if !ui_config.show_ui {
continue;
}
let logical_size = if let Some(logical_size) = camera.logical_viewport_size() {
logical_size
} else {
continue;
};
let mut projection = OrthographicProjection {
far: UI_CAMERA_FAR,
window_origin: WindowOrigin::BottomLeft,
depth_calculation: DepthCalculation::ZDifference,
..Default::default()
};
projection.update(logical_size.x, logical_size.y);
if let Some(physical_size) = camera.physical_viewport_size() {
let ui_camera = commands
.spawn()
.insert(ExtractedView {
projection: projection.get_projection_matrix(),
projection: ui_config.projection.get_projection_matrix(),
transform: GlobalTransform::from_xyz(
0.0,
0.0,
ui_config.position.x,
ui_config.position.y,
UI_CAMERA_FAR + UI_CAMERA_TRANSFORM_OFFSET,
),
width: physical_size.x,
Expand Down
19 changes: 18 additions & 1 deletion crates/bevy_ui/src/update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,16 @@ use crate::{entity::UiCameraConfig, CalculatedClip, Overflow, Style};
use super::Node;
use bevy_ecs::{
entity::Entity,
prelude::{Changed, Or},
query::{With, Without},
system::{Commands, Query},
};
use bevy_hierarchy::{Children, Parent};
use bevy_math::Vec2;
use bevy_render::view::{ComputedVisibility, RenderLayers};
use bevy_render::{
camera::{Camera, CameraProjection},
view::{ComputedVisibility, RenderLayers},
};
use bevy_sprite::Rect;
use bevy_transform::components::{GlobalTransform, Transform};

Expand Down Expand Up @@ -107,6 +111,19 @@ pub fn update_clipping_system(
}
}

pub fn update_ui_camera_perspective(
mut query: Query<
(&Camera, &mut UiCameraConfig),
Or<(Changed<Camera>, Changed<UiCameraConfig>)>,
>,
) {
for (camera, mut ui_config) in query.iter_mut() {
if let Some(logical_size) = camera.logical_viewport_size() {
ui_config.projection.update(logical_size.x, logical_size.y);
}
}
}

fn update_clipping(
commands: &mut Commands,
children_query: &Query<&Children>,
Expand Down

0 comments on commit 60c29b8

Please sign in to comment.