From 7cbc0357be4d21c647b0b8c2f80b1734d35257f7 Mon Sep 17 00:00:00 2001 From: Rob Parrett Date: Thu, 16 May 2024 16:26:22 -0700 Subject: [PATCH] Use `load_with_settings` instead of manually overriding srgbness in examples (#13399) # Objective `parallax_mapping` and `deferred_rendering` both use a roundabout way of manually overriding the srgbness of their normal map textures. This can now be done with `load_with_settings` in one line of code. ## Solution - Delete the override systems and use `load_with_settings` instead - Make `deferred_rendering`'s instruction text style consistent with other examples while I'm in there. (see #8478) ## Testing Tested by running with `load` instead of `load_settings` and confirming that lighting looks bad when `is_srgb` is not configured, and good when it is. ## Discussion It would arguably make more sense to configure this in a `.meta` file, but I used `load_with_settings` because that's how it was done in the `clearcoat` example and it does seem nice for documentation purposes to call this out explicitly in code. --- examples/3d/deferred_rendering.rs | 47 ++++++++--------------------- examples/3d/parallax_mapping.rs | 50 +++++-------------------------- 2 files changed, 20 insertions(+), 77 deletions(-) diff --git a/examples/3d/deferred_rendering.rs b/examples/3d/deferred_rendering.rs index 6ee41a335a..3f8e04a110 100644 --- a/examples/3d/deferred_rendering.rs +++ b/examples/3d/deferred_rendering.rs @@ -12,7 +12,7 @@ use bevy::{ NotShadowCaster, NotShadowReceiver, OpaqueRendererMethod, }, prelude::*, - render::render_resource::TextureFormat, + render::texture::ImageLoaderSettings, }; fn main() { @@ -21,13 +21,9 @@ fn main() { .insert_resource(DefaultOpaqueRendererMethod::deferred()) .insert_resource(DirectionalLightShadowMap { size: 4096 }) .add_plugins(DefaultPlugins) - .insert_resource(Normal(None)) .insert_resource(Pause(true)) .add_systems(Startup, (setup, setup_parallax)) - .add_systems( - Update, - (animate_light_direction, switch_mode, spin, update_normal), - ) + .add_systems(Update, (animate_light_direction, switch_mode, spin)) .run(); } @@ -211,14 +207,14 @@ fn setup( TextBundle::from_section( "", TextStyle { - font_size: 18.0, + font_size: 20.0, ..default() }, ) .with_style(Style { position_type: PositionType::Absolute, - top: Val::Px(10.0), - left: Val::Px(10.0), + top: Val::Px(12.0), + left: Val::Px(12.0), ..default() }), ); @@ -244,14 +240,17 @@ fn setup_parallax( mut commands: Commands, mut materials: ResMut>, mut meshes: ResMut>, - mut normal: ResMut, asset_server: Res, ) { // The normal map. Note that to generate it in the GIMP image editor, you should // open the depth map, and do Filters → Generic → Normal Map // You should enable the "flip X" checkbox. - let normal_handle = asset_server.load("textures/parallax_example/cube_normal.png"); - normal.0 = Some(normal_handle); + let normal_handle = asset_server.load_with_settings( + "textures/parallax_example/cube_normal.png", + // The normal map texture is in linear color space. Lighting won't look correct + // if `is_srgb` is `true`, which is the default. + |settings: &mut ImageLoaderSettings| settings.is_srgb = false, + ); let mut cube = Mesh::from(Cuboid::new(0.15, 0.15, 0.15)); @@ -262,7 +261,7 @@ fn setup_parallax( let parallax_material = materials.add(StandardMaterial { perceptual_roughness: 0.4, base_color_texture: Some(asset_server.load("textures/parallax_example/cube_color.png")), - normal_map_texture: normal.0.clone(), + normal_map_texture: Some(normal_handle), // The depth map is a greyscale texture where black is the highest level and // white the lowest. depth_map: Some(asset_server.load("textures/parallax_example/cube_depth.png")), @@ -281,28 +280,6 @@ fn setup_parallax( Spin { speed: 0.3 }, )); } - -/// Store handle of the normal to later modify its format in [`update_normal`]. -#[derive(Resource)] -struct Normal(Option>); - -// See `examples/3d/parallax_mapping.rs` example for reasoning -fn update_normal( - mut already_ran: Local, - mut images: ResMut>, - normal: Res, -) { - if *already_ran { - return; - } - if let Some(normal) = normal.0.as_ref() { - if let Some(image) = images.get_mut(normal) { - image.texture_descriptor.format = TextureFormat::Rgba8Unorm; - *already_ran = true; - } - } -} - #[derive(Component)] struct Spin { speed: f32, diff --git a/examples/3d/parallax_mapping.rs b/examples/3d/parallax_mapping.rs index 612b403b3e..e361ff05b5 100644 --- a/examples/3d/parallax_mapping.rs +++ b/examples/3d/parallax_mapping.rs @@ -3,18 +3,16 @@ use std::fmt; -use bevy::{prelude::*, render::render_resource::TextureFormat}; +use bevy::{prelude::*, render::texture::ImageLoaderSettings}; fn main() { App::new() .add_plugins(DefaultPlugins) - .insert_resource(Normal(None)) .add_systems(Startup, setup) .add_systems( Update, ( spin, - update_normal, move_camera, update_parallax_depth_scale, update_parallax_layers, @@ -200,14 +198,17 @@ fn setup( mut commands: Commands, mut materials: ResMut>, mut meshes: ResMut>, - mut normal: ResMut, asset_server: Res, ) { // The normal map. Note that to generate it in the GIMP image editor, you should // open the depth map, and do Filters → Generic → Normal Map // You should enable the "flip X" checkbox. - let normal_handle = asset_server.load("textures/parallax_example/cube_normal.png"); - normal.0 = Some(normal_handle); + let normal_handle = asset_server.load_with_settings( + "textures/parallax_example/cube_normal.png", + // The normal map texture is in linear color space. Lighting won't look correct + // if `is_srgb` is `true`, which is the default. + |settings: &mut ImageLoaderSettings| settings.is_srgb = false, + ); // Camera commands.spawn(( @@ -254,7 +255,7 @@ fn setup( let parallax_material = materials.add(StandardMaterial { perceptual_roughness: 0.4, base_color_texture: Some(asset_server.load("textures/parallax_example/cube_color.png")), - normal_map_texture: normal.0.clone(), + normal_map_texture: Some(normal_handle), // The depth map is a greyscale texture where black is the highest level and // white the lowest. depth_map: Some(asset_server.load("textures/parallax_example/cube_depth.png")), @@ -335,38 +336,3 @@ fn setup( }), ); } - -/// Store handle of the normal to later modify its format in [`update_normal`]. -#[derive(Resource)] -struct Normal(Option>); - -/// Work around the default bevy image loader. -/// -/// The bevy image loader used by `AssetServer` always loads images in -/// `Srgb` mode, which is usually what it should do, -/// but is incompatible with normal maps. -/// -/// Normal maps require a texture in linear color space, -/// so we overwrite the format of the normal map we loaded through `AssetServer` -/// in this system. -/// -/// Note that this method of conversion is a last resort workaround. You should -/// get your normal maps from a 3d model file, like gltf. -/// -/// In this system, we wait until the image is loaded, immediately -/// change its format and never run the logic afterward. -fn update_normal( - mut already_ran: Local, - mut images: ResMut>, - normal: Res, -) { - if *already_ran { - return; - } - if let Some(normal) = normal.0.as_ref() { - if let Some(image) = images.get_mut(normal) { - image.texture_descriptor.format = TextureFormat::Rgba8Unorm; - *already_ran = true; - } - } -}