Skip to content

Split Camera.hdr out into a new component #18873

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
3 changes: 2 additions & 1 deletion crates/bevy_core_pipeline/src/auto_exposure/settings.rs
Original file line number Diff line number Diff line change
@@ -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.
///
14 changes: 9 additions & 5 deletions crates/bevy_core_pipeline/src/bloom/settings.rs
Original file line number Diff line number Diff line change
@@ -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<Hdr>;
type Out = (Self, BloomUniforms);

fn extract_component((bloom, camera): QueryItem<'_, Self::QueryData>) -> Option<Self::Out> {
@@ -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;
3 changes: 2 additions & 1 deletion crates/bevy_pbr/src/atmosphere/mod.rs
Original file line number Diff line number Diff line change
@@ -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
9 changes: 2 additions & 7 deletions crates/bevy_pbr/src/atmosphere/resources.rs
Original file line number Diff line number Diff line change
@@ -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<Atmosphere>>,
views: Query<(Entity, &Msaa), (With<Camera>, With<Atmosphere>)>,
pipeline_cache: Res<PipelineCache>,
layouts: Res<RenderSkyBindGroupLayouts>,
mut specializer: ResMut<SpecializedRenderPipelines<RenderSkyBindGroupLayouts>>,
render_device: Res<RenderDevice>,
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),
12 changes: 5 additions & 7 deletions crates/bevy_render/src/camera/camera.rs
Original file line number Diff line number Diff line change
@@ -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<Hdr>,
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,
9 changes: 9 additions & 0 deletions crates/bevy_render/src/view/mod.rs
Original file line number Diff line number Diff line change
@@ -114,6 +114,7 @@ impl Plugin for ViewPlugin {
.register_type::<OcclusionCulling>()
// NOTE: windows.is_changed() handles cases where a window was resized
.add_plugins((
ExtractComponentPlugin::<Hdr>::default(),
ExtractComponentPlugin::<Msaa>::default(),
ExtractComponentPlugin::<OcclusionCulling>::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
7 changes: 4 additions & 3 deletions crates/bevy_ui/src/render/mod.rs
Original file line number Diff line number Diff line change
@@ -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<Hdr>,
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(),
1 change: 0 additions & 1 deletion examples/2d/bloom_2d.rs
Original file line number Diff line number Diff line change
@@ -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()
},
6 changes: 2 additions & 4 deletions examples/3d/anti_aliasing.rs
Original file line number Diff line number Diff line change
@@ -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,
7 changes: 1 addition & 6 deletions examples/3d/atmosphere.rs
Original file line number Diff line number Diff line change
@@ -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.
4 changes: 0 additions & 4 deletions examples/3d/auto_exposure.rs
Original file line number Diff line number Diff line change
@@ -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(),
25 changes: 20 additions & 5 deletions examples/3d/blend_modes.rs
Original file line number Diff line number Diff line change
@@ -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<Assets<StandardMaterial>>,
controllable: Query<(&MeshMaterial3d<StandardMaterial>, &ExampleControls)>,
camera: Single<(&mut Camera, &mut Transform, &GlobalTransform), With<Camera3d>>,
camera: Single<
(
Entity,
&mut Camera,
&mut Transform,
&GlobalTransform,
Has<Hdr>,
),
With<Camera3d>,
>,
mut labels: Query<(&mut Node, &ExampleLabel)>,
mut display: Single<&mut Text, With<ExampleDisplay>>,
labeled: Query<&GlobalTransform>,
mut state: Local<ExampleState>,
time: Res<Time>,
input: Res<ButtonInput<KeyCode>>,
mut commands: Commands,
) {
if input.pressed(KeyCode::ArrowUp) {
state.alpha = (state.alpha + time.delta_secs()).min(1.0);
@@ -289,10 +300,14 @@ fn example_control_system(
}
}

let (mut camera, mut camera_transform, camera_global_transform) = camera.into_inner();
let (entity, camera, mut camera_transform, camera_global_transform, hdr) = camera.into_inner();

if input.just_pressed(KeyCode::KeyH) {
camera.hdr = !camera.hdr;
if hdr {
commands.entity(entity).remove::<Hdr>();
} else {
commands.entity(entity).insert(Hdr);
}
}

let rotation = if input.pressed(KeyCode::ArrowLeft) {
@@ -318,7 +333,7 @@ fn example_control_system(

display.0 = format!(
" HDR: {}\nAlpha: {:.2}",
if camera.hdr { "ON " } else { "OFF" },
if hdr { "ON " } else { "OFF" },
state.alpha
);
}
7 changes: 3 additions & 4 deletions examples/3d/bloom_3d.rs
Original file line number Diff line number Diff line change
@@ -29,17 +29,16 @@ fn setup_scene(
commands.spawn((
Camera3d::default(),
Camera {
hdr: true, // 1. HDR is required for bloom
clear_color: ClearColorConfig::Custom(Color::BLACK),
..default()
},
Tonemapping::TonyMcMapface, // 2. Using a tonemapper that desaturates to white is recommended
Tonemapping::TonyMcMapface, // 1. Using a tonemapper that desaturates to white is recommended
Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y),
Bloom::NATURAL, // 3. Enable bloom for the camera
Bloom::NATURAL, // 2. Enable bloom for the camera
));

let material_emissive1 = materials.add(StandardMaterial {
emissive: LinearRgba::rgb(0.0, 0.0, 150.0), // 4. Put something bright in a dark environment to see the effect
emissive: LinearRgba::rgb(0.0, 0.0, 150.0), // 3. Put something bright in a dark environment to see the effect
..default()
});
let material_emissive2 = materials.add(StandardMaterial {
Loading