Split OrthographicProjection::default into 2d & 3d (Adopted) (#15073)

Adopted PR from dmlary, all credit to them!
https://github.com/bevyengine/bevy/pull/9915

Original description:

# Objective

The default value for `near` in `OrthographicProjection` should be
different for 2d & 3d.

For 2d using `near = -1000` allows bevy users to build up scenes using
background `z = 0`, and foreground elements `z > 0` similar to css.
However in 3d `near = -1000` results in objects behind the camera being
rendered. Using `near = 0` works for 3d, but forces 2d users to assign
`z <= 0` for rendered elements, putting the background at some arbitrary
negative value.

There is no common value for `near` that doesn't result in a footgun or
usability issue for either 2d or 3d, so they should have separate
values.

There was discussion about other options in the discord
[0](https://discord.com/channels/691052431525675048/1154114310042292325),
but splitting `default()` into `default_2d()` and `default_3d()` seemed
like the lowest cost approach.

Related/past work https://github.com/bevyengine/bevy/issues/9138,
https://github.com/bevyengine/bevy/pull/9214,
https://github.com/bevyengine/bevy/pull/9310,
https://github.com/bevyengine/bevy/pull/9537 (thanks to @Selene-Amanita
for the list)

## Solution

This commit splits `OrthographicProjection::default` into `default_2d`
and `default_3d`.

## Migration Guide

- In initialization of `OrthographicProjection`, change `..default()` to
`..OrthographicProjection::default_2d()` or
`..OrthographicProjection::default_3d()`

Example:
```diff
--- a/examples/3d/orthographic.rs
+++ b/examples/3d/orthographic.rs
@@ -20,7 +20,7 @@ fn setup(
         projection: OrthographicProjection {
             scale: 3.0,
             scaling_mode: ScalingMode::FixedVertical(2.0),
-            ..default()
+            ..OrthographicProjection::default_3d()
         }
         .into(),
         transform: Transform::from_xyz(5.0, 5.0, 5.0).looking_at(Vec3::ZERO, Vec3::Y),
```

---------

Co-authored-by: David M. Lary <dmlary@gmail.com>
Co-authored-by: Jan Hohenheim <jan@hohenheim.ch>
This commit is contained in:
Alix Bott 2024-09-09 17:51:28 +02:00 committed by GitHub
parent 8460cfa6ab
commit 82e416dc48
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 33 additions and 20 deletions

View file

@ -23,10 +23,6 @@ pub struct Camera2d;
pub struct Camera2dBundle {
pub camera: Camera,
pub camera_render_graph: CameraRenderGraph,
/// Note: default value for `OrthographicProjection.near` is `0.0`
/// which makes objects on the screen plane invisible to 2D camera.
/// `Camera2dBundle::default()` sets `near` to negative value,
/// so be careful when initializing this field manually.
pub projection: OrthographicProjection,
pub visible_entities: VisibleEntities,
pub frustum: Frustum,
@ -41,11 +37,7 @@ pub struct Camera2dBundle {
impl Default for Camera2dBundle {
fn default() -> Self {
let projection = OrthographicProjection {
far: 1000.,
near: -1000.,
..Default::default()
};
let projection = OrthographicProjection::default_2d();
let transform = Transform::default();
let frustum = projection.compute_frustum(&GlobalTransform::from(transform));
Self {
@ -77,7 +69,7 @@ impl Camera2dBundle {
// the camera's translation by far and use a right handed coordinate system
let projection = OrthographicProjection {
far,
..Default::default()
..OrthographicProjection::default_2d()
};
let transform = Transform::from_xyz(0.0, 0.0, far - 0.1);
let frustum = projection.compute_frustum(&GlobalTransform::from(transform));

View file

@ -92,7 +92,7 @@ fn update_debug_camera(
projection: OrthographicProjection {
far: 1000.0,
viewport_origin: Vec2::new(0.0, 0.0),
..default()
..OrthographicProjection::default_3d()
},
camera: Camera {
order: LAYOUT_DEBUG_CAMERA_ORDER,

View file

@ -1256,7 +1256,7 @@ fn load_node(
far: orthographic.zfar(),
scaling_mode: ScalingMode::FixedHorizontal(1.0),
scale: xmag,
..Default::default()
..OrthographicProjection::default_3d()
};
Projection::Orthographic(orthographic_projection)

View file

@ -237,7 +237,7 @@ impl Default for PerspectiveProjection {
/// # use bevy_render::camera::{OrthographicProjection, Projection, ScalingMode};
/// let projection = Projection::Orthographic(OrthographicProjection {
/// scaling_mode: ScalingMode::FixedVertical(2.0),
/// ..OrthographicProjection::default()
/// ..OrthographicProjection::default_2d()
/// });
/// ```
#[derive(Debug, Clone, Copy, Reflect, Serialize, Deserialize)]
@ -334,11 +334,11 @@ impl DivAssign<f32> for ScalingMode {
/// # use bevy_render::camera::{OrthographicProjection, Projection, ScalingMode};
/// let projection = Projection::Orthographic(OrthographicProjection {
/// scaling_mode: ScalingMode::WindowSize(100.0),
/// ..OrthographicProjection::default()
/// ..OrthographicProjection::default_2d()
/// });
/// ```
#[derive(Component, Debug, Clone, Reflect)]
#[reflect(Component, Default)]
#[reflect(Component)]
pub struct OrthographicProjection {
/// The distance of the near clipping plane in world units.
///
@ -479,8 +479,29 @@ impl CameraProjection for OrthographicProjection {
}
}
impl Default for OrthographicProjection {
fn default() -> Self {
impl FromWorld for OrthographicProjection {
fn from_world(_world: &mut World) -> Self {
OrthographicProjection::default_3d()
}
}
impl OrthographicProjection {
/// Returns the default orthographic projection for a 2D context.
///
/// The near plane is set to a negative value so that the camera can still
/// render the scene when using positive z coordinates to order foreground elements.
pub fn default_2d() -> Self {
OrthographicProjection {
near: -1000.0,
..OrthographicProjection::default_3d()
}
}
/// Returns the default orthographic projection for a 3D context.
///
/// The near plane is set to 0.0 so that the camera doesn't render
/// objects that are behind it.
pub fn default_3d() -> Self {
OrthographicProjection {
scale: 1.0,
near: 0.0,

View file

@ -20,7 +20,7 @@ fn setup(
projection: OrthographicProjection {
// 6 world units per window height.
scaling_mode: ScalingMode::FixedVertical(6.0),
..default()
..OrthographicProjection::default_3d()
}
.into(),
transform: Transform::from_xyz(5.0, 5.0, 5.0).looking_at(Vec3::ZERO, Vec3::Y),

View file

@ -121,7 +121,7 @@ fn setup(
transform: Transform::from_xyz(0.0, 0.0, 8.0).looking_at(Vec3::default(), Vec3::Y),
projection: OrthographicProjection {
scale: 0.01,
..default()
..OrthographicProjection::default_3d()
}
.into(),
..default()

View file

@ -96,7 +96,7 @@ fn setup(
projection: OrthographicProjection {
scale: 20.0,
scaling_mode: ScalingMode::FixedHorizontal(1.0),
..default()
..OrthographicProjection::default_3d()
}
.into(),
..default()