diff --git a/crates/bevy_render/src/camera/camera.rs b/crates/bevy_render/src/camera/camera.rs index 7a3defd68c8792..51f459273bad57 100644 --- a/crates/bevy_render/src/camera/camera.rs +++ b/crates/bevy_render/src/camera/camera.rs @@ -823,6 +823,7 @@ pub struct ExtractedCamera { pub clear_color: ClearColorConfig, pub sorted_camera_index_for_target: usize, pub exposure: f32, + pub hdr: bool, } pub fn extract_cameras( @@ -902,6 +903,7 @@ pub fn extract_cameras( exposure: exposure .map(|e| e.exposure()) .unwrap_or_else(|| Exposure::default().exposure()), + hdr: camera.hdr, }, ExtractedView { projection: camera.projection_matrix(), @@ -953,6 +955,7 @@ pub struct SortedCamera { pub entity: Entity, pub order: isize, pub target: Option, + pub hdr: bool, } pub fn sort_cameras( @@ -965,6 +968,7 @@ pub fn sort_cameras( entity, order: camera.order, target: camera.target.clone(), + hdr: camera.hdr, }); } // sort by order and ensure within an order, RenderTargets of the same type are packed together @@ -985,7 +989,7 @@ pub fn sort_cameras( } } if let Some(target) = &sorted_camera.target { - let count = target_counts.entry(target.clone()).or_insert(0usize); + let count = target_counts.entry((target.clone(), sorted_camera.hdr)).or_insert(0usize); let (_, mut camera) = cameras.get_mut(sorted_camera.entity).unwrap(); camera.sorted_camera_index_for_target = *count; *count += 1; diff --git a/crates/bevy_render/src/texture/texture_attachment.rs b/crates/bevy_render/src/texture/texture_attachment.rs index 1d6b3ba33c2929..0e1632074de8ca 100644 --- a/crates/bevy_render/src/texture/texture_attachment.rs +++ b/crates/bevy_render/src/texture/texture_attachment.rs @@ -1,6 +1,7 @@ use super::CachedTexture; use crate::render_resource::{TextureFormat, TextureView}; use bevy_color::LinearRgba; +use bevy_utils::tracing::info; use std::sync::{ atomic::{AtomicBool, Ordering}, Arc, @@ -39,7 +40,6 @@ impl ColorAttachment { pub fn get_attachment(&self) -> RenderPassColorAttachment { if let Some(resolve_target) = self.resolve_target.as_ref() { let first_call = self.is_first_call.fetch_and(false, Ordering::SeqCst); - RenderPassColorAttachment { view: &resolve_target.default_view, resolve_target: Some(&self.texture.default_view), diff --git a/crates/bevy_render/src/view/mod.rs b/crates/bevy_render/src/view/mod.rs index 20e669ec1be192..3a47335129903f 100644 --- a/crates/bevy_render/src/view/mod.rs +++ b/crates/bevy_render/src/view/mod.rs @@ -41,6 +41,7 @@ use wgpu::{ BufferUsages, Extent3d, RenderPassColorAttachment, RenderPassDepthStencilAttachment, StoreOp, TextureDescriptor, TextureDimension, TextureFormat, TextureUsages, }; +use bevy_utils::tracing::info; pub const VIEW_TYPE_HANDLE: Handle = Handle::weak_from_u128(15421373904451797197); @@ -905,6 +906,12 @@ pub fn prepare_view_targets( main_texture: main_texture.clone(), }; + info!( + "{} Creating view target for camera {:?} with target {:?}", + entity, + camera.order, sampled.as_ref().map(|x| x.default_view.id()), + ); + commands.entity(entity).insert(ViewTarget { main_texture: main_textures.main_texture.clone(), main_textures, diff --git a/examples/3d/split_screen.rs b/examples/3d/split_screen.rs index 7d78b59ccbf996..ef3087b3d5b894 100644 --- a/examples/3d/split_screen.rs +++ b/examples/3d/split_screen.rs @@ -5,10 +5,14 @@ use std::f32::consts::PI; use bevy::{ pbr::CascadeShadowConfigBuilder, prelude::*, render::camera::Viewport, window::WindowResized, }; +use bevy::color::palettes::css::{BLACK, BLUE, RED}; +use bevy::render::camera::CameraOutputMode; +use bevy::render::render_resource::{BlendComponent, BlendFactor, BlendOperation, BlendState}; fn main() { App::new() .add_plugins(DefaultPlugins) + // .insert_resource(Msaa::Off) .add_systems(Startup, setup) .add_systems(Update, (set_camera_viewports, button_system)) .run(); @@ -46,19 +50,19 @@ fn setup( maximum_distance: 280.0, ..default() } - .into(), + .into(), ..default() }); // Cameras and their dedicated UI - for (index, (camera_name, camera_pos)) in [ - ("Player 1", Vec3::new(0.0, 200.0, -150.0)), - ("Player 2", Vec3::new(150.0, 150., 50.0)), - ("Player 3", Vec3::new(100.0, 150., -150.0)), - ("Player 4", Vec3::new(-100.0, 80., 150.0)), + for (index, (camera_name, camera_pos, hdr)) in [ + ("Player 1", Vec3::new(0.0, 200.0, -150.0), false), + ("Player 2", Vec3::new(150.0, 150., 50.0), true), + ("Player 3", Vec3::new(100.0, 150., -150.0), false), + ("Player 4", Vec3::new(-100.0, 80., 150.0), true), ] - .iter() - .enumerate() + .iter() + .enumerate() { let camera = commands .spawn(( @@ -66,13 +70,36 @@ fn setup( transform: Transform::from_translation(*camera_pos) .looking_at(Vec3::ZERO, Vec3::Y), camera: Camera { + hdr: *hdr, // Renders cameras with different priorities to prevent ambiguities order: index as isize, // Don't clear after the first camera because the first camera already cleared the entire window - clear_color: if index > 0 { - ClearColorConfig::None - } else { + clear_color: if index == 0 || index == 1 { ClearColorConfig::default() + } else { + ClearColorConfig::None + }, + output_mode: if index == 0 || index == 1 { + CameraOutputMode::Write { + clear_color: ClearColorConfig::Default, + blend_state: Some(BlendState::REPLACE), + } + } else { + CameraOutputMode::Write { + clear_color: ClearColorConfig::None, + blend_state: Some(BlendState { + color: BlendComponent { + src_factor: BlendFactor::SrcAlpha, + dst_factor: BlendFactor::OneMinusSrcAlpha, + operation: BlendOperation::Max, + }, + alpha: BlendComponent{ + src_factor: BlendFactor::One, + dst_factor: BlendFactor::OneMinusSrcAlpha, + operation: BlendOperation::Min, + }, + }) + } }, ..default() }, @@ -83,53 +110,6 @@ fn setup( }, )) .id(); - - // Set up UI - commands - .spawn(( - TargetCamera(camera), - NodeBundle { - style: Style { - width: Val::Percent(100.), - height: Val::Percent(100.), - padding: UiRect::all(Val::Px(20.)), - ..default() - }, - ..default() - }, - )) - .with_children(|parent| { - parent.spawn(TextBundle::from_section( - *camera_name, - TextStyle { - font_size: 20., - ..default() - }, - )); - buttons_panel(parent); - }); - } - - fn buttons_panel(parent: &mut ChildBuilder) { - parent - .spawn(NodeBundle { - style: Style { - position_type: PositionType::Absolute, - width: Val::Percent(100.), - height: Val::Percent(100.), - display: Display::Flex, - flex_direction: FlexDirection::Row, - justify_content: JustifyContent::SpaceBetween, - align_items: AlignItems::Center, - padding: UiRect::all(Val::Px(20.)), - ..default() - }, - ..default() - }) - .with_children(|parent| { - rotate_button(parent, "<", Direction::Left); - rotate_button(parent, ">", Direction::Right); - }); } fn rotate_button(parent: &mut ChildBuilder, caption: &str, direction: Direction) { @@ -199,23 +179,10 @@ fn set_camera_viewports( #[allow(clippy::type_complexity)] fn button_system( - interaction_query: Query< - (&Interaction, &TargetCamera, &RotateCamera), - (Changed, With