Skip to content
9 changes: 4 additions & 5 deletions crates/bevy_camera/src/camera.rs
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,8 @@ pub enum ViewportConversionError {
CameraMainTextureUsages,
VisibleEntities,
Transform,
Visibility
Visibility,
RenderTarget
)]
pub struct Camera {
/// If set, this camera will render to the given [`Viewport`] rectangle within the configured [`RenderTarget`].
Expand All @@ -356,8 +357,7 @@ pub struct Camera {
/// Computed values for this camera, such as the projection matrix and the render target size.
#[reflect(ignore, clone)]
pub computed: ComputedCameraValues,
/// The "target" that this camera will render to.
pub target: RenderTarget,
// todo: reflect this when #6042 lands
/// The [`CameraOutputMode`] for this camera.
pub output_mode: CameraOutputMode,
/// Controls when MSAA writeback occurs for this camera.
Expand Down Expand Up @@ -385,7 +385,6 @@ impl Default for Camera {
order: 0,
viewport: None,
computed: Default::default(),
target: Default::default(),
output_mode: Default::default(),
msaa_writeback: MsaaWriteback::default(),
clear_color: Default::default(),
Expand Down Expand Up @@ -811,7 +810,7 @@ impl Default for CameraOutputMode {

/// The "target" that a [`Camera`] will render to. For example, this could be a `Window`
/// swapchain or an [`Image`].
#[derive(Debug, Clone, Reflect, From)]
#[derive(Component, Debug, Clone, Reflect, From)]
#[reflect(Clone)]
pub enum RenderTarget {
/// Window to which the camera's view is rendered.
Expand Down
14 changes: 7 additions & 7 deletions crates/bevy_core_pipeline/src/oit/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Order Independent Transparency (OIT) for 3d rendering. See [`OrderIndependentTransparencyPlugin`] for more details.

use bevy_app::prelude::*;
use bevy_camera::{Camera, Camera3d};
use bevy_camera::{Camera3d, RenderTarget};
use bevy_ecs::{component::*, lifecycle::ComponentHook, prelude::*};
use bevy_math::UVec2;
use bevy_platform::collections::HashSet;
Expand Down Expand Up @@ -135,8 +135,8 @@ impl Plugin for OrderIndependentTransparencyPlugin {
// bevy reuses the same depth texture so we need to set this on all cameras with the same render target.
fn configure_depth_texture_usages(
p: Query<Entity, With<PrimaryWindow>>,
cameras: Query<(&Camera, Has<OrderIndependentTransparencySettings>)>,
mut new_cameras: Query<(&mut Camera3d, &Camera), Added<Camera3d>>,
cameras: Query<(&RenderTarget, Has<OrderIndependentTransparencySettings>)>,
mut new_cameras: Query<(&mut Camera3d, &RenderTarget), Added<Camera3d>>,
) {
if new_cameras.is_empty() {
return;
Expand All @@ -145,15 +145,15 @@ fn configure_depth_texture_usages(
// Find all the render target that potentially uses OIT
let primary_window = p.single().ok();
let mut render_target_has_oit = <HashSet<_>>::default();
for (camera, has_oit) in &cameras {
for (render_target, has_oit) in &cameras {
if has_oit {
render_target_has_oit.insert(camera.target.normalize(primary_window));
render_target_has_oit.insert(render_target.normalize(primary_window));
}
}

// Update the depth texture usage for cameras with a render target that has OIT
for (mut camera_3d, camera) in &mut new_cameras {
if render_target_has_oit.contains(&camera.target.normalize(primary_window)) {
for (mut camera_3d, render_target) in &mut new_cameras {
if render_target_has_oit.contains(&render_target.normalize(primary_window)) {
let mut usages = TextureUsages::from(camera_3d.depth_texture_usages);
usages |= TextureUsages::RENDER_ATTACHMENT | TextureUsages::TEXTURE_BINDING;
camera_3d.depth_texture_usages = usages.into();
Expand Down
11 changes: 5 additions & 6 deletions crates/bevy_dev_tools/src/picking_debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use bevy_app::prelude::*;
use bevy_camera::visibility::Visibility;
use bevy_camera::Camera;
use bevy_camera::{Camera, RenderTarget};
use bevy_color::prelude::*;
use bevy_ecs::prelude::*;
use bevy_picking::backend::HitData;
Expand Down Expand Up @@ -243,7 +243,7 @@ pub fn update_debug_data(
/// Draw text on each cursor with debug info
pub fn debug_draw(
mut commands: Commands,
camera_query: Query<(Entity, &Camera)>,
camera_query: Query<(Entity, &Camera, &RenderTarget)>,
primary_window: Query<Entity, With<bevy_window::PrimaryWindow>>,
pointers: Query<(Entity, &PointerId, &PointerDebug)>,
scale: Res<UiScale>,
Expand All @@ -254,17 +254,16 @@ pub fn debug_draw(
};
let text = format!("{id:?}\n{debug}");

for (camera, _) in camera_query.iter().filter(|(_, camera)| {
camera
.target
for (camera, _, _) in camera_query.iter().filter(|(_, _, render_target)| {
render_target
.normalize(primary_window.single().ok())
.is_some_and(|target| target == pointer_location.target)
}) {
let mut pointer_pos = pointer_location.position;
if let Some(viewport) = camera_query
.get(camera)
.ok()
.and_then(|(_, camera)| camera.logical_viewport_rect())
.and_then(|(_, camera, _)| camera.logical_viewport_rect())
{
pointer_pos -= viewport.min;
}
Expand Down
19 changes: 12 additions & 7 deletions crates/bevy_picking/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ pub mod ray {
//! Types and systems for constructing rays from cameras and pointers.

use crate::backend::prelude::{PointerId, PointerLocation};
use bevy_camera::Camera;
use bevy_camera::{Camera, RenderTarget};
use bevy_ecs::prelude::*;
use bevy_math::Ray3d;
use bevy_platform::collections::{hash_map::Iter, HashMap};
Expand Down Expand Up @@ -196,20 +196,24 @@ pub mod ray {
pub fn repopulate(
mut ray_map: ResMut<Self>,
primary_window_entity: Query<Entity, With<PrimaryWindow>>,
cameras: Query<(Entity, &Camera, &GlobalTransform)>,
cameras: Query<(Entity, &Camera, &RenderTarget, &GlobalTransform)>,
pointers: Query<(&PointerId, &PointerLocation)>,
) {
ray_map.map.clear();

for (camera_entity, camera, camera_tfm) in &cameras {
for (camera_entity, camera, render_target, camera_tfm) in &cameras {
if !camera.is_active {
continue;
}

for (&pointer_id, pointer_loc) in &pointers {
if let Some(ray) =
make_ray(&primary_window_entity, camera, camera_tfm, pointer_loc)
{
if let Some(ray) = make_ray(
&primary_window_entity,
camera,
render_target,
camera_tfm,
pointer_loc,
) {
ray_map
.map
.insert(RayId::new(camera_entity, pointer_id), ray);
Expand All @@ -222,11 +226,12 @@ pub mod ray {
fn make_ray(
primary_window_entity: &Query<Entity, With<PrimaryWindow>>,
camera: &Camera,
render_target: &RenderTarget,
camera_tfm: &GlobalTransform,
pointer_loc: &PointerLocation,
) -> Option<Ray3d> {
let pointer_loc = pointer_loc.location()?;
if !pointer_loc.is_in_viewport(camera, primary_window_entity) {
if !pointer_loc.is_in_viewport(camera, render_target, primary_window_entity) {
return None;
}
camera
Expand Down
6 changes: 3 additions & 3 deletions crates/bevy_picking/src/pointer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
//! The purpose of this module is primarily to provide a common interface that can be
//! driven by lower-level input devices and consumed by higher-level interaction systems.

use bevy_camera::Camera;
use bevy_camera::NormalizedRenderTarget;
use bevy_camera::{Camera, RenderTarget};
use bevy_ecs::prelude::*;
use bevy_input::mouse::MouseScrollUnit;
use bevy_math::Vec2;
Expand Down Expand Up @@ -223,10 +223,10 @@ impl Location {
pub fn is_in_viewport(
&self,
camera: &Camera,
render_target: &RenderTarget,
primary_window: &Query<Entity, With<PrimaryWindow>>,
) -> bool {
if camera
.target
if render_target
.normalize(Some(match primary_window.single() {
Ok(w) => w,
Err(_) => return false,
Expand Down
48 changes: 27 additions & 21 deletions crates/bevy_render/src/camera.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use bevy_camera::{
visibility::{self, RenderLayers, VisibleEntities},
Camera, Camera2d, Camera3d, CameraMainTextureUsages, CameraOutputMode, CameraUpdateSystems,
ClearColor, ClearColorConfig, Exposure, ManualTextureViewHandle, MsaaWriteback,
NormalizedRenderTarget, Projection, RenderTargetInfo, Viewport,
NormalizedRenderTarget, Projection, RenderTarget, RenderTargetInfo, Viewport,
};
use bevy_derive::{Deref, DerefMut};
use bevy_ecs::{
Expand Down Expand Up @@ -312,7 +312,7 @@ pub fn camera_system(
windows: Query<(Entity, &Window)>,
images: Res<Assets<Image>>,
manual_texture_views: Res<ManualTextureViews>,
mut cameras: Query<(&mut Camera, &mut Projection)>,
mut cameras: Query<(&mut Camera, &RenderTarget, &mut Projection)>,
) -> Result<(), BevyError> {
let primary_window = primary_window.iter().next();

Expand All @@ -333,13 +333,13 @@ pub fn camera_system(
})
.collect();

for (mut camera, mut camera_projection) in &mut cameras {
for (mut camera, render_target, mut camera_projection) in &mut cameras {
let mut viewport_size = camera
.viewport
.as_ref()
.map(|viewport| viewport.physical_size);

if let Some(normalized_target) = &camera.target.normalize(primary_window)
if let Some(normalized_target) = render_target.normalize(primary_window)
&& (normalized_target.is_changed(&changed_window_ids, &changed_image_handles)
|| camera.is_added()
|| camera_projection.is_changed()
Expand Down Expand Up @@ -423,18 +423,21 @@ pub fn extract_cameras(
Entity,
RenderEntity,
&Camera,
&RenderTarget,
&CameraRenderGraph,
&GlobalTransform,
&VisibleEntities,
&Frustum,
Has<Hdr>,
Option<&ColorGrading>,
Option<&Exposure>,
Option<&TemporalJitter>,
Option<&MipBias>,
Option<&RenderLayers>,
Option<&Projection>,
Has<NoIndirectDrawing>,
(
Has<Hdr>,
Option<&ColorGrading>,
Option<&Exposure>,
Option<&TemporalJitter>,
Option<&MipBias>,
Option<&RenderLayers>,
Option<&Projection>,
Has<NoIndirectDrawing>,
),
)>,
>,
primary_window: Extract<Query<Entity, With<PrimaryWindow>>>,
Expand All @@ -457,18 +460,21 @@ pub fn extract_cameras(
main_entity,
render_entity,
camera,
render_target,
camera_render_graph,
transform,
visible_entities,
frustum,
hdr,
color_grading,
exposure,
temporal_jitter,
mip_bias,
render_layers,
projection,
no_indirect_drawing,
(
hdr,
color_grading,
exposure,
temporal_jitter,
mip_bias,
render_layers,
projection,
no_indirect_drawing,
),
) in query.iter()
{
if !camera.is_active {
Expand Down Expand Up @@ -523,7 +529,7 @@ pub fn extract_cameras(
let mut commands = commands.entity(render_entity);
commands.insert((
ExtractedCamera {
target: camera.target.normalize(primary_window),
target: render_target.normalize(primary_window),
viewport: camera.viewport.clone(),
physical_viewport_size: Some(viewport_size),
physical_target_size: Some(target_size),
Expand Down
7 changes: 4 additions & 3 deletions crates/bevy_sprite/src/picking_backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use bevy_app::prelude::*;
use bevy_asset::prelude::*;
use bevy_camera::{
visibility::{RenderLayers, ViewVisibility},
Camera, Projection,
Camera, Projection, RenderTarget,
};
use bevy_color::Alpha;
use bevy_ecs::prelude::*;
Expand Down Expand Up @@ -88,6 +88,7 @@ fn sprite_picking(
cameras: Query<(
Entity,
&Camera,
&RenderTarget,
&GlobalTransform,
&Projection,
Has<SpritePickingCamera>,
Expand Down Expand Up @@ -135,6 +136,7 @@ fn sprite_picking(
let Ok((
cam_entity,
camera,
render_target,
cam_transform,
Projection::Orthographic(cam_ortho),
cam_can_pick,
Expand All @@ -156,8 +158,7 @@ fn sprite_picking(
None
})?;

if camera
.target
if render_target
.normalize(primary_window)
.is_none_or(|x| x != location.target)
{
Expand Down
8 changes: 4 additions & 4 deletions crates/bevy_ui/src/focus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::{
ui_transform::UiGlobalTransform, ComputedNode, ComputedUiTargetCamera, Node, OverrideClip,
UiStack,
};
use bevy_camera::{visibility::InheritedVisibility, Camera, NormalizedRenderTarget};
use bevy_camera::{visibility::InheritedVisibility, Camera, NormalizedRenderTarget, RenderTarget};
use bevy_ecs::{
change_detection::DetectChangesMut,
entity::{ContainsEntity, Entity},
Expand Down Expand Up @@ -149,7 +149,7 @@ pub struct NodeQuery {
pub fn ui_focus_system(
mut hovered_nodes: Local<Vec<Entity>>,
mut state: Local<State>,
camera_query: Query<(Entity, &Camera)>,
camera_query: Query<(Entity, &Camera, &RenderTarget)>,
primary_window: Query<Entity, With<PrimaryWindow>>,
windows: Query<&Window>,
mouse_button_input: Res<ButtonInput<MouseButton>>,
Expand Down Expand Up @@ -189,10 +189,10 @@ pub fn ui_focus_system(

let camera_cursor_positions: HashMap<Entity, Vec2> = camera_query
.iter()
.filter_map(|(entity, camera)| {
.filter_map(|(entity, camera, render_target)| {
// Interactions are only supported for cameras rendering to a window.
let Some(NormalizedRenderTarget::Window(window_ref)) =
camera.target.normalize(primary_window)
render_target.normalize(primary_window)
else {
return None;
};
Expand Down
Loading