diff --git a/crates/bevy_core_pipeline/src/tonemapping/mod.rs b/crates/bevy_core_pipeline/src/tonemapping/mod.rs index 939307725760d..c66aa02022038 100644 --- a/crates/bevy_core_pipeline/src/tonemapping/mod.rs +++ b/crates/bevy_core_pipeline/src/tonemapping/mod.rs @@ -86,12 +86,12 @@ pub struct TonemappingPipeline { #[reflect(FromReflect)] pub enum TonemappingMethod { None, - /// Suffers from lots of hue shifting, brights don't desaturate naturally. + /// Suffers from lots hue shifting, brights don't desaturate naturally. Reinhard, /// Old bevy default. Suffers from hue shifting, brights don't desaturate much at all. ReinhardLuminance, /// Bad - ACES, + Aces, /// Very Good AgX, /// Also good @@ -123,7 +123,7 @@ impl SpecializedRenderPipeline for TonemappingPipeline { TonemappingMethod::ReinhardLuminance => { shader_defs.push("TONEMAP_METHOD_REINHARD_LUMINANCE".into()); } - TonemappingMethod::ACES => shader_defs.push("TONEMAP_METHOD_ACES".into()), + TonemappingMethod::Aces => shader_defs.push("TONEMAP_METHOD_ACES".into()), TonemappingMethod::AgX => shader_defs.push("TONEMAP_METHOD_AGX".into()), TonemappingMethod::SomewhatBoringDisplayTransform => { shader_defs.push("TONEMAP_METHOD_SOMEWHAT_BORING_DISPLAY_TRANSFORM".into()) @@ -264,7 +264,7 @@ pub fn get_lut_bindings<'a>( TonemappingMethod::None | TonemappingMethod::Reinhard | TonemappingMethod::ReinhardLuminance - | TonemappingMethod::ACES + | TonemappingMethod::Aces | TonemappingMethod::AgX | TonemappingMethod::SomewhatBoringDisplayTransform => &tonemapping_luts.agx, TonemappingMethod::TonyMcMapface => &tonemapping_luts.tony_mc_mapface, diff --git a/crates/bevy_pbr/src/material.rs b/crates/bevy_pbr/src/material.rs index 300c3bb009aae..ae6c37f20c36b 100644 --- a/crates/bevy_pbr/src/material.rs +++ b/crates/bevy_pbr/src/material.rs @@ -417,7 +417,7 @@ pub fn queue_material_meshes( TonemappingMethod::ReinhardLuminance => { MeshPipelineKey::TONEMAP_METHOD_REINHARD_LUMINANCE } - TonemappingMethod::ACES => MeshPipelineKey::TONEMAP_METHOD_ACES, + TonemappingMethod::Aces => MeshPipelineKey::TONEMAP_METHOD_ACES, TonemappingMethod::AgX => MeshPipelineKey::TONEMAP_METHOD_AGX, TonemappingMethod::SomewhatBoringDisplayTransform => { MeshPipelineKey::TONEMAP_METHOD_SOMEWHAT_BORING_DISPLAY_TRANSFORM diff --git a/crates/bevy_sprite/src/mesh2d/material.rs b/crates/bevy_sprite/src/mesh2d/material.rs index b9ddf7b46075f..e605d137812e8 100644 --- a/crates/bevy_sprite/src/mesh2d/material.rs +++ b/crates/bevy_sprite/src/mesh2d/material.rs @@ -359,7 +359,7 @@ pub fn queue_material2d_meshes( TonemappingMethod::ReinhardLuminance => { Mesh2dPipelineKey::TONEMAP_METHOD_REINHARD_LUMINANCE } - TonemappingMethod::ACES => Mesh2dPipelineKey::TONEMAP_METHOD_ACES, + TonemappingMethod::Aces => Mesh2dPipelineKey::TONEMAP_METHOD_ACES, TonemappingMethod::AgX => Mesh2dPipelineKey::TONEMAP_METHOD_AGX, TonemappingMethod::SomewhatBoringDisplayTransform => { Mesh2dPipelineKey::TONEMAP_METHOD_SOMEWHAT_BORING_DISPLAY_TRANSFORM diff --git a/examples/3d/tonemapping.rs b/examples/3d/tonemapping.rs index 4a335d2b3a4f9..c4a7a622f718a 100644 --- a/examples/3d/tonemapping.rs +++ b/examples/3d/tonemapping.rs @@ -1,5 +1,7 @@ //! This examples compares Tonemapping options +use std::f32::consts::PI; + use bevy::{ core_pipeline::tonemapping::{Tonemapping, TonemappingMethod}, math::vec2, @@ -13,77 +15,108 @@ use bevy::{ texture::ImageSampler, view::ColorGrading, }, + utils::HashMap, }; -use std::f32::consts::PI; fn main() { App::new() - .add_plugins(DefaultPlugins) - .add_plugin(MaterialPlugin::::default()) - .insert_resource(CameraTransform( + .add_plugins(DefaultPlugins.set(AssetPlugin { + // Tell the asset server to watch for asset changes on disk: + watch_for_changes: true, + ..default() + })) + .add_plugin(MaterialPlugin::::default()) + .insert_resource(CamTrans( Transform::from_xyz(0.7, 0.7, 1.0).looking_at(Vec3::new(0.0, 0.3, 0.0), Vec3::Y), )) - .insert_resource(CurrentScene(1)) - .add_startup_system(setup) - .add_startup_system(setup_basic_scene) - .add_startup_system(setup_color_gradient_scene) - .add_startup_system(setup_image_viewer_scene) - .add_system(update_image_viewer) + .add_startup_system(setup_camera) + .add_startup_system(scene1) + .add_startup_system(scene2) + .add_startup_system(scene3) + .add_system(hdr_viewer) .add_system(toggle_scene) - .add_system(toggle_tonemapping_method) + .add_system(toggle_tonemapping) .add_system(update_color_grading_settings) - .add_system(update_ui) .run(); } -fn setup( - mut commands: Commands, - asset_server: Res, - camera_transform: Res, -) { +#[derive(Component)] +struct Scene(u32); + +#[derive(Component)] +struct HDRViewer; + +#[derive(Resource)] +struct CamTrans(Transform); + +fn setup_camera(mut commands: Commands, asset_server: Res, cam_trans: Res) { + println!("Toggle with:"); + println!("1 - Flight helmet and simple 3D shapes"); + println!("2 - Image viewer"); + println!("3 - Color Sweep"); + + println!(); + + println!("B - Bypass"); + println!("4 - Reinhard"); + println!("5 - Reinhard Luminance (old bevy default)"); + println!("6 - ACES"); + println!("7 - AgX"); + println!("8 - SomewhatBoringDisplayTransform"); + println!("9 - TonyMcMapface"); + println!("0 - Blender Filmic"); + // camera - commands.spawn(( - Camera3dBundle { + commands + .spawn(Camera3dBundle { camera: Camera { - hdr: true, + hdr: true, // Works with and without hdr ..default() }, + transform: cam_trans.0, + tonemapping: Tonemapping::Enabled { + deband_dither: true, + method: TonemappingMethod::ReinhardLuminance, + }, color_grading: ColorGrading { + // to initially match other tonemappers exposure: 0.5, ..default() }, - transform: camera_transform.0, ..default() - }, - EnvironmentMapLight { + }) + .insert(EnvironmentMapLight { diffuse_map: asset_server.load("environment_maps/pisa_diffuse_rgb9e5_zstd.ktx2"), specular_map: asset_server.load("environment_maps/pisa_specular_rgb9e5_zstd.ktx2"), - }, - )); + }); - // ui - commands.spawn( - TextBundle::from_section( - "", - TextStyle { - font: asset_server.load("fonts/FiraMono-Medium.ttf"), - font_size: 18.0, - color: Color::WHITE, - }, - ) - .with_style(Style { - position_type: PositionType::Absolute, - position: UiRect { - top: Val::Px(10.0), - left: Val::Px(10.0), + commands + .spawn( + TextBundle::from_section( + "", + TextStyle { + font: asset_server.load("fonts/FiraMono-Medium.ttf"), + font_size: 18.0, + color: Color::BLACK, + }, + ) + .with_style(Style { + position_type: PositionType::Absolute, + position: UiRect { + top: Val::Px(10.0), + left: Val::Px(10.0), + ..default() + }, ..default() - }, - ..default() - }), - ); + }), + ) + .insert(ControlsUI); } -fn setup_basic_scene( +#[derive(Component)] +struct ControlsUI; + +fn scene1( mut commands: Commands, mut meshes: ResMut>, mut materials: ResMut>, @@ -104,14 +137,15 @@ fn setup_basic_scene( }), ..default() }, - SceneNumber(1), + Scene(1), )); - // cubes let cube_material = materials.add(StandardMaterial { base_color_texture: Some(images.add(uv_debug_texture())), ..default() }); + + // cubes for i in 0..5 { commands.spawn(( PbrBundle { @@ -120,7 +154,7 @@ fn setup_basic_scene( transform: Transform::from_xyz(i as f32 * 0.25 - 1.0, 0.125, -i as f32 * 0.5), ..default() }, - SceneNumber(1), + Scene(1), )); } @@ -165,7 +199,7 @@ fn setup_basic_scene( ), ..default() }, - SceneNumber(1), + Scene(1), )); } @@ -176,7 +210,7 @@ fn setup_basic_scene( transform: Transform::from_xyz(-0.5, 0.0, 0.25), ..default() }, - SceneNumber(1), + Scene(1), )); // light @@ -201,91 +235,68 @@ fn setup_basic_scene( .into(), ..default() }, - SceneNumber(1), + Scene(1), )); } -fn setup_color_gradient_scene( +fn scene2( mut commands: Commands, mut meshes: ResMut>, - mut materials: ResMut>, - camera_transform: Res, + mut materials: ResMut>, + cam_trans: Res, ) { - let mut transform = camera_transform.0; + let mut transform = cam_trans.0; transform.translation += transform.forward(); + // exr/hdr viewer (exr requires enabling bevy feature) commands.spawn(( - MaterialMeshBundle { + PbrBundle { mesh: meshes.add(Mesh::from(shape::Quad { - size: vec2(1.0, 1.0) * 0.7, + size: vec2(1.0, 1.0), flip: false, })), - material: materials.add(ColorGradientMaterial {}), + material: materials.add(StandardMaterial { + base_color_texture: None, + unlit: true, + ..default() + }), transform, visibility: Visibility::Hidden, ..default() }, - SceneNumber(2), + Scene(2), + HDRViewer, )); } -fn setup_image_viewer_scene( +fn scene3( mut commands: Commands, mut meshes: ResMut>, - mut materials: ResMut>, - camera_transform: Res, - asset_server: Res, + mut materials: ResMut>, + cam_trans: Res, ) { - let mut transform = camera_transform.0; + let mut transform = cam_trans.0; transform.translation += transform.forward(); - - // exr/hdr viewer (exr requires enabling bevy feature) + // exr/hdr viewer commands.spawn(( - PbrBundle { + MaterialMeshBundle { mesh: meshes.add(Mesh::from(shape::Quad { - size: vec2(1.0, 1.0), + size: vec2(1.0, 1.0) * 0.7, flip: false, })), - material: materials.add(StandardMaterial { - base_color_texture: None, - unlit: true, - ..default() - }), + material: materials.add(TestMaterial {}), transform, visibility: Visibility::Hidden, ..default() }, - SceneNumber(3), + Scene(3), HDRViewer, )); - - commands - .spawn(( - TextBundle::from_section( - "Drag and drop an HDR or EXR file", - TextStyle { - font: asset_server.load("fonts/FiraMono-Medium.ttf"), - font_size: 36.0, - color: Color::BLACK, - }, - ) - .with_text_alignment(TextAlignment::Center) - .with_style(Style { - align_self: AlignSelf::Center, - margin: UiRect::all(Val::Auto), - ..default() - }), - SceneNumber(3), - )) - .insert(Visibility::Hidden); } -// ---------------------------------------------------------------------------- - #[allow(clippy::too_many_arguments)] -fn update_image_viewer( - image_mesh: Query<(&Handle, &Handle), With>, - text: Query, With)>, +fn hdr_viewer( + query: Query<(&Handle, &Handle), With>, mut materials: ResMut>, mut meshes: ResMut>, images: Res>, @@ -293,7 +304,6 @@ fn update_image_viewer( mut drop_hovered: Local, asset_server: Res, mut image_events: EventReader>, - mut commands: Commands, ) { let mut new_image: Option> = None; @@ -308,12 +318,11 @@ fn update_image_viewer( } } - for (mat_h, mesh_h) in &image_mesh { + for (mat_h, mesh_h) in &query { if let Some(mat) = materials.get_mut(mat_h) { if let Some(ref new_image) = new_image { + // Update texture mat.base_color_texture = Some(new_image.clone()); - - commands.entity(text.single()).despawn(); } for event in image_events.iter() { @@ -336,11 +345,7 @@ fn update_image_viewer( } } -fn toggle_scene( - keys: Res>, - mut query: Query<(&mut Visibility, &SceneNumber)>, - mut current_scene: ResMut, -) { +fn toggle_scene(keys: Res>, mut query: Query<(&mut Visibility, &Scene)>) { let mut pressed = None; if keys.just_pressed(KeyCode::Key1) { pressed = Some(1); @@ -349,215 +354,285 @@ fn toggle_scene( } else if keys.just_pressed(KeyCode::Key3) { pressed = Some(3); } - if let Some(pressed) = pressed { - current_scene.0 = pressed; - - for (mut visibility, scene) in query.iter_mut() { + for (mut vis, scene) in query.iter_mut() { if scene.0 == pressed { - *visibility = Visibility::Visible; + *vis = Visibility::Visible; } else { - *visibility = Visibility::Hidden; + *vis = Visibility::Hidden; } } } } -fn toggle_tonemapping_method( - keys: Res>, - mut tonemapping: Query<&mut Tonemapping>, - mut color_grading: Query<&mut ColorGrading>, -) { - let Tonemapping::Enabled { method, .. } = &mut *tonemapping.single_mut() else { unreachable!() }; - let mut color_grading = color_grading.single_mut(); - - if keys.just_pressed(KeyCode::Q) { - *method = TonemappingMethod::None; - } else if keys.just_pressed(KeyCode::W) { - *method = TonemappingMethod::Reinhard; - } else if keys.just_pressed(KeyCode::E) { - *method = TonemappingMethod::ReinhardLuminance; - } else if keys.just_pressed(KeyCode::R) { - *method = TonemappingMethod::ACES; - } else if keys.just_pressed(KeyCode::T) { - *method = TonemappingMethod::AgX; - } else if keys.just_pressed(KeyCode::Y) { - *method = TonemappingMethod::SomewhatBoringDisplayTransform; - } else if keys.just_pressed(KeyCode::U) { - *method = TonemappingMethod::TonyMcMapface; - } else if keys.just_pressed(KeyCode::I) { - *method = TonemappingMethod::BlenderFilmic; +fn toggle_tonemapping(keys: Res>, mut query: Query<&mut Tonemapping>) { + if let Some(mut tonemapping) = query.iter_mut().next() { + if keys.just_pressed(KeyCode::B) { + *tonemapping = Tonemapping::Enabled { + deband_dither: true, + method: TonemappingMethod::None, + }; + println!("Bypass"); + } else if keys.just_pressed(KeyCode::Key4) { + *tonemapping = Tonemapping::Enabled { + deband_dither: true, + method: TonemappingMethod::Reinhard, + }; + println!("Reinhard"); + } else if keys.just_pressed(KeyCode::Key5) { + *tonemapping = Tonemapping::Enabled { + deband_dither: true, + method: TonemappingMethod::ReinhardLuminance, + }; + println!("ReinhardLuminance (old bevy default)"); + } else if keys.just_pressed(KeyCode::Key6) { + *tonemapping = Tonemapping::Enabled { + deband_dither: true, + method: TonemappingMethod::Aces, + }; + println!("Aces"); + } else if keys.just_pressed(KeyCode::Key7) { + *tonemapping = Tonemapping::Enabled { + deband_dither: true, + method: TonemappingMethod::AgX, + }; + println!("AgX"); + } else if keys.just_pressed(KeyCode::Key8) { + *tonemapping = Tonemapping::Enabled { + deband_dither: true, + method: TonemappingMethod::SomewhatBoringDisplayTransform, + }; + println!("SomewhatBoringDisplayTransform"); + } else if keys.just_pressed(KeyCode::Key9) { + *tonemapping = Tonemapping::Enabled { + deband_dither: true, + method: TonemappingMethod::TonyMcMapface, + }; + println!("TonyMcMapface"); + } else if keys.just_pressed(KeyCode::Key0) { + *tonemapping = Tonemapping::Enabled { + deband_dither: true, + method: TonemappingMethod::BlenderFilmic, + }; + println!("Blender Filmic"); + } } +} + +pub struct PerMethodSettings { + pub settings: HashMap, +} - if keys.just_pressed(KeyCode::Q) - || keys.just_pressed(KeyCode::W) - || keys.just_pressed(KeyCode::E) - || keys.just_pressed(KeyCode::R) - || keys.just_pressed(KeyCode::T) - || keys.just_pressed(KeyCode::Y) - || keys.just_pressed(KeyCode::U) - || keys.just_pressed(KeyCode::I) - { - *color_grading = match method { - TonemappingMethod::Reinhard | TonemappingMethod::ReinhardLuminance => ColorGrading { +impl Default for PerMethodSettings { + fn default() -> Self { + let mut settings = HashMap::new(); + + settings.insert(TonemappingMethod::None, ColorGrading::default()); + settings.insert(TonemappingMethod::Reinhard, ColorGrading::default()); + settings.insert( + TonemappingMethod::ReinhardLuminance, + ColorGrading::default(), + ); + settings.insert(TonemappingMethod::Aces, ColorGrading::default()); + settings.insert(TonemappingMethod::AgX, ColorGrading::default()); + settings.insert( + TonemappingMethod::SomewhatBoringDisplayTransform, + ColorGrading::default(), + ); + settings.insert(TonemappingMethod::TonyMcMapface, ColorGrading::default()); + settings.insert(TonemappingMethod::BlenderFilmic, ColorGrading::default()); + + Self { settings } + } +} + +impl PerMethodSettings { + fn matched() -> Self { + // Settings to somewhat match the tone mappers, especially in exposure, for this specific scene. + let mut settings = HashMap::new(); + + settings.insert(TonemappingMethod::None, ColorGrading::default()); + settings.insert( + TonemappingMethod::Reinhard, + ColorGrading { + exposure: 0.5, + ..default() + }, + ); + settings.insert( + TonemappingMethod::ReinhardLuminance, + ColorGrading { exposure: 0.5, ..default() }, - TonemappingMethod::ACES => ColorGrading { + ); + settings.insert( + TonemappingMethod::Aces, + ColorGrading { exposure: -0.3, ..default() }, - TonemappingMethod::AgX => ColorGrading { + ); + settings.insert( + TonemappingMethod::AgX, + ColorGrading { exposure: -0.2, gamma: 1.0, pre_saturation: 1.1, post_saturation: 1.1, }, - _ => ColorGrading::default(), - }; + ); + settings.insert( + TonemappingMethod::SomewhatBoringDisplayTransform, + ColorGrading { + exposure: 0.0, + ..default() + }, + ); + settings.insert( + TonemappingMethod::TonyMcMapface, + ColorGrading { + exposure: 0.0, + ..default() + }, + ); + settings.insert( + TonemappingMethod::BlenderFilmic, + ColorGrading { + exposure: 0.0, + ..default() + }, + ); + + Self { settings } } } fn update_color_grading_settings( - keys: Res>, - time: Res