Skip to content

Commit

Permalink
Add Viewport component to the camera bundles
Browse files Browse the repository at this point in the history
Cameras are now decoupled from Windows, but automatic viewport resizing
isn't implemented yet.
  • Loading branch information
rmsc committed Feb 6, 2021
1 parent 3475a64 commit 87df397
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 54 deletions.
62 changes: 14 additions & 48 deletions crates/bevy_render/src/camera/camera.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
use super::CameraProjection;
use bevy_app::prelude::EventReader;
use bevy_ecs::{Added, Component, Entity, Query, QuerySet, Res};
use super::{CameraProjection, Viewport};
use bevy_ecs::{Changed, Component, Query};
use bevy_math::{Mat4, Vec2, Vec3};
use bevy_reflect::{Reflect, ReflectComponent, ReflectDeserialize};
use bevy_transform::components::GlobalTransform;
use bevy_window::{WindowCreated, WindowId, WindowResized, Windows};
use serde::{Deserialize, Serialize};

#[derive(Default, Debug, Reflect)]
Expand All @@ -13,8 +11,6 @@ pub struct Camera {
pub projection_matrix: Mat4,
pub name: Option<String>,
#[reflect(ignore)]
pub window: WindowId,
#[reflect(ignore)]
pub depth_calculation: DepthCalculation,
}

Expand All @@ -37,12 +33,10 @@ impl Camera {
/// Given a position in world space, use the camera to compute the screen space coordinates.
pub fn world_to_screen(
&self,
windows: &Windows,
viewport: &Viewport,
camera_transform: &GlobalTransform,
world_position: Vec3,
) -> Option<Vec2> {
let window = windows.get(self.window)?;
let window_size = Vec2::new(window.width(), window.height());
// Build a transform to convert from world to NDC using camera data
let world_to_ndc: Mat4 =
self.projection_matrix * camera_transform.compute_matrix().inverse();
Expand All @@ -52,50 +46,22 @@ impl Camera {
return None;
}
// Once in NDC space, we can discard the z element and rescale x/y to fit the screen
let screen_space_coords = (ndc_space_coords.truncate() + Vec2::one()) / 2.0 * window_size;
let screen_space_coords =
viewport.origin + (ndc_space_coords.truncate() + Vec2::one()) / 2.0 * viewport.size;
Some(screen_space_coords)
}
}

pub fn camera_system<T: CameraProjection + Component>(
mut window_resized_events: EventReader<WindowResized>,
mut window_created_events: EventReader<WindowCreated>,
windows: Res<Windows>,
mut queries: QuerySet<(
Query<(Entity, &mut Camera, &mut T)>,
Query<Entity, Added<Camera>>,
)>,
mut query: Query<(&mut Camera, &mut T, &Viewport), Changed<Viewport>>,
) {
let mut changed_window_ids = Vec::new();
// handle resize events. latest events are handled first because we only want to resize each window once
for event in window_resized_events.iter().rev() {
if changed_window_ids.contains(&event.id) {
continue;
}

changed_window_ids.push(event.id);
}

// handle resize events. latest events are handled first because we only want to resize each window once
for event in window_created_events.iter().rev() {
if changed_window_ids.contains(&event.id) {
continue;
}

changed_window_ids.push(event.id);
}

let mut added_cameras = vec![];
for entity in &mut queries.q1().iter() {
added_cameras.push(entity);
}
for (entity, mut camera, mut camera_projection) in queries.q0_mut().iter_mut() {
if let Some(window) = windows.get(camera.window) {
if changed_window_ids.contains(&window.id()) || added_cameras.contains(&entity) {
camera_projection.update(window.width(), window.height());
camera.projection_matrix = camera_projection.get_projection_matrix();
camera.depth_calculation = camera_projection.depth_calculation();
}
}
for (mut camera, mut camera_projection, viewport) in query.iter_mut() {
println!(
"updating camera {:?}, vp {}x{} at {}x{}",
camera.name, viewport.size.x, viewport.size.y, viewport.origin.x, viewport.origin.y
);
camera_projection.update(viewport.size.x, viewport.size.y);
camera.projection_matrix = camera_projection.get_projection_matrix();
camera.depth_calculation = camera_projection.depth_calculation();
}
}
2 changes: 2 additions & 0 deletions crates/bevy_render/src/camera/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ mod active_cameras;
#[allow(clippy::module_inception)]
mod camera;
mod projection;
mod viewport;
mod visible_entities;

pub use active_cameras::*;
pub use camera::*;
pub use projection::*;
pub use viewport::*;
pub use visible_entities::*;
22 changes: 22 additions & 0 deletions crates/bevy_render/src/camera/viewport.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use bevy_math::Vec2;
use bevy_reflect::{Reflect, ReflectComponent};

#[derive(Debug, PartialEq, Clone, Reflect)]
#[reflect(Component)]
pub struct Viewport {
pub name: Option<String>,
pub origin: Vec2,
pub size: Vec2,
pub scale_factor: f64,
}

impl Default for Viewport {
fn default() -> Self {
Self {
name: None,
origin: Vec2::zero(),
size: Vec2::one(),
scale_factor: 1.0,
}
}
}
9 changes: 8 additions & 1 deletion crates/bevy_render/src/entity.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::{
camera::{
Camera, DepthCalculation, OrthographicProjection, PerspectiveProjection, ScalingMode,
VisibleEntities,
Viewport, VisibleEntities,
},
pipeline::RenderPipelines,
prelude::Visible,
Expand Down Expand Up @@ -32,6 +32,7 @@ pub struct MeshBundle {
pub struct PerspectiveCameraBundle {
pub camera: Camera,
pub perspective_projection: PerspectiveProjection,
pub viewport: Viewport,
pub visible_entities: VisibleEntities,
pub transform: Transform,
pub global_transform: GlobalTransform,
Expand All @@ -49,6 +50,7 @@ impl PerspectiveCameraBundle {
..Default::default()
},
perspective_projection: Default::default(),
viewport: Default::default(),
visible_entities: Default::default(),
transform: Default::default(),
global_transform: Default::default(),
Expand All @@ -64,6 +66,7 @@ impl Default for PerspectiveCameraBundle {
..Default::default()
},
perspective_projection: Default::default(),
viewport: Default::default(),
visible_entities: Default::default(),
transform: Default::default(),
global_transform: Default::default(),
Expand All @@ -78,6 +81,7 @@ impl Default for PerspectiveCameraBundle {
pub struct OrthographicCameraBundle {
pub camera: Camera,
pub orthographic_projection: OrthographicProjection,
pub viewport: Viewport,
pub visible_entities: VisibleEntities,
pub transform: Transform,
pub global_transform: GlobalTransform,
Expand All @@ -98,6 +102,7 @@ impl OrthographicCameraBundle {
depth_calculation: DepthCalculation::ZDifference,
..Default::default()
},
viewport: Default::default(),
visible_entities: Default::default(),
transform: Transform::from_xyz(0.0, 0.0, far - 0.1),
global_transform: Default::default(),
Expand All @@ -115,6 +120,7 @@ impl OrthographicCameraBundle {
depth_calculation: DepthCalculation::Distance,
..Default::default()
},
viewport: Default::default(),
visible_entities: Default::default(),
transform: Default::default(),
global_transform: Default::default(),
Expand All @@ -128,6 +134,7 @@ impl OrthographicCameraBundle {
..Default::default()
},
orthographic_projection: Default::default(),
viewport: Default::default(),
visible_entities: Default::default(),
transform: Default::default(),
global_transform: Default::default(),
Expand Down
21 changes: 17 additions & 4 deletions crates/bevy_render/src/render_graph/nodes/pass_node.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{
camera::{ActiveCameras, VisibleEntities},
camera::{ActiveCameras, Viewport, VisibleEntities},
draw::{Draw, RenderCommand},
pass::{ClearColor, LoadOp, PassDescriptor, TextureAttachment},
pipeline::{
Expand Down Expand Up @@ -216,13 +216,26 @@ where
continue;
};

// get an ordered list of entities visible to the camera
let visible_entities = if let Some(camera_entity) = active_cameras.get(&camera_info.name) {
world.get::<VisibleEntities>(camera_entity).unwrap()
let camera_entity = if let Some(camera_entity) = active_cameras.get(&camera_info.name) {
camera_entity
} else {
continue;
};

// get an ordered list of entities visible to the camera
let visible_entities = world.get::<VisibleEntities>(camera_entity).unwrap();

// get camera viewport and apply it
let viewport = world.get::<Viewport>(camera_entity).unwrap();
render_pass.set_viewport(
viewport.origin.x,
viewport.origin.y,
viewport.size.x,
viewport.size.y,
// TODO: implement min/max depth
0.0, 1.0,
);

// attempt to draw each visible entity
let mut draw_state = DrawState::default();
for visible_entity in visible_entities.iter() {
Expand Down
6 changes: 5 additions & 1 deletion crates/bevy_ui/src/entity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ use crate::{
use bevy_asset::Handle;
use bevy_ecs::Bundle;
use bevy_render::{
camera::{Camera, DepthCalculation, OrthographicProjection, VisibleEntities, WindowOrigin},
camera::{
Camera, DepthCalculation, OrthographicProjection, Viewport, VisibleEntities, WindowOrigin,
},
draw::Draw,
mesh::Mesh,
pipeline::{RenderPipeline, RenderPipelines},
Expand Down Expand Up @@ -167,6 +169,7 @@ impl Default for ButtonBundle {
pub struct UiCameraBundle {
pub camera: Camera,
pub orthographic_projection: OrthographicProjection,
pub viewport: Viewport,
pub visible_entities: VisibleEntities,
pub transform: Transform,
pub global_transform: GlobalTransform,
Expand All @@ -189,6 +192,7 @@ impl Default for UiCameraBundle {
..Default::default()
},
visible_entities: Default::default(),
viewport: Default::default(),
transform: Transform::from_xyz(0.0, 0.0, far - 0.1),
global_transform: Default::default(),
}
Expand Down

0 comments on commit 87df397

Please sign in to comment.