Skip to content

Commit

Permalink
Add CameraTarget
Browse files Browse the repository at this point in the history
  • Loading branch information
HackerFoo committed Dec 21, 2021
1 parent c04dfc1 commit e814a8a
Show file tree
Hide file tree
Showing 6 changed files with 144 additions and 73 deletions.
4 changes: 2 additions & 2 deletions crates/bevy_core_pipeline/src/clear_pass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ impl Node for ClearPassNode {
// are multiple views drawing to the same target. This should be fixed when we make
// clearing happen on "render targets" instead of "views" (see the TODO below for more context).
for (target, depth, camera) in self.query.iter_manual(world) {
if let Some(camera) = camera {
cleared_windows.insert(camera.window_id);
if let Some(window_id) = camera.and_then(|camera| camera.get_window()) {
cleared_windows.insert(window_id);
}
let pass_descriptor = RenderPassDescriptor {
label: Some("clear_pass"),
Expand Down
22 changes: 12 additions & 10 deletions crates/bevy_pbr/src/light.rs
Original file line number Diff line number Diff line change
Expand Up @@ -341,23 +341,25 @@ pub fn add_clusters(
cameras: Query<(Entity, &Camera), Without<Clusters>>,
) {
for (entity, camera) in cameras.iter() {
let window = match windows.get(camera.window) {
Some(window) => window,
None => continue,
};
let clusters = Clusters::from_screen_size_and_z_slices(
UVec2::new(window.physical_width(), window.physical_height()),
Z_SLICES,
);
commands.entity(entity).insert(clusters);
if let Some(window_id) = camera.get_window() {
let window = match windows.get(window_id) {
Some(window) => window,
None => continue,
};
let clusters = Clusters::from_screen_size_and_z_slices(
UVec2::new(window.physical_width(), window.physical_height()),
Z_SLICES,
);
commands.entity(entity).insert(clusters);
}
}
}

pub fn update_clusters(windows: Res<Windows>, mut views: Query<(&Camera, &mut Clusters)>) {
for (camera, mut clusters) in views.iter_mut() {
let is_orthographic = camera.projection_matrix.w_axis.w == 1.0;
let inverse_projection = camera.projection_matrix.inverse();
let window = windows.get(camera.window).unwrap();
let window = windows.get(camera.get_window().unwrap()).unwrap();
let screen_size_u32 = UVec2::new(window.physical_width(), window.physical_height());
// Don't update clusters if screen size is 0.
if screen_size_u32.x == 0 || screen_size_u32.y == 0 {
Expand Down
30 changes: 26 additions & 4 deletions crates/bevy_render/src/camera/camera.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::camera::CameraProjection;
use crate::{camera::CameraProjection, prelude::Image};
use bevy_asset::Handle;
use bevy_ecs::{
component::Component,
entity::Entity,
Expand All @@ -20,13 +21,27 @@ pub struct Camera {
pub projection_matrix: Mat4,
pub name: Option<String>,
#[reflect(ignore)]
pub window: WindowId,
pub target: CameraTarget,
#[reflect(ignore)]
pub depth_calculation: DepthCalculation,
pub near: f32,
pub far: f32,
}

#[derive(Debug, Clone, Reflect)]
pub enum CameraTarget {
/// Window to which the camera's view is rendered.
Window(WindowId),
/// Image to which the camera's view is rendered.
Image(Handle<Image>),
}

impl Default for CameraTarget {
fn default() -> Self {
Self::Window(Default::default())
}
}

#[derive(Debug, Clone, Copy, Reflect, Serialize, Deserialize)]
#[reflect_value(Serialize, Deserialize)]
pub enum DepthCalculation {
Expand All @@ -43,14 +58,21 @@ impl Default for DepthCalculation {
}

impl Camera {
pub fn get_window(&self) -> Option<WindowId> {
if let CameraTarget::Window(window) = self.target {
Some(window)
} else {
None
}
}
/// Given a position in world space, use the camera to compute the screen space coordinates.
pub fn world_to_screen(
&self,
windows: &Windows,
camera_transform: &GlobalTransform,
world_position: Vec3,
) -> Option<Vec2> {
let window = windows.get(self.window)?;
let window = self.get_window().and_then(|window| windows.get(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 =
Expand Down Expand Up @@ -106,7 +128,7 @@ pub fn camera_system<T: CameraProjection + Component>(
added_cameras.push(entity);
}
for (entity, mut camera, mut camera_projection) in queries.q0().iter_mut() {
if let Some(window) = windows.get(camera.window) {
if let Some(window) = camera.get_window().and_then(|window| windows.get(window)) {
if changed_window_ids.contains(&window.id())
|| added_cameras.contains(&entity)
|| camera_projection.is_changed()
Expand Down
67 changes: 48 additions & 19 deletions crates/bevy_render/src/camera/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,17 @@ mod camera;
mod projection;

pub use active_cameras::*;
use bevy_asset::Assets;
use bevy_transform::components::GlobalTransform;
use bevy_utils::HashMap;
use bevy_window::{WindowId, Windows};
pub use bundle::*;
pub use camera::*;
pub use projection::*;
use wgpu::Extent3d;

use crate::{
prelude::Image,
primitives::Aabb,
view::{ComputedVisibility, ExtractedView, Visibility, VisibleEntities},
RenderApp, RenderStage,
Expand Down Expand Up @@ -66,14 +69,25 @@ pub struct ExtractedCameraNames {

#[derive(Component, Debug)]
pub struct ExtractedCamera {
pub window_id: WindowId,
pub target: CameraTarget,
pub name: Option<String>,
}

impl ExtractedCamera {
pub fn get_window(&self) -> Option<WindowId> {
if let CameraTarget::Window(window) = self.target {
Some(window)
} else {
None
}
}
}

fn extract_cameras(
mut commands: Commands,
active_cameras: Res<ActiveCameras>,
windows: Res<Windows>,
images: Res<Assets<Image>>,
query: Query<(Entity, &Camera, &GlobalTransform, &VisibleEntities)>,
) {
let mut entities = HashMap::default();
Expand All @@ -82,24 +96,39 @@ fn extract_cameras(
if let Some((entity, camera, transform, visible_entities)) =
camera.entity.and_then(|e| query.get(e).ok())
{
if let Some(window) = windows.get(camera.window) {
entities.insert(name.clone(), entity);
commands.get_or_spawn(entity).insert_bundle((
ExtractedCamera {
window_id: camera.window,
name: camera.name.clone(),
},
ExtractedView {
projection: camera.projection_matrix,
transform: *transform,
width: window.physical_width().max(1),
height: window.physical_height().max(1),
near: camera.near,
far: camera.far,
},
visible_entities.clone(),
));
}
let (width, height) = match &camera.target {
CameraTarget::Window(window_id) => {
if let Some(window) = windows.get(*window_id) {
(window.physical_width(), window.physical_height())
} else {
continue;
}
}
CameraTarget::Image(image_handle) => {
if let Some(image) = images.get(image_handle) {
let Extent3d { width, height, .. } = image.texture_descriptor.size;
(width, height)
} else {
continue;
}
}
};
entities.insert(name.clone(), entity);
commands.get_or_spawn(entity).insert_bundle((
ExtractedCamera {
target: camera.target.clone(),
name: camera.name.clone(),
},
ExtractedView {
projection: camera.projection_matrix,
transform: *transform,
width: width.max(1),
height: height.max(1),
near: camera.near,
far: camera.far,
},
visible_entities.clone(),
));
}
}

Expand Down
90 changes: 54 additions & 36 deletions crates/bevy_render/src/view/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ use wgpu::{
pub use window::*;

use crate::{
camera::{ExtractedCamera, ExtractedCameraNames},
camera::{CameraTarget, ExtractedCamera, ExtractedCameraNames},
prelude::Image,
render_asset::RenderAssets,
render_resource::{DynamicUniformVec, Texture, TextureView},
renderer::{RenderDevice, RenderQueue},
texture::{BevyDefault, TextureCache},
Expand Down Expand Up @@ -156,6 +158,7 @@ fn prepare_view_targets(
mut commands: Commands,
camera_names: Res<ExtractedCameraNames>,
windows: Res<ExtractedWindows>,
gpu_images: Res<RenderAssets<Image>>,
msaa: Res<Msaa>,
render_device: Res<RenderDevice>,
mut texture_cache: ResMut<TextureCache>,
Expand All @@ -167,41 +170,56 @@ fn prepare_view_targets(
} else {
continue;
};
let window = if let Some(window) = windows.get(&camera.window_id) {
window
} else {
continue;
};
let swap_chain_texture = if let Some(texture) = &window.swap_chain_texture {
texture
} else {
continue;
let view_target = match &camera.target {
CameraTarget::Window(window_id) => {
let window = if let Some(window) = windows.get(window_id) {
window
} else {
continue;
};
let swap_chain_texture = if let Some(texture) = &window.swap_chain_texture {
texture
} else {
continue;
};
let sampled_target = if msaa.samples > 1 {
let sampled_texture = texture_cache.get(
&render_device,
TextureDescriptor {
label: Some("sampled_color_attachment_texture"),
size: Extent3d {
width: window.physical_width,
height: window.physical_height,
depth_or_array_layers: 1,
},
mip_level_count: 1,
sample_count: msaa.samples,
dimension: TextureDimension::D2,
format: TextureFormat::bevy_default(),
usage: TextureUsages::RENDER_ATTACHMENT,
},
);
Some(sampled_texture.default_view.clone())
} else {
None
};
ViewTarget {
view: swap_chain_texture.clone(),
sampled_target,
}
}
CameraTarget::Image(image_handle) => {
if let Some(gpu_image) = gpu_images.get(image_handle) {
// TODO: MSAA support
ViewTarget {
view: gpu_image.texture_view.clone(),
sampled_target: None,
}
} else {
continue;
}
}
};
let sampled_target = if msaa.samples > 1 {
let sampled_texture = texture_cache.get(
&render_device,
TextureDescriptor {
label: Some("sampled_color_attachment_texture"),
size: Extent3d {
width: window.physical_width,
height: window.physical_height,
depth_or_array_layers: 1,
},
mip_level_count: 1,
sample_count: msaa.samples,
dimension: TextureDimension::D2,
format: TextureFormat::bevy_default(),
usage: TextureUsages::RENDER_ATTACHMENT,
},
);
Some(sampled_texture.default_view.clone())
} else {
None
};

commands.entity(entity).insert(ViewTarget {
view: swap_chain_texture.clone(),
sampled_target,
});
commands.entity(entity).insert(view_target);
}
}
4 changes: 2 additions & 2 deletions examples/window/multiple_windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use bevy::{
core_pipeline::{draw_3d_graph, node, AlphaMask3d, Opaque3d, Transparent3d},
prelude::*,
render::{
camera::{ActiveCameras, ExtractedCameraNames},
camera::{ActiveCameras, CameraTarget, ExtractedCameraNames},
render_graph::{Node, NodeRunError, RenderGraph, RenderGraphContext, SlotValue},
render_phase::RenderPhase,
renderer::RenderContext,
Expand Down Expand Up @@ -65,7 +65,7 @@ fn create_new_window(
// second window camera
commands.spawn_bundle(PerspectiveCameraBundle {
camera: Camera {
window: window_id,
target: CameraTarget::Window(window_id),
name: Some(SECONDARY_CAMERA_NAME.into()),
..Default::default()
},
Expand Down

0 comments on commit e814a8a

Please sign in to comment.