Skip to content

Commit 60c29b8

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 17153b6 commit 60c29b8

File tree

4 files changed

+64
-20
lines changed

4 files changed

+64
-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
};
@@ -186,13 +188,42 @@ pub struct UiCameraConfig {
186188
pub show_ui: bool,
187189
/// The ui camera layers this camera can see.
188190
pub ui_render_layers: RenderLayers,
191+
/// The position of the UI camera in UI space.
192+
pub position: Vec2,
193+
/// The projection data for the UI camera.
194+
///
195+
/// The code relies on this not being set,
196+
/// please use [`UiCameraConfig::scale_mut`] and [`UiCameraConfig::projection`]
197+
/// instead.
198+
/// This is only public so it is possible to use the struct update syntax.
199+
#[doc(hidden)]
200+
pub projection: OrthographicProjection,
201+
}
202+
203+
impl UiCameraConfig {
204+
/// Get mutably the scale of the UI camera, useful for zoom effects.
205+
pub fn scale_mut(&mut self) -> &mut f32 {
206+
&mut self.projection.scale
207+
}
208+
209+
/// The projection data for the UI camera.
210+
pub fn projection(&self) -> &OrthographicProjection {
211+
&self.projection
212+
}
189213
}
190214

191215
impl Default for UiCameraConfig {
192216
fn default() -> Self {
193217
Self {
194218
show_ui: true,
195219
ui_render_layers: Default::default(),
220+
position: Vec2::ZERO,
221+
projection: OrthographicProjection {
222+
far: UI_CAMERA_FAR,
223+
window_origin: WindowOrigin::BottomLeft,
224+
depth_calculation: DepthCalculation::ZDifference,
225+
..Default::default()
226+
},
196227
}
197228
}
198229
}

crates/bevy_ui/src/lib.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ use bevy_input::InputSystem;
3030
use bevy_render::view::VisibilitySystems;
3131
use bevy_transform::TransformSystem;
3232
use bevy_window::ModifiesWindows;
33-
use update::{ui_z_system, update_clipping_system, update_layer_visibility};
33+
use update::{
34+
ui_z_system, update_clipping_system, update_layer_visibility, update_ui_camera_perspective,
35+
};
3436

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

5357
impl Plugin for UiPlugin {
@@ -93,6 +97,10 @@ impl Plugin for UiPlugin {
9397
CoreStage::PostUpdate,
9498
widget::image_node_system.before(UiSystem::Flex),
9599
)
100+
.add_system_to_stage(
101+
CoreStage::Last,
102+
update_ui_camera_perspective.label(UiSystem::UpdateUiCameraPerspective),
103+
)
96104
.add_system_to_stage(
97105
CoreStage::PostUpdate,
98106
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},
@@ -219,7 +219,7 @@ pub fn extract_uinodes(
219219
/// as ui elements are "stacked on top of each other", they are within the camera's view
220220
/// and have room to grow.
221221
// TODO: Consider computing this value at runtime based on the maximum z-value.
222-
const UI_CAMERA_FAR: f32 = 1000.0;
222+
pub(crate) const UI_CAMERA_FAR: f32 = 1000.0;
223223

224224
// This value is subtracted from the far distance for the camera's z-position to ensure nodes at z == 0.0 are rendered
225225
// TODO: Evaluate if we still need this.
@@ -251,26 +251,14 @@ pub fn extract_default_ui_camera_view<T: Component>(
251251
if !ui_config.show_ui {
252252
continue;
253253
}
254-
let logical_size = if let Some(logical_size) = camera.logical_viewport_size() {
255-
logical_size
256-
} else {
257-
continue;
258-
};
259-
let mut projection = OrthographicProjection {
260-
far: UI_CAMERA_FAR,
261-
window_origin: WindowOrigin::BottomLeft,
262-
depth_calculation: DepthCalculation::ZDifference,
263-
..Default::default()
264-
};
265-
projection.update(logical_size.x, logical_size.y);
266254
if let Some(physical_size) = camera.physical_viewport_size() {
267255
let ui_camera = commands
268256
.spawn()
269257
.insert(ExtractedView {
270-
projection: projection.get_projection_matrix(),
258+
projection: ui_config.projection.get_projection_matrix(),
271259
transform: GlobalTransform::from_xyz(
272-
0.0,
273-
0.0,
260+
ui_config.position.x,
261+
ui_config.position.y,
274262
UI_CAMERA_FAR + UI_CAMERA_TRANSFORM_OFFSET,
275263
),
276264
width: physical_size.x,

crates/bevy_ui/src/update.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,16 @@ use crate::{entity::UiCameraConfig, CalculatedClip, Overflow, Style};
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;
13-
use bevy_render::view::{ComputedVisibility, RenderLayers};
14+
use bevy_render::{
15+
camera::{Camera, CameraProjection},
16+
view::{ComputedVisibility, RenderLayers},
17+
};
1418
use bevy_sprite::Rect;
1519
use bevy_transform::components::{GlobalTransform, Transform};
1620

@@ -107,6 +111,19 @@ pub fn update_clipping_system(
107111
}
108112
}
109113

114+
pub fn update_ui_camera_perspective(
115+
mut query: Query<
116+
(&Camera, &mut UiCameraConfig),
117+
Or<(Changed<Camera>, Changed<UiCameraConfig>)>,
118+
>,
119+
) {
120+
for (camera, mut ui_config) in query.iter_mut() {
121+
if let Some(logical_size) = camera.logical_viewport_size() {
122+
ui_config.projection.update(logical_size.x, logical_size.y);
123+
}
124+
}
125+
}
126+
110127
fn update_clipping(
111128
commands: &mut Commands,
112129
children_query: &Query<&Children>,

0 commit comments

Comments
 (0)