Skip to content

Commit

Permalink
use marker components for cameras instead of name strings (#3635)
Browse files Browse the repository at this point in the history
**Problem**
- whenever you want more than one of the builtin cameras (for example multiple windows, split screen, portals), you need to add a render graph node that executes the correct sub graph, extract the camera into the render world and add the correct `RenderPhase<T>` components
- querying for the 3d camera is annoying because you need to compare the camera's name to e.g. `CameraPlugin::CAMERA_3d`

**Solution**
- Introduce the marker types `Camera3d`, `Camera2d` and `CameraUi`
-> `Query<&mut Transform, With<Camera3d>>` works
- `PerspectiveCameraBundle::new_3d()` and `PerspectiveCameraBundle::<Camera3d>::default()` contain the `Camera3d` marker
- `OrthographicCameraBundle::new_3d()` has `Camera3d`, `OrthographicCameraBundle::new_2d()` has `Camera2d`
- remove `ActiveCameras`, `ExtractedCameraNames`
- run 2d, 3d and ui passes for every camera of their respective marker
-> no custom setup for multiple windows example needed

**Open questions**
- do we need a replacement for `ActiveCameras`? What about a component `ActiveCamera { is_active: bool }` similar to `Visibility`?

Co-authored-by: Carter Anderson <[email protected]>
  • Loading branch information
jakobhellermann and cart committed Mar 12, 2022
1 parent 0e821da commit bf6de89
Show file tree
Hide file tree
Showing 16 changed files with 289 additions and 392 deletions.
31 changes: 14 additions & 17 deletions crates/bevy_core_pipeline/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use bevy_app::{App, Plugin};
use bevy_core::FloatOrd;
use bevy_ecs::prelude::*;
use bevy_render::{
camera::{ActiveCameras, CameraPlugin, RenderTarget},
camera::{ActiveCamera, Camera2d, Camera3d, RenderTarget},
color::Color,
render_graph::{EmptyNode, RenderGraph, SlotInfo, SlotType},
render_phase::{
Expand Down Expand Up @@ -367,23 +367,20 @@ pub fn extract_clear_color(

pub fn extract_core_pipeline_camera_phases(
mut commands: Commands,
active_cameras: Res<ActiveCameras>,
active_2d: Res<ActiveCamera<Camera2d>>,
active_3d: Res<ActiveCamera<Camera3d>>,
) {
if let Some(camera_2d) = active_cameras.get(CameraPlugin::CAMERA_2D) {
if let Some(entity) = camera_2d.entity {
commands
.get_or_spawn(entity)
.insert(RenderPhase::<Transparent2d>::default());
}
}
if let Some(camera_3d) = active_cameras.get(CameraPlugin::CAMERA_3D) {
if let Some(entity) = camera_3d.entity {
commands.get_or_spawn(entity).insert_bundle((
RenderPhase::<Opaque3d>::default(),
RenderPhase::<AlphaMask3d>::default(),
RenderPhase::<Transparent3d>::default(),
));
}
if let Some(entity) = active_2d.get() {
commands
.get_or_spawn(entity)
.insert(RenderPhase::<Transparent2d>::default());
}
if let Some(entity) = active_3d.get() {
commands.get_or_spawn(entity).insert_bundle((
RenderPhase::<Opaque3d>::default(),
RenderPhase::<AlphaMask3d>::default(),
RenderPhase::<Transparent3d>::default(),
));
}
}

Expand Down
11 changes: 5 additions & 6 deletions crates/bevy_core_pipeline/src/main_pass_driver.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use bevy_ecs::world::World;
use bevy_render::{
camera::{CameraPlugin, ExtractedCameraNames},
camera::{ActiveCamera, Camera2d, Camera3d},
render_graph::{Node, NodeRunError, RenderGraphContext, SlotValue},
renderer::RenderContext,
};
Expand All @@ -14,18 +14,17 @@ impl Node for MainPassDriverNode {
_render_context: &mut RenderContext,
world: &World,
) -> Result<(), NodeRunError> {
let extracted_cameras = world.resource::<ExtractedCameraNames>();
if let Some(camera_2d) = extracted_cameras.entities.get(CameraPlugin::CAMERA_2D) {
if let Some(camera_2d) = world.resource::<ActiveCamera<Camera2d>>().get() {
graph.run_sub_graph(
crate::draw_2d_graph::NAME,
vec![SlotValue::Entity(*camera_2d)],
vec![SlotValue::Entity(camera_2d)],
)?;
}

if let Some(camera_3d) = extracted_cameras.entities.get(CameraPlugin::CAMERA_3D) {
if let Some(camera_3d) = world.resource::<ActiveCamera<Camera3d>>().get() {
graph.run_sub_graph(
crate::draw_3d_graph::NAME,
vec![SlotValue::Entity(*camera_3d)],
vec![SlotValue::Entity(camera_3d)],
)?;
}

Expand Down
7 changes: 3 additions & 4 deletions crates/bevy_gltf/src/loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use bevy_pbr::{
};
use bevy_render::{
camera::{
Camera, CameraPlugin, CameraProjection, OrthographicProjection, PerspectiveProjection,
Camera, Camera2d, Camera3d, CameraProjection, OrthographicProjection, PerspectiveProjection,
},
color::Color,
mesh::{Indices, Mesh, VertexAttributeValues},
Expand Down Expand Up @@ -494,11 +494,10 @@ fn load_node(
};

node.insert(Camera {
name: Some(CameraPlugin::CAMERA_2D.to_owned()),
projection_matrix: orthographic_projection.get_projection_matrix(),
..Default::default()
});
node.insert(orthographic_projection);
node.insert(orthographic_projection).insert(Camera2d);
}
gltf::camera::Projection::Perspective(perspective) => {
let mut perspective_projection: PerspectiveProjection = PerspectiveProjection {
Expand All @@ -513,13 +512,13 @@ fn load_node(
perspective_projection.aspect_ratio = aspect_ratio;
}
node.insert(Camera {
name: Some(CameraPlugin::CAMERA_3D.to_owned()),
projection_matrix: perspective_projection.get_projection_matrix(),
near: perspective_projection.near,
far: perspective_projection.far,
..Default::default()
});
node.insert(perspective_projection);
node.insert(Camera3d);
}
}
}
Expand Down
73 changes: 0 additions & 73 deletions crates/bevy_render/src/camera/active_cameras.rs

This file was deleted.

129 changes: 57 additions & 72 deletions crates/bevy_render/src/camera/bundle.rs
Original file line number Diff line number Diff line change
@@ -1,36 +1,48 @@
use crate::{
camera::{
Camera, CameraPlugin, DepthCalculation, OrthographicProjection, PerspectiveProjection,
ScalingMode,
},
camera::{Camera, DepthCalculation, OrthographicProjection, PerspectiveProjection},
primitives::Frustum,
view::VisibleEntities,
};
use bevy_ecs::bundle::Bundle;
use bevy_ecs::{bundle::Bundle, prelude::Component};
use bevy_math::Vec3;
use bevy_transform::components::{GlobalTransform, Transform};

use super::CameraProjection;
use super::{CameraProjection, ScalingMode};

#[derive(Component, Default)]
pub struct Camera3d;

#[derive(Component, Default)]
pub struct Camera2d;

/// Component bundle for camera entities with perspective projection
///
/// Use this for 3D rendering.
#[derive(Bundle)]
pub struct PerspectiveCameraBundle {
pub struct PerspectiveCameraBundle<M: Component> {
pub camera: Camera,
pub perspective_projection: PerspectiveProjection,
pub visible_entities: VisibleEntities,
pub frustum: Frustum,
pub transform: Transform,
pub global_transform: GlobalTransform,
pub marker: M,
}

impl Default for PerspectiveCameraBundle<Camera3d> {
fn default() -> Self {
PerspectiveCameraBundle::new_3d()
}
}

impl PerspectiveCameraBundle {
impl PerspectiveCameraBundle<Camera3d> {
pub fn new_3d() -> Self {
Default::default()
PerspectiveCameraBundle::new()
}
}

pub fn with_name(name: &str) -> Self {
impl<M: Component + Default> PerspectiveCameraBundle<M> {
pub fn new() -> Self {
let perspective_projection = PerspectiveProjection::default();
let view_projection = perspective_projection.get_projection_matrix();
let frustum = Frustum::from_view_projection(
Expand All @@ -41,7 +53,6 @@ impl PerspectiveCameraBundle {
);
PerspectiveCameraBundle {
camera: Camera {
name: Some(name.to_string()),
near: perspective_projection.near,
far: perspective_projection.far,
..Default::default()
Expand All @@ -51,30 +62,56 @@ impl PerspectiveCameraBundle {
frustum,
transform: Default::default(),
global_transform: Default::default(),
marker: M::default(),
}
}
}

impl Default for PerspectiveCameraBundle {
fn default() -> Self {
PerspectiveCameraBundle::with_name(CameraPlugin::CAMERA_3D)
}
}

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

impl OrthographicCameraBundle<Camera3d> {
pub fn new_3d() -> Self {
let orthographic_projection = OrthographicProjection {
scaling_mode: ScalingMode::FixedVertical,
depth_calculation: DepthCalculation::Distance,
..Default::default()
};
let view_projection = orthographic_projection.get_projection_matrix();
let frustum = Frustum::from_view_projection(
&view_projection,
&Vec3::ZERO,
&Vec3::Z,
orthographic_projection.far(),
);
OrthographicCameraBundle {
camera: Camera {
near: orthographic_projection.near,
far: orthographic_projection.far,
..Default::default()
},
orthographic_projection,
visible_entities: VisibleEntities::default(),
frustum,
transform: Default::default(),
global_transform: Default::default(),
marker: Camera3d,
}
}
}

impl OrthographicCameraBundle {
impl OrthographicCameraBundle<Camera2d> {
/// Create an orthographic projection camera to render 2D content.
///
/// The projection creates a camera space where X points to the right of the screen,
Expand Down Expand Up @@ -112,7 +149,6 @@ impl OrthographicCameraBundle {
);
OrthographicCameraBundle {
camera: Camera {
name: Some(CameraPlugin::CAMERA_2D.to_string()),
near: orthographic_projection.near,
far: orthographic_projection.far,
..Default::default()
Expand All @@ -122,58 +158,7 @@ impl OrthographicCameraBundle {
frustum,
transform,
global_transform: Default::default(),
}
}

pub fn new_3d() -> Self {
let orthographic_projection = OrthographicProjection {
scaling_mode: ScalingMode::FixedVertical,
depth_calculation: DepthCalculation::Distance,
..Default::default()
};
let view_projection = orthographic_projection.get_projection_matrix();
let frustum = Frustum::from_view_projection(
&view_projection,
&Vec3::ZERO,
&Vec3::Z,
orthographic_projection.far(),
);
OrthographicCameraBundle {
camera: Camera {
name: Some(CameraPlugin::CAMERA_3D.to_string()),
near: orthographic_projection.near,
far: orthographic_projection.far,
..Default::default()
},
orthographic_projection,
visible_entities: VisibleEntities::default(),
frustum,
transform: Default::default(),
global_transform: Default::default(),
}
}

pub fn with_name(name: &str) -> Self {
let orthographic_projection = OrthographicProjection::default();
let view_projection = orthographic_projection.get_projection_matrix();
let frustum = Frustum::from_view_projection(
&view_projection,
&Vec3::ZERO,
&Vec3::Z,
orthographic_projection.far(),
);
OrthographicCameraBundle {
camera: Camera {
name: Some(name.to_string()),
near: orthographic_projection.near,
far: orthographic_projection.far,
..Default::default()
},
orthographic_projection,
visible_entities: VisibleEntities::default(),
frustum,
transform: Default::default(),
global_transform: Default::default(),
marker: Camera2d,
}
}
}
Loading

0 comments on commit bf6de89

Please sign in to comment.