Skip to content

Commit be9d099

Browse files
committed
Add user control of UI cameras
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.
1 parent 31155fe commit be9d099

File tree

4 files changed

+60
-20
lines changed

4 files changed

+60
-20
lines changed

crates/bevy_ui/src/entity.rs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@
22
33
use crate::{
44
widget::{Button, ImageMode},
5-
CalculatedSize, FocusPolicy, Interaction, Node, Style, UiColor, UiImage,
5+
CalculatedSize, FocusPolicy, Interaction, Node, Style, UiColor, UiImage, UI_CAMERA_FAR,
66
};
77
use bevy_ecs::{bundle::Bundle, prelude::Component};
8+
use bevy_math::Vec2;
89
use bevy_render::{
10+
camera::{DepthCalculation, OrthographicProjection, WindowOrigin},
911
prelude::ComputedVisibility,
1012
view::{RenderLayers, Visibility},
1113
};
@@ -152,13 +154,42 @@ pub struct UiCameraConfig {
152154
pub show_ui: bool,
153155
/// The ui camera layers this camera can see.
154156
pub ui_render_layers: RenderLayers,
157+
/// The position of the UI camera in UI space.
158+
pub position: Vec2,
159+
/// The projection data for the UI camera.
160+
///
161+
/// The code relies on this not being set,
162+
/// please use [`UiCameraConfig::scale_mut`] and [`UiCameraConfig::projection`]
163+
/// instead.
164+
/// This is only public so it is possible to use the struct update syntax.
165+
#[doc(hidden)]
166+
pub projection: OrthographicProjection,
167+
}
168+
169+
impl UiCameraConfig {
170+
/// Get mutably the scale of the UI camera, useful for zoom effects.
171+
pub fn scale_mut(&mut self) -> &mut f32 {
172+
&mut self.projection.scale
173+
}
174+
175+
/// The projection data for the UI camera.
176+
pub fn projection(&self) -> &OrthographicProjection {
177+
&self.projection
178+
}
155179
}
156180

157181
impl Default for UiCameraConfig {
158182
fn default() -> Self {
159183
Self {
160184
show_ui: true,
161185
ui_render_layers: Default::default(),
186+
position: Vec2::ZERO,
187+
projection: OrthographicProjection {
188+
far: UI_CAMERA_FAR,
189+
window_origin: WindowOrigin::BottomLeft,
190+
depth_calculation: DepthCalculation::ZDifference,
191+
..Default::default()
192+
},
162193
}
163194
}
164195
}

crates/bevy_ui/src/lib.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use bevy_ecs::schedule::{ParallelSystemDescriptorCoercion, SystemLabel};
2929
use bevy_input::InputSystem;
3030
use bevy_transform::TransformSystem;
3131
use bevy_window::ModifiesWindows;
32-
use update::{ui_z_system, update_clipping_system};
32+
use update::{ui_z_system, update_clipping_system, update_ui_camera_perspective};
3333

3434
/// The basic plugin for Bevy UI
3535
#[derive(Default)]
@@ -42,6 +42,8 @@ pub enum UiSystem {
4242
Flex,
4343
/// After this label, input interactions with UI entities have been updated for this frame
4444
Focus,
45+
/// Update Ui camera perspective to fit new viewport logical size.
46+
UpdateUiCameraPerspective,
4547
}
4648

4749
impl Plugin for UiPlugin {
@@ -87,6 +89,10 @@ impl Plugin for UiPlugin {
8789
CoreStage::PostUpdate,
8890
widget::image_node_system.before(UiSystem::Flex),
8991
)
92+
.add_system_to_stage(
93+
CoreStage::Last,
94+
update_ui_camera_perspective.label(UiSystem::UpdateUiCameraPerspective),
95+
)
9096
.add_system_to_stage(
9197
CoreStage::PostUpdate,
9298
flex_node_system

crates/bevy_ui/src/render/mod.rs

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use bevy_ecs::prelude::*;
1212
use bevy_math::{Mat4, Vec2, Vec3, Vec4Swizzles};
1313
use bevy_reflect::TypeUuid;
1414
use bevy_render::{
15-
camera::{Camera, CameraProjection, DepthCalculation, OrthographicProjection, WindowOrigin},
15+
camera::{Camera, CameraProjection},
1616
color::Color,
1717
render_asset::RenderAssets,
1818
render_graph::{RenderGraph, RunGraphOnViewNode, SlotInfo, SlotType},
@@ -218,7 +218,7 @@ pub fn extract_uinodes(
218218
/// as ui elements are "stacked on top of each other", they are within the camera's view
219219
/// and have room to grow.
220220
// TODO: Consider computing this value at runtime based on the maximum z-value.
221-
const UI_CAMERA_FAR: f32 = 1000.0;
221+
pub(crate) const UI_CAMERA_FAR: f32 = 1000.0;
222222

223223
// This value is subtracted from the far distance for the camera's z-position to ensure nodes at z == 0.0 are rendered
224224
// TODO: Evaluate if we still need this.
@@ -240,26 +240,14 @@ pub fn extract_default_ui_camera_view<T: Component>(
240240
if !ui_config.show_ui {
241241
continue;
242242
}
243-
let logical_size = if let Some(logical_size) = camera.logical_viewport_size() {
244-
logical_size
245-
} else {
246-
continue;
247-
};
248-
let mut projection = OrthographicProjection {
249-
far: UI_CAMERA_FAR,
250-
window_origin: WindowOrigin::BottomLeft,
251-
depth_calculation: DepthCalculation::ZDifference,
252-
..Default::default()
253-
};
254-
projection.update(logical_size.x, logical_size.y);
255243
if let Some(physical_size) = camera.physical_viewport_size() {
256244
let ui_camera = commands
257245
.spawn()
258246
.insert(ExtractedView {
259-
projection: projection.get_projection_matrix(),
247+
projection: ui_config.projection.get_projection_matrix(),
260248
transform: GlobalTransform::from_xyz(
261-
0.0,
262-
0.0,
249+
ui_config.position.x,
250+
ui_config.position.y,
263251
UI_CAMERA_FAR + UI_CAMERA_TRANSFORM_OFFSET,
264252
),
265253
width: physical_size.x,

crates/bevy_ui/src/update.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
//! This module contains systems that update the UI when something changes
22
3-
use crate::{CalculatedClip, Overflow, Style};
3+
use crate::{prelude::UiCameraConfig, CalculatedClip, Overflow, Style};
44

55
use super::Node;
66
use bevy_ecs::{
77
entity::Entity,
8+
prelude::{Changed, Or},
89
query::{With, Without},
910
system::{Commands, Query},
1011
};
1112
use bevy_hierarchy::{Children, Parent};
1213
use bevy_math::Vec2;
14+
use bevy_render::camera::{Camera, CameraProjection};
1315
use bevy_sprite::Rect;
1416
use bevy_transform::components::{GlobalTransform, Transform};
1517

@@ -82,6 +84,19 @@ pub fn update_clipping_system(
8284
}
8385
}
8486

87+
pub fn update_ui_camera_perspective(
88+
mut query: Query<
89+
(&Camera, &mut UiCameraConfig),
90+
Or<(Changed<Camera>, Changed<UiCameraConfig>)>,
91+
>,
92+
) {
93+
for (camera, mut ui_config) in query.iter_mut() {
94+
if let Some(logical_size) = camera.logical_viewport_size() {
95+
ui_config.projection.update(logical_size.x, logical_size.y);
96+
}
97+
}
98+
}
99+
85100
fn update_clipping(
86101
commands: &mut Commands,
87102
children_query: &Query<&Children>,

0 commit comments

Comments
 (0)