Skip to content

Commit

Permalink
OrthographicProjection scaling mode + camera bundle refactoring (#400)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
inodentry authored Jan 30, 2021
1 parent af67231 commit 57f9ac1
Show file tree
Hide file tree
Showing 41 changed files with 163 additions and 67 deletions.
69 changes: 58 additions & 11 deletions crates/bevy_render/src/camera/projection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,20 @@ pub enum WindowOrigin {
BottomLeft,
}

#[derive(Debug, Clone, Reflect, Serialize, Deserialize)]
#[reflect_value(Serialize, Deserialize)]
pub enum ScalingMode {
/// Manually specify left/right/top/bottom values.
/// Ignore window resizing; the image will stretch.
None,
/// Match the window size. 1 world unit = 1 pixel.
WindowSize,
/// Keep vertical axis constant; resize horizontal with aspect ratio.
FixedVertical,
/// Keep horizontal axis constant; resize vertical with aspect ratio.
FixedHorizontal,
}

#[derive(Debug, Clone, Reflect)]
#[reflect(Component)]
pub struct OrthographicProjection {
Expand All @@ -61,36 +75,67 @@ pub struct OrthographicProjection {
pub near: f32,
pub far: f32,
pub window_origin: WindowOrigin,
pub scaling_mode: ScalingMode,
pub scale: f32,
}

impl CameraProjection for OrthographicProjection {
fn get_projection_matrix(&self) -> Mat4 {
Mat4::orthographic_rh(
self.left,
self.right,
self.bottom,
self.top,
self.left * self.scale,
self.right * self.scale,
self.bottom * self.scale,
self.top * self.scale,
self.near,
self.far,
)
}

fn update(&mut self, width: f32, height: f32) {
match self.window_origin {
WindowOrigin::Center => {
match (&self.scaling_mode, &self.window_origin) {
(ScalingMode::WindowSize, WindowOrigin::Center) => {
let half_width = width / 2.0;
let half_height = height / 2.0;
self.left = -half_width;
self.right = half_width;
self.top = half_height;
self.bottom = -half_height;
}
WindowOrigin::BottomLeft => {
(ScalingMode::WindowSize, WindowOrigin::BottomLeft) => {
self.left = 0.0;
self.right = width;
self.top = height;
self.bottom = 0.0;
}
(ScalingMode::FixedVertical, WindowOrigin::Center) => {
let aspect_ratio = width / height;
self.left = -aspect_ratio;
self.right = aspect_ratio;
self.top = 1.0;
self.bottom = -1.0;
}
(ScalingMode::FixedVertical, WindowOrigin::BottomLeft) => {
let aspect_ratio = width / height;
self.left = 0.0;
self.right = aspect_ratio;
self.top = 1.0;
self.bottom = 0.0;
}
(ScalingMode::FixedHorizontal, WindowOrigin::Center) => {
let aspect_ratio = height / width;
self.left = -1.0;
self.right = 1.0;
self.top = aspect_ratio;
self.bottom = -aspect_ratio;
}
(ScalingMode::FixedHorizontal, WindowOrigin::BottomLeft) => {
let aspect_ratio = height / width;
self.left = 0.0;
self.right = 1.0;
self.top = aspect_ratio;
self.bottom = 0.0;
}
(ScalingMode::None, _) => {}
}
}

Expand All @@ -102,13 +147,15 @@ impl CameraProjection for OrthographicProjection {
impl Default for OrthographicProjection {
fn default() -> Self {
OrthographicProjection {
left: 0.0,
right: 0.0,
bottom: 0.0,
top: 0.0,
left: -1.0,
right: 1.0,
bottom: -1.0,
top: 1.0,
near: 0.0,
far: 1000.0,
window_origin: WindowOrigin::Center,
scaling_mode: ScalingMode::WindowSize,
scale: 1.0,
}
}
}
67 changes: 58 additions & 9 deletions crates/bevy_render/src/entity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,40 @@ pub struct MeshBundle {
pub global_transform: GlobalTransform,
}

/// A component bundle for "3d camera" entities
/// Component bundle for camera entities with perspective projection
///
/// Use this for 3D rendering.
#[derive(Bundle)]
pub struct Camera3dBundle {
pub struct PerspectiveCameraBundle {
pub camera: Camera,
pub perspective_projection: PerspectiveProjection,
pub visible_entities: VisibleEntities,
pub transform: Transform,
pub global_transform: GlobalTransform,
}

impl Default for Camera3dBundle {
impl PerspectiveCameraBundle {
pub fn new_3d() -> Self {
Default::default()
}

pub fn with_name(name: &str) -> Self {
PerspectiveCameraBundle {
camera: Camera {
name: Some(name.to_string()),
..Default::default()
},
perspective_projection: Default::default(),
visible_entities: Default::default(),
transform: Default::default(),
global_transform: Default::default(),
}
}
}

impl Default for PerspectiveCameraBundle {
fn default() -> Self {
Camera3dBundle {
PerspectiveCameraBundle {
camera: Camera {
name: Some(base::camera::CAMERA_3D.to_string()),
..Default::default()
Expand All @@ -47,22 +68,24 @@ impl Default for Camera3dBundle {
}
}

/// A component bundle for "2d camera" entities
/// Component bundle for camera entities with orthographic projection
///
/// Use this for 2D games, isometric games, CAD-like 3D views.
#[derive(Bundle)]
pub struct Camera2dBundle {
pub struct OrthographicCameraBundle {
pub camera: Camera,
pub orthographic_projection: OrthographicProjection,
pub visible_entities: VisibleEntities,
pub transform: Transform,
pub global_transform: GlobalTransform,
}

impl Default for Camera2dBundle {
fn default() -> Self {
impl OrthographicCameraBundle {
pub fn new_2d() -> Self {
// we want 0 to be "closest" and +far to be "farthest" in 2d, so we offset
// the camera's translation by far and use a right handed coordinate system
let far = 1000.0;
Camera2dBundle {
OrthographicCameraBundle {
camera: Camera {
name: Some(base::camera::CAMERA_2D.to_string()),
..Default::default()
Expand All @@ -76,4 +99,30 @@ impl Default for Camera2dBundle {
global_transform: Default::default(),
}
}

pub fn new_3d() -> Self {
OrthographicCameraBundle {
camera: Camera {
name: Some(base::camera::CAMERA_3D.to_string()),
..Default::default()
},
orthographic_projection: Default::default(),
visible_entities: Default::default(),
transform: Default::default(),
global_transform: Default::default(),
}
}

pub fn with_name(name: &str) -> Self {
OrthographicCameraBundle {
camera: Camera {
name: Some(name.to_string()),
..Default::default()
},
orthographic_projection: Default::default(),
visible_entities: Default::default(),
transform: Default::default(),
global_transform: Default::default(),
}
}
}
6 changes: 3 additions & 3 deletions crates/bevy_ui/src/entity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,20 +164,20 @@ impl Default for ButtonBundle {
}

#[derive(Bundle, Debug)]
pub struct CameraUiBundle {
pub struct UiCameraBundle {
pub camera: Camera,
pub orthographic_projection: OrthographicProjection,
pub visible_entities: VisibleEntities,
pub transform: Transform,
pub global_transform: GlobalTransform,
}

impl Default for CameraUiBundle {
impl Default for UiCameraBundle {
fn default() -> Self {
// we want 0 to be "closest" and +far to be "farthest" in 2d, so we offset
// the camera's translation by far and use a right handed coordinate system
let far = 1000.0;
CameraUiBundle {
UiCameraBundle {
camera: Camera {
name: Some(crate::camera::CAMERA_UI.to_string()),
..Default::default()
Expand Down
4 changes: 2 additions & 2 deletions examples/2d/contributors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ fn setup(
let texture_handle = asset_server.load("branding/icon.png");

commands
.spawn(Camera2dBundle::default())
.spawn(CameraUiBundle::default());
.spawn(OrthographicCameraBundle::new_2d())
.spawn(UiCameraBundle::default());

let mut sel = ContributorSelection {
order: vec![],
Expand Down
2 changes: 1 addition & 1 deletion examples/2d/sprite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ fn setup(
) {
let texture_handle = asset_server.load("branding/icon.png");
commands
.spawn(Camera2dBundle::default())
.spawn(OrthographicCameraBundle::new_2d())
.spawn(SpriteBundle {
material: materials.add(texture_handle.into()),
..Default::default()
Expand Down
2 changes: 1 addition & 1 deletion examples/2d/sprite_sheet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ fn setup(
let texture_atlas = TextureAtlas::from_grid(texture_handle, Vec2::new(24.0, 24.0), 7, 1);
let texture_atlas_handle = texture_atlases.add(texture_atlas);
commands
.spawn(Camera2dBundle::default())
.spawn(OrthographicCameraBundle::new_2d())
.spawn(SpriteSheetBundle {
texture_atlas: texture_atlas_handle,
transform: Transform::from_scale(Vec3::splat(6.0)),
Expand Down
2 changes: 1 addition & 1 deletion examples/2d/text2d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ fn main() {
fn setup(commands: &mut Commands, asset_server: Res<AssetServer>) {
commands
// 2d camera
.spawn(Camera2dBundle::default())
.spawn(OrthographicCameraBundle::new_2d())
.spawn(Text2dBundle {
text: Text::with_section(
"This text is in the 2D scene.",
Expand Down
2 changes: 1 addition & 1 deletion examples/2d/texture_atlas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ fn setup(

// set up a scene to display our texture atlas
commands
.spawn(Camera2dBundle::default())
.spawn(OrthographicCameraBundle::new_2d())
// draw a sprite from the atlas
.spawn(SpriteSheetBundle {
transform: Transform {
Expand Down
2 changes: 1 addition & 1 deletion examples/3d/3d_scene.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ fn setup(
..Default::default()
})
// camera
.spawn(Camera3dBundle {
.spawn(PerspectiveCameraBundle {
transform: Transform::from_xyz(-2.0, 2.5, 5.0)
.looking_at(Vec3::default(), Vec3::unit_y()),
..Default::default()
Expand Down
2 changes: 1 addition & 1 deletion examples/3d/load_gltf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ fn setup(commands: &mut Commands, asset_server: Res<AssetServer>) {
transform: Transform::from_xyz(4.0, 5.0, 4.0),
..Default::default()
})
.spawn(Camera3dBundle {
.spawn(PerspectiveCameraBundle {
transform: Transform::from_xyz(0.7, 0.7, 1.0)
.looking_at(Vec3::new(0.0, 0.3, 0.0), Vec3::unit_y()),
..Default::default()
Expand Down
2 changes: 1 addition & 1 deletion examples/3d/msaa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ fn setup(
..Default::default()
})
// camera
.spawn(Camera3dBundle {
.spawn(PerspectiveCameraBundle {
transform: Transform::from_xyz(-3.0, 3.0, 5.0)
.looking_at(Vec3::default(), Vec3::unit_y()),
..Default::default()
Expand Down
2 changes: 1 addition & 1 deletion examples/3d/parenting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ fn setup(
..Default::default()
})
// camera
.spawn(Camera3dBundle {
.spawn(PerspectiveCameraBundle {
transform: Transform::from_xyz(5.0, 10.0, 10.0)
.looking_at(Vec3::default(), Vec3::unit_y()),
..Default::default()
Expand Down
2 changes: 1 addition & 1 deletion examples/3d/spawner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ fn setup(
..Default::default()
})
// camera
.spawn(Camera3dBundle {
.spawn(PerspectiveCameraBundle {
transform: Transform::from_xyz(0.0, 15.0, 150.0)
.looking_at(Vec3::default(), Vec3::unit_y()),
..Default::default()
Expand Down
2 changes: 1 addition & 1 deletion examples/3d/texture.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ fn setup(
..Default::default()
})
// camera
.spawn(Camera3dBundle {
.spawn(PerspectiveCameraBundle {
transform: Transform::from_xyz(3.0, 5.0, 8.0)
.looking_at(Vec3::default(), Vec3::unit_y()),
..Default::default()
Expand Down
2 changes: 1 addition & 1 deletion examples/3d/update_gltf_scene.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ fn setup(
transform: Transform::from_xyz(4.0, 5.0, 4.0),
..Default::default()
})
.spawn(Camera3dBundle {
.spawn(PerspectiveCameraBundle {
transform: Transform::from_xyz(1.05, 0.9, 1.5)
.looking_at(Vec3::new(0.0, 0.3, 0.0), Vec3::unit_y()),
..Default::default()
Expand Down
2 changes: 1 addition & 1 deletion examples/3d/z_sort_debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ fn setup(
});
})
// camera
.spawn(Camera3dBundle {
.spawn(PerspectiveCameraBundle {
transform: Transform::from_xyz(5.0, 10.0, 10.0)
.looking_at(Vec3::default(), Vec3::unit_y()),
..Default::default()
Expand Down
2 changes: 1 addition & 1 deletion examples/android/android.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ fn setup(
..Default::default()
})
// camera
.spawn(Camera3dBundle {
.spawn(PerspectiveCameraBundle {
transform: Transform::from_xyz(-2.0, 2.5, 5.0)
.looking_at(Vec3::default(), Vec3::unit_y()),
..Default::default()
Expand Down
2 changes: 1 addition & 1 deletion examples/asset/asset_loading.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ fn setup(
..Default::default()
})
// camera
.spawn(Camera3dBundle {
.spawn(PerspectiveCameraBundle {
transform: Transform::from_xyz(0.0, 3.0, 10.0)
.looking_at(Vec3::default(), Vec3::unit_y()),
..Default::default()
Expand Down
2 changes: 1 addition & 1 deletion examples/asset/custom_asset_io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ fn setup(
) {
let texture_handle = asset_server.load("branding/icon.png");
commands
.spawn(Camera2dBundle::default())
.spawn(OrthographicCameraBundle::new_2d())
.spawn(SpriteBundle {
material: materials.add(texture_handle.into()),
..Default::default()
Expand Down
Loading

0 comments on commit 57f9ac1

Please sign in to comment.