Skip to content

Commit 57f9ac1

Browse files
authored
OrthographicProjection scaling mode + camera bundle refactoring (#400)
* add normalized orthographic projection * custom scale for ScaledOrthographicProjection * allow choosing base axis for ScaledOrthographicProjection * cargo fmt * add general (scaled) orthographic camera bundle FIXME: does the same "far" trick from Camera2DBundle make any sense here? * fixes * camera bundles: rename and new ortho constructors * unify orthographic projections * give PerspectiveCameraBundle constructors like those of OrthographicCameraBundle * update examples with new camera bundle syntax * rename CameraUiBundle to UiCameraBundle * update examples * ScalingMode::None * remove extra blank lines * sane default bounds for orthographic projection * fix alien_cake_addict example * reorder ScalingMode enum variants * ios example fix
1 parent af67231 commit 57f9ac1

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+163
-67
lines changed

crates/bevy_render/src/camera/projection.rs

Lines changed: 58 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,20 @@ pub enum WindowOrigin {
5151
BottomLeft,
5252
}
5353

54+
#[derive(Debug, Clone, Reflect, Serialize, Deserialize)]
55+
#[reflect_value(Serialize, Deserialize)]
56+
pub enum ScalingMode {
57+
/// Manually specify left/right/top/bottom values.
58+
/// Ignore window resizing; the image will stretch.
59+
None,
60+
/// Match the window size. 1 world unit = 1 pixel.
61+
WindowSize,
62+
/// Keep vertical axis constant; resize horizontal with aspect ratio.
63+
FixedVertical,
64+
/// Keep horizontal axis constant; resize vertical with aspect ratio.
65+
FixedHorizontal,
66+
}
67+
5468
#[derive(Debug, Clone, Reflect)]
5569
#[reflect(Component)]
5670
pub struct OrthographicProjection {
@@ -61,36 +75,67 @@ pub struct OrthographicProjection {
6175
pub near: f32,
6276
pub far: f32,
6377
pub window_origin: WindowOrigin,
78+
pub scaling_mode: ScalingMode,
79+
pub scale: f32,
6480
}
6581

6682
impl CameraProjection for OrthographicProjection {
6783
fn get_projection_matrix(&self) -> Mat4 {
6884
Mat4::orthographic_rh(
69-
self.left,
70-
self.right,
71-
self.bottom,
72-
self.top,
85+
self.left * self.scale,
86+
self.right * self.scale,
87+
self.bottom * self.scale,
88+
self.top * self.scale,
7389
self.near,
7490
self.far,
7591
)
7692
}
7793

7894
fn update(&mut self, width: f32, height: f32) {
79-
match self.window_origin {
80-
WindowOrigin::Center => {
95+
match (&self.scaling_mode, &self.window_origin) {
96+
(ScalingMode::WindowSize, WindowOrigin::Center) => {
8197
let half_width = width / 2.0;
8298
let half_height = height / 2.0;
8399
self.left = -half_width;
84100
self.right = half_width;
85101
self.top = half_height;
86102
self.bottom = -half_height;
87103
}
88-
WindowOrigin::BottomLeft => {
104+
(ScalingMode::WindowSize, WindowOrigin::BottomLeft) => {
89105
self.left = 0.0;
90106
self.right = width;
91107
self.top = height;
92108
self.bottom = 0.0;
93109
}
110+
(ScalingMode::FixedVertical, WindowOrigin::Center) => {
111+
let aspect_ratio = width / height;
112+
self.left = -aspect_ratio;
113+
self.right = aspect_ratio;
114+
self.top = 1.0;
115+
self.bottom = -1.0;
116+
}
117+
(ScalingMode::FixedVertical, WindowOrigin::BottomLeft) => {
118+
let aspect_ratio = width / height;
119+
self.left = 0.0;
120+
self.right = aspect_ratio;
121+
self.top = 1.0;
122+
self.bottom = 0.0;
123+
}
124+
(ScalingMode::FixedHorizontal, WindowOrigin::Center) => {
125+
let aspect_ratio = height / width;
126+
self.left = -1.0;
127+
self.right = 1.0;
128+
self.top = aspect_ratio;
129+
self.bottom = -aspect_ratio;
130+
}
131+
(ScalingMode::FixedHorizontal, WindowOrigin::BottomLeft) => {
132+
let aspect_ratio = height / width;
133+
self.left = 0.0;
134+
self.right = 1.0;
135+
self.top = aspect_ratio;
136+
self.bottom = 0.0;
137+
}
138+
(ScalingMode::None, _) => {}
94139
}
95140
}
96141

@@ -102,13 +147,15 @@ impl CameraProjection for OrthographicProjection {
102147
impl Default for OrthographicProjection {
103148
fn default() -> Self {
104149
OrthographicProjection {
105-
left: 0.0,
106-
right: 0.0,
107-
bottom: 0.0,
108-
top: 0.0,
150+
left: -1.0,
151+
right: 1.0,
152+
bottom: -1.0,
153+
top: 1.0,
109154
near: 0.0,
110155
far: 1000.0,
111156
window_origin: WindowOrigin::Center,
157+
scaling_mode: ScalingMode::WindowSize,
158+
scale: 1.0,
112159
}
113160
}
114161
}

crates/bevy_render/src/entity.rs

Lines changed: 58 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,40 @@ pub struct MeshBundle {
2222
pub global_transform: GlobalTransform,
2323
}
2424

25-
/// A component bundle for "3d camera" entities
25+
/// Component bundle for camera entities with perspective projection
26+
///
27+
/// Use this for 3D rendering.
2628
#[derive(Bundle)]
27-
pub struct Camera3dBundle {
29+
pub struct PerspectiveCameraBundle {
2830
pub camera: Camera,
2931
pub perspective_projection: PerspectiveProjection,
3032
pub visible_entities: VisibleEntities,
3133
pub transform: Transform,
3234
pub global_transform: GlobalTransform,
3335
}
3436

35-
impl Default for Camera3dBundle {
37+
impl PerspectiveCameraBundle {
38+
pub fn new_3d() -> Self {
39+
Default::default()
40+
}
41+
42+
pub fn with_name(name: &str) -> Self {
43+
PerspectiveCameraBundle {
44+
camera: Camera {
45+
name: Some(name.to_string()),
46+
..Default::default()
47+
},
48+
perspective_projection: Default::default(),
49+
visible_entities: Default::default(),
50+
transform: Default::default(),
51+
global_transform: Default::default(),
52+
}
53+
}
54+
}
55+
56+
impl Default for PerspectiveCameraBundle {
3657
fn default() -> Self {
37-
Camera3dBundle {
58+
PerspectiveCameraBundle {
3859
camera: Camera {
3960
name: Some(base::camera::CAMERA_3D.to_string()),
4061
..Default::default()
@@ -47,22 +68,24 @@ impl Default for Camera3dBundle {
4768
}
4869
}
4970

50-
/// A component bundle for "2d camera" entities
71+
/// Component bundle for camera entities with orthographic projection
72+
///
73+
/// Use this for 2D games, isometric games, CAD-like 3D views.
5174
#[derive(Bundle)]
52-
pub struct Camera2dBundle {
75+
pub struct OrthographicCameraBundle {
5376
pub camera: Camera,
5477
pub orthographic_projection: OrthographicProjection,
5578
pub visible_entities: VisibleEntities,
5679
pub transform: Transform,
5780
pub global_transform: GlobalTransform,
5881
}
5982

60-
impl Default for Camera2dBundle {
61-
fn default() -> Self {
83+
impl OrthographicCameraBundle {
84+
pub fn new_2d() -> Self {
6285
// we want 0 to be "closest" and +far to be "farthest" in 2d, so we offset
6386
// the camera's translation by far and use a right handed coordinate system
6487
let far = 1000.0;
65-
Camera2dBundle {
88+
OrthographicCameraBundle {
6689
camera: Camera {
6790
name: Some(base::camera::CAMERA_2D.to_string()),
6891
..Default::default()
@@ -76,4 +99,30 @@ impl Default for Camera2dBundle {
7699
global_transform: Default::default(),
77100
}
78101
}
102+
103+
pub fn new_3d() -> Self {
104+
OrthographicCameraBundle {
105+
camera: Camera {
106+
name: Some(base::camera::CAMERA_3D.to_string()),
107+
..Default::default()
108+
},
109+
orthographic_projection: Default::default(),
110+
visible_entities: Default::default(),
111+
transform: Default::default(),
112+
global_transform: Default::default(),
113+
}
114+
}
115+
116+
pub fn with_name(name: &str) -> Self {
117+
OrthographicCameraBundle {
118+
camera: Camera {
119+
name: Some(name.to_string()),
120+
..Default::default()
121+
},
122+
orthographic_projection: Default::default(),
123+
visible_entities: Default::default(),
124+
transform: Default::default(),
125+
global_transform: Default::default(),
126+
}
127+
}
79128
}

crates/bevy_ui/src/entity.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -164,20 +164,20 @@ impl Default for ButtonBundle {
164164
}
165165

166166
#[derive(Bundle, Debug)]
167-
pub struct CameraUiBundle {
167+
pub struct UiCameraBundle {
168168
pub camera: Camera,
169169
pub orthographic_projection: OrthographicProjection,
170170
pub visible_entities: VisibleEntities,
171171
pub transform: Transform,
172172
pub global_transform: GlobalTransform,
173173
}
174174

175-
impl Default for CameraUiBundle {
175+
impl Default for UiCameraBundle {
176176
fn default() -> Self {
177177
// we want 0 to be "closest" and +far to be "farthest" in 2d, so we offset
178178
// the camera's translation by far and use a right handed coordinate system
179179
let far = 1000.0;
180-
CameraUiBundle {
180+
UiCameraBundle {
181181
camera: Camera {
182182
name: Some(crate::camera::CAMERA_UI.to_string()),
183183
..Default::default()

examples/2d/contributors.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ fn setup(
5555
let texture_handle = asset_server.load("branding/icon.png");
5656

5757
commands
58-
.spawn(Camera2dBundle::default())
59-
.spawn(CameraUiBundle::default());
58+
.spawn(OrthographicCameraBundle::new_2d())
59+
.spawn(UiCameraBundle::default());
6060

6161
let mut sel = ContributorSelection {
6262
order: vec![],

examples/2d/sprite.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ fn setup(
1414
) {
1515
let texture_handle = asset_server.load("branding/icon.png");
1616
commands
17-
.spawn(Camera2dBundle::default())
17+
.spawn(OrthographicCameraBundle::new_2d())
1818
.spawn(SpriteBundle {
1919
material: materials.add(texture_handle.into()),
2020
..Default::default()

examples/2d/sprite_sheet.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ fn setup(
3131
let texture_atlas = TextureAtlas::from_grid(texture_handle, Vec2::new(24.0, 24.0), 7, 1);
3232
let texture_atlas_handle = texture_atlases.add(texture_atlas);
3333
commands
34-
.spawn(Camera2dBundle::default())
34+
.spawn(OrthographicCameraBundle::new_2d())
3535
.spawn(SpriteSheetBundle {
3636
texture_atlas: texture_atlas_handle,
3737
transform: Transform::from_scale(Vec3::splat(6.0)),

examples/2d/text2d.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ fn main() {
1111
fn setup(commands: &mut Commands, asset_server: Res<AssetServer>) {
1212
commands
1313
// 2d camera
14-
.spawn(Camera2dBundle::default())
14+
.spawn(OrthographicCameraBundle::new_2d())
1515
.spawn(Text2dBundle {
1616
text: Text::with_section(
1717
"This text is in the 2D scene.",

examples/2d/texture_atlas.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ fn setup(
6464

6565
// set up a scene to display our texture atlas
6666
commands
67-
.spawn(Camera2dBundle::default())
67+
.spawn(OrthographicCameraBundle::new_2d())
6868
// draw a sprite from the atlas
6969
.spawn(SpriteSheetBundle {
7070
transform: Transform {

examples/3d/3d_scene.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ fn setup(
3535
..Default::default()
3636
})
3737
// camera
38-
.spawn(Camera3dBundle {
38+
.spawn(PerspectiveCameraBundle {
3939
transform: Transform::from_xyz(-2.0, 2.5, 5.0)
4040
.looking_at(Vec3::default(), Vec3::unit_y()),
4141
..Default::default()

examples/3d/load_gltf.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ fn setup(commands: &mut Commands, asset_server: Res<AssetServer>) {
1515
transform: Transform::from_xyz(4.0, 5.0, 4.0),
1616
..Default::default()
1717
})
18-
.spawn(Camera3dBundle {
18+
.spawn(PerspectiveCameraBundle {
1919
transform: Transform::from_xyz(0.7, 0.7, 1.0)
2020
.looking_at(Vec3::new(0.0, 0.3, 0.0), Vec3::unit_y()),
2121
..Default::default()

0 commit comments

Comments
 (0)