diff --git a/crates/bevy_core_pipeline/src/auto_exposure/settings.rs b/crates/bevy_core_pipeline/src/auto_exposure/settings.rs index cf6fdd4e24d81..ae359a8a01dd4 100644 --- a/crates/bevy_core_pipeline/src/auto_exposure/settings.rs +++ b/crates/bevy_core_pipeline/src/auto_exposure/settings.rs @@ -5,7 +5,7 @@ use bevy_asset::Handle; use bevy_ecs::{prelude::Component, reflect::ReflectComponent}; use bevy_image::Image; use bevy_reflect::{std_traits::ReflectDefault, Reflect}; -use bevy_render::extract_component::ExtractComponent; +use bevy_render::{extract_component::ExtractComponent, view::Hdr}; use bevy_utils::default; /// Component that enables auto exposure for an HDR-enabled 2d or 3d camera. @@ -25,6 +25,7 @@ use bevy_utils::default; /// **Auto Exposure requires compute shaders and is not compatible with WebGL2.** #[derive(Component, Clone, Reflect, ExtractComponent)] #[reflect(Component, Default, Clone)] +#[require(Hdr)] pub struct AutoExposure { /// The range of exposure values for the histogram. /// diff --git a/crates/bevy_core_pipeline/src/bloom/settings.rs b/crates/bevy_core_pipeline/src/bloom/settings.rs index f6ee8dbd1e358..195c2eb4c0b53 100644 --- a/crates/bevy_core_pipeline/src/bloom/settings.rs +++ b/crates/bevy_core_pipeline/src/bloom/settings.rs @@ -1,8 +1,12 @@ use super::downsampling_pipeline::BloomUniforms; -use bevy_ecs::{prelude::Component, query::QueryItem, reflect::ReflectComponent}; +use bevy_ecs::{ + prelude::Component, + query::{QueryItem, With}, + reflect::ReflectComponent, +}; use bevy_math::{AspectRatio, URect, UVec4, Vec2, Vec4}; use bevy_reflect::{std_traits::ReflectDefault, Reflect}; -use bevy_render::{extract_component::ExtractComponent, prelude::Camera}; +use bevy_render::{extract_component::ExtractComponent, prelude::Camera, view::Hdr}; /// Applies a bloom effect to an HDR-enabled 2d or 3d camera. /// @@ -26,6 +30,7 @@ use bevy_render::{extract_component::ExtractComponent, prelude::Camera}; /// used in Bevy as well as a visualization of the curve's respective scattering profile. #[derive(Component, Reflect, Clone)] #[reflect(Component, Default, Clone)] +#[require(Hdr)] pub struct Bloom { /// Controls the baseline of how much the image is scattered (default: 0.15). /// @@ -219,7 +224,7 @@ pub enum BloomCompositeMode { impl ExtractComponent for Bloom { type QueryData = (&'static Self, &'static Camera); - type QueryFilter = (); + type QueryFilter = With; type Out = (Self, BloomUniforms); fn extract_component((bloom, camera): QueryItem<'_, Self::QueryData>) -> Option { @@ -228,9 +233,8 @@ impl ExtractComponent for Bloom { camera.physical_viewport_size(), camera.physical_target_size(), camera.is_active, - camera.hdr, ) { - (Some(URect { min: origin, .. }), Some(size), Some(target_size), true, true) + (Some(URect { min: origin, .. }), Some(size), Some(target_size), true) if size.x != 0 && size.y != 0 => { let threshold = bloom.prefilter.threshold; diff --git a/crates/bevy_pbr/src/atmosphere/mod.rs b/crates/bevy_pbr/src/atmosphere/mod.rs index e7f17f0e1e855..1dd9038494f47 100644 --- a/crates/bevy_pbr/src/atmosphere/mod.rs +++ b/crates/bevy_pbr/src/atmosphere/mod.rs @@ -50,6 +50,7 @@ use bevy_reflect::{std_traits::ReflectDefault, Reflect}; use bevy_render::{ extract_component::UniformComponentPlugin, render_resource::{DownlevelFlags, ShaderType, SpecializedRenderPipelines}, + view::Hdr, }; use bevy_render::{ extract_component::{ExtractComponent, ExtractComponentPlugin}, @@ -246,7 +247,7 @@ impl Plugin for AtmospherePlugin { /// from the planet's surface, ozone only exists in a band centered at a fairly /// high altitude. #[derive(Clone, Component, Reflect, ShaderType)] -#[require(AtmosphereSettings)] +#[require(AtmosphereSettings, Hdr)] #[reflect(Clone, Default)] pub struct Atmosphere { /// Radius of the planet diff --git a/crates/bevy_pbr/src/atmosphere/resources.rs b/crates/bevy_pbr/src/atmosphere/resources.rs index b872916619830..9f6e4801da161 100644 --- a/crates/bevy_pbr/src/atmosphere/resources.rs +++ b/crates/bevy_pbr/src/atmosphere/resources.rs @@ -325,7 +325,6 @@ pub(crate) struct RenderSkyPipelineId(pub CachedRenderPipelineId); #[derive(Copy, Clone, Hash, PartialEq, Eq)] pub(crate) struct RenderSkyPipelineKey { pub msaa_samples: u32, - pub hdr: bool, pub dual_source_blending: bool, } @@ -338,9 +337,6 @@ impl SpecializedRenderPipeline for RenderSkyBindGroupLayouts { if key.msaa_samples > 1 { shader_defs.push("MULTISAMPLED".into()); } - if key.hdr { - shader_defs.push("TONEMAP_IN_SHADER".into()); - } if key.dual_source_blending { shader_defs.push("DUAL_SOURCE_BLENDING".into()); } @@ -394,20 +390,19 @@ impl SpecializedRenderPipeline for RenderSkyBindGroupLayouts { } pub(super) fn queue_render_sky_pipelines( - views: Query<(Entity, &Camera, &Msaa), With>, + views: Query<(Entity, &Msaa), (With, With)>, pipeline_cache: Res, layouts: Res, mut specializer: ResMut>, render_device: Res, mut commands: Commands, ) { - for (entity, camera, msaa) in &views { + for (entity, msaa) in &views { let id = specializer.specialize( &pipeline_cache, &layouts, RenderSkyPipelineKey { msaa_samples: msaa.samples(), - hdr: camera.hdr, dual_source_blending: render_device .features() .contains(WgpuFeatures::DUAL_SOURCE_BLENDING), diff --git a/crates/bevy_render/src/camera/camera.rs b/crates/bevy_render/src/camera/camera.rs index 95218b7a593cd..2828486fd4d68 100644 --- a/crates/bevy_render/src/camera/camera.rs +++ b/crates/bevy_render/src/camera/camera.rs @@ -13,7 +13,7 @@ use crate::{ sync_world::{RenderEntity, SyncToRenderWorld}, texture::GpuImage, view::{ - ColorGrading, ExtractedView, ExtractedWindows, Msaa, NoIndirectDrawing, RenderLayers, + ColorGrading, ExtractedView, ExtractedWindows, Hdr, Msaa, NoIndirectDrawing, RenderLayers, RenderVisibleEntities, RetainedViewEntity, ViewUniformOffset, Visibility, VisibleEntities, }, Extract, @@ -356,9 +356,6 @@ pub struct Camera { pub computed: ComputedCameraValues, /// The "target" that this camera will render to. pub target: RenderTarget, - /// If this is set to `true`, the camera will use an intermediate "high dynamic range" render texture. - /// This allows rendering with a wider range of lighting values. - pub hdr: bool, // todo: reflect this when #6042 lands /// The [`CameraOutputMode`] for this camera. #[reflect(ignore, clone)] @@ -389,7 +386,6 @@ impl Default for Camera { computed: Default::default(), target: Default::default(), output_mode: Default::default(), - hdr: false, msaa_writeback: true, clear_color: Default::default(), sub_camera_view: None, @@ -1101,6 +1097,7 @@ pub fn extract_cameras( &GlobalTransform, &VisibleEntities, &Frustum, + Has, Option<&ColorGrading>, Option<&Exposure>, Option<&TemporalJitter>, @@ -1122,6 +1119,7 @@ pub fn extract_cameras( transform, visible_entities, frustum, + hdr, color_grading, exposure, temporal_jitter, @@ -1200,14 +1198,14 @@ pub fn extract_cameras( exposure: exposure .map(Exposure::exposure) .unwrap_or_else(|| Exposure::default().exposure()), - hdr: camera.hdr, + hdr, }, ExtractedView { retained_view_entity: RetainedViewEntity::new(main_entity.into(), None, 0), clip_from_view: camera.clip_from_view(), world_from_view: *transform, clip_from_world: None, - hdr: camera.hdr, + hdr, viewport: UVec4::new( viewport_origin.x, viewport_origin.y, diff --git a/crates/bevy_render/src/view/mod.rs b/crates/bevy_render/src/view/mod.rs index c392dcaaebe76..1df3b12f04ecb 100644 --- a/crates/bevy_render/src/view/mod.rs +++ b/crates/bevy_render/src/view/mod.rs @@ -114,6 +114,7 @@ impl Plugin for ViewPlugin { .register_type::() // NOTE: windows.is_changed() handles cases where a window was resized .add_plugins(( + ExtractComponentPlugin::::default(), ExtractComponentPlugin::::default(), ExtractComponentPlugin::::default(), VisibilityPlugin, @@ -199,6 +200,14 @@ impl Msaa { } } +/// If this component is added to a camera, the camera will use an intermediate "high dynamic range" render texture. +/// This allows rendering with a wider range of lighting values. +#[derive( + Component, Default, Copy, Clone, ExtractComponent, Reflect, PartialEq, Eq, Hash, Debug, +)] +#[reflect(Component, Default, PartialEq, Hash, Debug)] +pub struct Hdr; + /// An identifier for a view that is stable across frames. /// /// We can't use [`Entity`] for this because render world entities aren't diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index 97ba9cd7ee4e4..be4f3391961e6 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -27,7 +27,7 @@ use bevy_render::render_phase::ViewSortedRenderPhases; use bevy_render::renderer::RenderContext; use bevy_render::sync_world::MainEntity; use bevy_render::texture::TRANSPARENT_IMAGE_HANDLE; -use bevy_render::view::RetainedViewEntity; +use bevy_render::view::{Hdr, RetainedViewEntity}; use bevy_render::{ camera::Camera, render_asset::RenderAssets, @@ -618,6 +618,7 @@ pub fn extract_ui_camera_view( Entity, RenderEntity, &Camera, + Has, Option<&UiAntiAlias>, Option<&BoxShadowSamples>, ), @@ -628,7 +629,7 @@ pub fn extract_ui_camera_view( ) { live_entities.clear(); - for (main_entity, render_entity, camera, ui_anti_alias, shadow_samples) in &query { + for (main_entity, render_entity, camera, hdr, ui_anti_alias, shadow_samples) in &query { // ignore inactive cameras if !camera.is_active { commands @@ -664,7 +665,7 @@ pub fn extract_ui_camera_view( UI_CAMERA_FAR + UI_CAMERA_TRANSFORM_OFFSET, ), clip_from_world: None, - hdr: camera.hdr, + hdr, viewport: UVec4::from(( physical_viewport_rect.min, physical_viewport_rect.size(), diff --git a/examples/2d/bloom_2d.rs b/examples/2d/bloom_2d.rs index fd90210d6fbc7..9d9be1e5c7f10 100644 --- a/examples/2d/bloom_2d.rs +++ b/examples/2d/bloom_2d.rs @@ -25,7 +25,6 @@ fn setup( commands.spawn(( Camera2d, Camera { - hdr: true, // 1. HDR is required for bloom clear_color: ClearColorConfig::Custom(Color::BLACK), ..default() }, diff --git a/examples/3d/anti_aliasing.rs b/examples/3d/anti_aliasing.rs index e29574588c71f..1f693ce23886a 100644 --- a/examples/3d/anti_aliasing.rs +++ b/examples/3d/anti_aliasing.rs @@ -17,6 +17,7 @@ use bevy::{ camera::TemporalJitter, render_asset::RenderAssetUsages, render_resource::{Extent3d, TextureDimension, TextureFormat}, + view::Hdr, }, }; @@ -300,10 +301,7 @@ fn setup( // Camera commands.spawn(( Camera3d::default(), - Camera { - hdr: true, - ..default() - }, + Hdr, Transform::from_xyz(0.7, 0.7, 1.0).looking_at(Vec3::new(0.0, 0.3, 0.0), Vec3::Y), ContrastAdaptiveSharpening { enabled: false, diff --git a/examples/3d/atmosphere.rs b/examples/3d/atmosphere.rs index 53c5c91dfa687..edc6d04dab7b0 100644 --- a/examples/3d/atmosphere.rs +++ b/examples/3d/atmosphere.rs @@ -20,11 +20,6 @@ fn main() { fn setup_camera_fog(mut commands: Commands) { commands.spawn(( Camera3d::default(), - // HDR is required for atmospheric scattering to be properly applied to the scene - Camera { - hdr: true, - ..default() - }, Transform::from_xyz(-1.2, 0.15, 0.0).looking_at(Vec3::Y * 0.1, Vec3::Y), // This is the component that enables atmospheric scattering for a camera Atmosphere::EARTH, @@ -36,7 +31,7 @@ fn setup_camera_fog(mut commands: Commands) { scene_units_to_m: 1e+4, ..Default::default() }, - // The directional light illuminance used in this scene + // The directional light illuminance used in this scene // (the one recommended for use with this feature) is // quite bright, so raising the exposure compensation helps // bring the scene to a nicer brightness range. diff --git a/examples/3d/auto_exposure.rs b/examples/3d/auto_exposure.rs index 79fece61c8e36..62c875dc5dc8a 100644 --- a/examples/3d/auto_exposure.rs +++ b/examples/3d/auto_exposure.rs @@ -40,10 +40,6 @@ fn setup( commands.spawn(( Camera3d::default(), - Camera { - hdr: true, - ..default() - }, Transform::from_xyz(1.0, 0.0, 0.0).looking_at(Vec3::ZERO, Vec3::Y), AutoExposure { metering_mask: metering_mask.clone(), diff --git a/examples/3d/blend_modes.rs b/examples/3d/blend_modes.rs index 830acfdb34160..95fe522cf0ba8 100644 --- a/examples/3d/blend_modes.rs +++ b/examples/3d/blend_modes.rs @@ -10,7 +10,7 @@ //! | `Spacebar` | Toggle Unlit | //! | `C` | Randomize Colors | -use bevy::{color::palettes::css::ORANGE, prelude::*}; +use bevy::{color::palettes::css::ORANGE, prelude::*, render::view::Hdr}; use rand::random; fn main() { @@ -149,6 +149,7 @@ fn setup( commands.spawn(( Camera3d::default(), Transform::from_xyz(0.0, 2.5, 10.0).looking_at(Vec3::ZERO, Vec3::Y), + Hdr, // Unfortunately, MSAA and HDR are not supported simultaneously under WebGL. // Since this example uses HDR, we must disable MSAA for Wasm builds, at least // until WebGPU is ready and no longer behind a feature flag in Web browsers. @@ -249,13 +250,23 @@ impl Default for ExampleState { fn example_control_system( mut materials: ResMut>, controllable: Query<(&MeshMaterial3d, &ExampleControls)>, - camera: Single<(&mut Camera, &mut Transform, &GlobalTransform), With>, + camera: Single< + ( + Entity, + &mut Camera, + &mut Transform, + &GlobalTransform, + Has, + ), + With, + >, mut labels: Query<(&mut Node, &ExampleLabel)>, mut display: Single<&mut Text, With>, labeled: Query<&GlobalTransform>, mut state: Local, time: Res