Skip to content

Commit

Permalink
Migrate cameras to required components (bevyengine#15641)
Browse files Browse the repository at this point in the history
# Objective

Yet another PR for migrating stuff to required components. This time,
cameras!

## Solution

As per the [selected
proposal](https://hackmd.io/tsYID4CGRiWxzsgawzxG_g#Combined-Proposal-1-Selected),
deprecate `Camera2dBundle` and `Camera3dBundle` in favor of `Camera2d`
and `Camera3d`.

Adding a `Camera` without `Camera2d` or `Camera3d` now logs a warning,
as suggested by Cart [on
Discord](https://discord.com/channels/691052431525675048/1264881140007702558/1291506402832945273).
I would personally like cameras to work a bit differently and be split
into a few more components, to avoid some footguns and confusing
semantics, but that is more controversial, and shouldn't block this core
migration.

## Testing

I ran a few 2D and 3D examples, and tried cameras with and without
render graphs.

---

## Migration Guide

`Camera2dBundle` and `Camera3dBundle` have been deprecated in favor of
`Camera2d` and `Camera3d`. Inserting them will now also insert the other
components required by them automatically.
  • Loading branch information
Jondolf authored Oct 5, 2024
1 parent ac9b0c8 commit 25bfa80
Show file tree
Hide file tree
Showing 241 changed files with 870 additions and 969 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ android_shared_stdcxx = ["bevy_internal/android_shared_stdcxx"]
# Enable detailed trace event logging. These trace events are expensive even when off, thus they require compile time opt-in
detailed_trace = ["bevy_internal/detailed_trace"]

# Include tonemapping Look Up Tables KTX2 files. If everything is pink, you need to enable this feature or change the `Tonemapping` method on your `Camera2dBundle` or `Camera3dBundle`.
# Include tonemapping Look Up Tables KTX2 files. If everything is pink, you need to enable this feature or change the `Tonemapping` method for your `Camera2d` or `Camera3d`.
tonemapping_luts = ["bevy_internal/tonemapping_luts", "ktx2", "zstd"]

# Include SMAA Look Up Tables KTX2 Files
Expand Down
15 changes: 15 additions & 0 deletions crates/bevy_core_pipeline/src/core_2d/camera_2d.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![expect(deprecated)]

use crate::{
core_2d::graph::Core2d,
tonemapping::{DebandDither, Tonemapping},
Expand All @@ -17,12 +19,25 @@ use bevy_render::{
};
use bevy_transform::prelude::{GlobalTransform, Transform};

/// A 2D camera component. Enables the 2D render graph for a [`Camera`].
#[derive(Component, Default, Reflect, Clone, ExtractComponent)]
#[extract_component_filter(With<Camera>)]
#[reflect(Component, Default)]
#[require(
Camera,
DebandDither,
CameraRenderGraph(|| CameraRenderGraph::new(Core2d)),
OrthographicProjection(OrthographicProjection::default_2d),
Frustum(|| OrthographicProjection::default_2d().compute_frustum(&GlobalTransform::from(Transform::default()))),
Tonemapping(|| Tonemapping::None),
)]
pub struct Camera2d;

#[derive(Bundle, Clone)]
#[deprecated(
since = "0.15.0",
note = "Use the `Camera2d` component instead. Inserting it will now also insert the other components required by it automatically."
)]
pub struct Camera2dBundle {
pub camera: Camera,
pub camera_render_graph: CameraRenderGraph,
Expand Down
20 changes: 18 additions & 2 deletions crates/bevy_core_pipeline/src/core_3d/camera_3d.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![expect(deprecated)]

use crate::{
core_3d::graph::Core3d,
tonemapping::{DebandDither, Tonemapping},
Expand All @@ -15,12 +17,22 @@ use bevy_render::{
use bevy_transform::prelude::{GlobalTransform, Transform};
use serde::{Deserialize, Serialize};

/// Configuration for the "main 3d render graph".
/// The camera coordinate space is right-handed x-right, y-up, z-back.
/// A 3D camera component. Enables the main 3D render graph for a [`Camera`].
///
/// The camera coordinate space is right-handed X-right, Y-up, Z-back.
/// This means "forward" is -Z.
#[derive(Component, Reflect, Clone, ExtractComponent)]
#[extract_component_filter(With<Camera>)]
#[reflect(Component, Default)]
#[require(
Camera,
DebandDither(|| DebandDither::Enabled),
CameraRenderGraph(|| CameraRenderGraph::new(Core3d)),
Projection,
Tonemapping,
ColorGrading,
Exposure
)]
pub struct Camera3d {
/// The depth clear operation to perform for the main 3d pass.
pub depth_load_op: Camera3dDepthLoadOp,
Expand Down Expand Up @@ -139,6 +151,10 @@ pub enum ScreenSpaceTransmissionQuality {
/// The camera coordinate space is right-handed x-right, y-up, z-back.
/// This means "forward" is -Z.
#[derive(Bundle, Clone)]
#[deprecated(
since = "0.15.0",
note = "Use the `Camera3d` component instead. Inserting it will now also insert the other components required by it automatically."
)]
pub struct Camera3dBundle {
pub camera: Camera,
pub camera_render_graph: CameraRenderGraph,
Expand Down
1 change: 1 addition & 0 deletions crates/bevy_core_pipeline/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ pub mod experimental {
/// The core pipeline prelude.
///
/// This includes the most common types in this crate, re-exported for your convenience.
#[expect(deprecated)]
pub mod prelude {
#[doc(hidden)]
pub use crate::{
Expand Down
4 changes: 2 additions & 2 deletions crates/bevy_core_pipeline/src/motion_blur/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,11 @@ pub struct MotionBlurBundle {
/// camera.
///
/// ```
/// # use bevy_core_pipeline::{core_3d::Camera3dBundle, motion_blur::MotionBlur};
/// # use bevy_core_pipeline::{core_3d::Camera3d, motion_blur::MotionBlur};
/// # use bevy_ecs::prelude::*;
/// # fn test(mut commands: Commands) {
/// commands.spawn((
/// Camera3dBundle::default(),
/// Camera3d::default(),
/// MotionBlur::default(),
/// ));
/// # }
Expand Down
6 changes: 3 additions & 3 deletions crates/bevy_core_pipeline/src/tonemapping/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ impl SpecializedRenderPipeline for TonemappingPipeline {
error!(
"AgX tonemapping requires the `tonemapping_luts` feature.
Either enable the `tonemapping_luts` feature for bevy in `Cargo.toml` (recommended),
or use a different `Tonemapping` method in your `Camera2dBundle`/`Camera3dBundle`."
or use a different `Tonemapping` method for your `Camera2d`/`Camera3d`."
);
shader_defs.push("TONEMAP_METHOD_AGX".into());
}
Expand All @@ -275,7 +275,7 @@ impl SpecializedRenderPipeline for TonemappingPipeline {
error!(
"TonyMcMapFace tonemapping requires the `tonemapping_luts` feature.
Either enable the `tonemapping_luts` feature for bevy in `Cargo.toml` (recommended),
or use a different `Tonemapping` method in your `Camera2dBundle`/`Camera3dBundle`."
or use a different `Tonemapping` method for your `Camera2d`/`Camera3d`."
);
shader_defs.push("TONEMAP_METHOD_TONY_MC_MAPFACE".into());
}
Expand All @@ -284,7 +284,7 @@ impl SpecializedRenderPipeline for TonemappingPipeline {
error!(
"BlenderFilmic tonemapping requires the `tonemapping_luts` feature.
Either enable the `tonemapping_luts` feature for bevy in `Cargo.toml` (recommended),
or use a different `Tonemapping` method in your `Camera2dBundle`/`Camera3dBundle`."
or use a different `Tonemapping` method for your `Camera2d`/`Camera3d`."
);
shader_defs.push("TONEMAP_METHOD_BLENDER_FILMIC".into());
}
Expand Down
22 changes: 10 additions & 12 deletions crates/bevy_dev_tools/src/ui_debug_overlay/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use core::any::{Any, TypeId};
use bevy_app::{App, Plugin, PostUpdate};
use bevy_color::Hsla;
use bevy_core::Name;
use bevy_core_pipeline::core_2d::Camera2dBundle;
use bevy_core_pipeline::core_2d::Camera2d;
use bevy_ecs::{prelude::*, system::SystemParam};
use bevy_gizmos::{config::GizmoConfigStore, prelude::Gizmos, AppGizmoBuilder};
use bevy_hierarchy::{Children, Parent};
Expand Down Expand Up @@ -88,17 +88,15 @@ fn update_debug_camera(
} else {
let spawn_cam = || {
cmds.spawn((
Camera2dBundle {
projection: OrthographicProjection {
far: 1000.0,
viewport_origin: Vec2::new(0.0, 0.0),
..OrthographicProjection::default_3d()
},
camera: Camera {
order: LAYOUT_DEBUG_CAMERA_ORDER,
clear_color: ClearColorConfig::None,
..default()
},
Camera2d,
OrthographicProjection {
far: 1000.0,
viewport_origin: Vec2::new(0.0, 0.0),
..OrthographicProjection::default_3d()
},
Camera {
order: LAYOUT_DEBUG_CAMERA_ORDER,
clear_color: ClearColorConfig::None,
..default()
},
LAYOUT_DEBUG_LAYERS.clone(),
Expand Down
3 changes: 0 additions & 3 deletions crates/bevy_ecs/src/bundle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,6 @@ use core::{any::TypeId, ptr::NonNull};
/// would create incoherent behavior.
/// This would be unexpected if bundles were treated as an abstraction boundary, as
/// the abstraction would be unmaintainable for these cases.
/// For example, both `Camera3dBundle` and `Camera2dBundle` contain the `CameraRenderGraph`
/// component, but specifying different render graphs to use.
/// If the bundles were both added to the same entity, only one of these two bundles would work.
///
/// For this reason, there is intentionally no [`Query`] to match whether an entity
/// contains the components of a bundle.
Expand Down
10 changes: 5 additions & 5 deletions crates/bevy_gltf/src/loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use bevy_asset::{
};
use bevy_color::{Color, LinearRgba};
use bevy_core::Name;
use bevy_core_pipeline::prelude::Camera3dBundle;
use bevy_core_pipeline::prelude::Camera3d;
use bevy_ecs::{
entity::{Entity, EntityHashMap},
world::World,
Expand Down Expand Up @@ -1413,15 +1413,15 @@ fn load_node(
Projection::Perspective(perspective_projection)
}
};
node.insert(Camera3dBundle {
node.insert((
Camera3d::default(),
projection,
transform,
camera: Camera {
Camera {
is_active: !*active_camera_found,
..Default::default()
},
..Default::default()
});
));

*active_camera_found = true;
}
Expand Down
5 changes: 1 addition & 4 deletions crates/bevy_pbr/src/fog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,7 @@ use bevy_render::{extract_component::ExtractComponent, prelude::Camera};
/// # fn system(mut commands: Commands) {
/// commands.spawn((
/// // Setup your camera as usual
/// Camera3dBundle {
/// // ... camera options
/// # ..Default::default()
/// },
/// Camera3d::default(),
/// // Add fog to the same entity
/// DistanceFog {
/// color: Color::WHITE,
Expand Down
35 changes: 29 additions & 6 deletions crates/bevy_render/src/camera/camera.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,29 @@ use crate::{
render_resource::TextureView,
texture::GpuImage,
view::{
ColorGrading, ExtractedView, ExtractedWindows, GpuCulling, RenderLayers, VisibleEntities,
ColorGrading, ExtractedView, ExtractedWindows, GpuCulling, Msaa, RenderLayers, Visibility,
VisibleEntities,
},
world_sync::RenderEntity,
world_sync::{RenderEntity, SyncToRenderWorld},
Extract,
};
use bevy_asset::{AssetEvent, AssetId, Assets, Handle};
use bevy_derive::{Deref, DerefMut};
use bevy_ecs::{
change_detection::DetectChanges,
component::Component,
component::{Component, ComponentId},
entity::Entity,
event::EventReader,
prelude::With,
query::Has,
reflect::ReflectComponent,
system::{Commands, Query, Res, ResMut, Resource},
world::DeferredWorld,
};
use bevy_math::{ops, vec2, Dir3, Mat4, Ray3d, Rect, URect, UVec2, UVec4, Vec2, Vec3};
use bevy_reflect::prelude::*;
use bevy_render_macros::ExtractComponent;
use bevy_transform::components::GlobalTransform;
use bevy_transform::components::{GlobalTransform, Transform};
use bevy_utils::{tracing::warn, warn_once, HashMap, HashSet};
use bevy_window::{
NormalizedWindowRef, PrimaryWindow, Window, WindowCreated, WindowRef, WindowResized,
Expand Down Expand Up @@ -274,10 +276,25 @@ pub enum ViewportConversionError {
/// to transform the 3D objects into a 2D image, as well as the render target into which that image
/// is produced.
///
/// Adding a camera is typically done by adding a bundle, either the `Camera2dBundle` or the
/// `Camera3dBundle`.
/// Note that a [`Camera`] needs a [`CameraRenderGraph`] to render anything.
/// This is typically provided by adding a [`Camera2d`] or [`Camera3d`] component,
/// but custom render graphs can also be defined. Inserting a [`Camera`] with no render
/// graph will emit an error at runtime.
///
/// [`Camera2d`]: https://docs.rs/crate/bevy_core_pipeline/latest/core_2d/struct.Camera2d.html
/// [`Camera3d`]: https://docs.rs/crate/bevy_core_pipeline/latest/core_3d/struct.Camera3d.html
#[derive(Component, Debug, Reflect, Clone)]
#[reflect(Component, Default, Debug)]
#[component(on_add = warn_on_no_render_graph)]
#[require(
Frustum,
CameraMainTextureUsages,
VisibleEntities,
Transform,
Visibility,
Msaa,
SyncToRenderWorld
)]
pub struct Camera {
/// If set, this camera will render to the given [`Viewport`] rectangle within the configured [`RenderTarget`].
pub viewport: Option<Viewport>,
Expand Down Expand Up @@ -309,6 +326,12 @@ pub struct Camera {
pub sub_camera_view: Option<SubCameraView>,
}

fn warn_on_no_render_graph(world: DeferredWorld, entity: Entity, _: ComponentId) {
if !world.entity(entity).contains::<CameraRenderGraph>() {
warn!("Entity {entity} has a `Camera` component, but it doesn't have a render graph configured. Consider adding a `Camera2d` or `Camera3d` component, or manually adding a `CameraRenderGraph` component if you need a custom render graph.");
}
}

impl Default for Camera {
fn default() -> Self {
Self {
Expand Down
3 changes: 1 addition & 2 deletions crates/bevy_render/src/primitives/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,8 +200,7 @@ impl HalfSpace {
/// This process is called frustum culling, and entities can opt out of it using
/// the [`NoFrustumCulling`] component.
///
/// The frustum component is typically added from a bundle, either the `Camera2dBundle`
/// or the `Camera3dBundle`.
/// The frustum component is typically added automatically for cameras, either `Camera2d` or `Camera3d`.
/// It is usually updated automatically by [`update_frusta`] from the
/// [`CameraProjection`] component and [`GlobalTransform`] of the camera entity.
///
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_text/src/text2d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use bevy_transform::prelude::{GlobalTransform, Transform};
use bevy_utils::HashSet;
use bevy_window::{PrimaryWindow, Window, WindowScaleFactorChanged};

/// The bundle of components needed to draw text in a 2D scene via a 2D `Camera2dBundle`.
/// The bundle of components needed to draw text in a 2D scene via a `Camera2d`.
/// [Example usage.](https://github.com/bevyengine/bevy/blob/latest/examples/2d/text2d.rs)
#[derive(Bundle, Clone, Debug, Default)]
pub struct Text2dBundle {
Expand Down
14 changes: 7 additions & 7 deletions crates/bevy_ui/src/layout/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,7 @@ mod tests {
use taffy::TraversePartialTree;

use bevy_asset::{AssetEvent, Assets};
use bevy_core_pipeline::core_2d::Camera2dBundle;
use bevy_core_pipeline::core_2d::Camera2d;
use bevy_ecs::{
entity::Entity,
event::Events,
Expand Down Expand Up @@ -539,7 +539,7 @@ mod tests {
},
PrimaryWindow,
));
world.spawn(Camera2dBundle::default());
world.spawn(Camera2d);

let mut ui_schedule = Schedule::default();
ui_schedule.add_systems(
Expand Down Expand Up @@ -646,7 +646,7 @@ mod tests {
assert!(ui_surface.camera_entity_to_taffy.is_empty());

// respawn camera
let camera_entity = world.spawn(Camera2dBundle::default()).id();
let camera_entity = world.spawn(Camera2d).id();

let ui_entity = world
.spawn((NodeBundle::default(), TargetCamera(camera_entity)))
Expand Down Expand Up @@ -970,13 +970,13 @@ mod tests {

let (mut world, mut ui_schedule) = setup_ui_test_world();

world.spawn(Camera2dBundle {
camera: Camera {
world.spawn((
Camera2d,
Camera {
order: 1,
..default()
},
..default()
});
));

world.spawn((
NodeBundle {
Expand Down
12 changes: 5 additions & 7 deletions crates/bevy_ui/src/ui_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2437,7 +2437,7 @@ impl TargetCamera {
/// # use bevy_ui::prelude::*;
/// # use bevy_ecs::prelude::Commands;
/// # use bevy_render::camera::{Camera, RenderTarget};
/// # use bevy_core_pipeline::prelude::Camera2dBundle;
/// # use bevy_core_pipeline::prelude::Camera2d;
/// # use bevy_window::{Window, WindowRef};
///
/// fn spawn_camera(mut commands: Commands) {
Expand All @@ -2446,11 +2446,9 @@ impl TargetCamera {
/// ..Default::default()
/// }).id();
/// commands.spawn((
/// Camera2dBundle {
/// camera: Camera {
/// target: RenderTarget::Window(WindowRef::Entity(another_window)),
/// ..Default::default()
/// },
/// Camera2d,
/// Camera {
/// target: RenderTarget::Window(WindowRef::Entity(another_window)),
/// ..Default::default()
/// },
/// // We add the Marker here so all Ui will spawn in
Expand Down Expand Up @@ -2502,7 +2500,7 @@ impl<'w, 's> DefaultUiCamera<'w, 's> {
///
/// fn spawn_camera(mut commands: Commands) {
/// commands.spawn((
/// Camera2dBundle::default(),
/// Camera2d,
/// // This will cause all Ui in this camera to be rendered without
/// // anti-aliasing
/// UiAntiAlias::Off,
Expand Down
2 changes: 1 addition & 1 deletion docs/cargo_features.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ The default feature set enables most of the expected features of a game engine,
|png|PNG image format support|
|smaa_luts|Include SMAA Look Up Tables KTX2 Files|
|sysinfo_plugin|Enables system information diagnostic plugin|
|tonemapping_luts|Include tonemapping Look Up Tables KTX2 files. If everything is pink, you need to enable this feature or change the `Tonemapping` method on your `Camera2dBundle` or `Camera3dBundle`.|
|tonemapping_luts|Include tonemapping Look Up Tables KTX2 files. If everything is pink, you need to enable this feature or change the `Tonemapping` method for your `Camera2d` or `Camera3d`.|
|vorbis|OGG/VORBIS audio format support|
|webgl2|Enable some limitations to be able to use WebGL2. Please refer to the [WebGL2 and WebGPU](https://github.com/bevyengine/bevy/tree/latest/examples#webgl2-and-webgpu) section of the examples README for more information on how to run Wasm builds with WebGPU.|
|x11|X11 display server support|
Expand Down
Loading

0 comments on commit 25bfa80

Please sign in to comment.