Skip to content

Commit

Permalink
Use load_with_settings instead of manually overriding srgbness in e…
Browse files Browse the repository at this point in the history
…xamples (#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.
  • Loading branch information
rparrett authored May 16, 2024
1 parent aa907d5 commit 7cbc035
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 77 deletions.
47 changes: 12 additions & 35 deletions examples/3d/deferred_rendering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use bevy::{
NotShadowCaster, NotShadowReceiver, OpaqueRendererMethod,
},
prelude::*,
render::render_resource::TextureFormat,
render::texture::ImageLoaderSettings,
};

fn main() {
Expand All @@ -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();
}

Expand Down Expand Up @@ -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()
}),
);
Expand All @@ -244,14 +240,17 @@ fn setup_parallax(
mut commands: Commands,
mut materials: ResMut<Assets<StandardMaterial>>,
mut meshes: ResMut<Assets<Mesh>>,
mut normal: ResMut<Normal>,
asset_server: Res<AssetServer>,
) {
// 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));

Expand All @@ -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")),
Expand All @@ -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<Handle<Image>>);

// See `examples/3d/parallax_mapping.rs` example for reasoning
fn update_normal(
mut already_ran: Local<bool>,
mut images: ResMut<Assets<Image>>,
normal: Res<Normal>,
) {
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,
Expand Down
50 changes: 8 additions & 42 deletions examples/3d/parallax_mapping.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -200,14 +198,17 @@ fn setup(
mut commands: Commands,
mut materials: ResMut<Assets<StandardMaterial>>,
mut meshes: ResMut<Assets<Mesh>>,
mut normal: ResMut<Normal>,
asset_server: Res<AssetServer>,
) {
// 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((
Expand Down Expand Up @@ -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")),
Expand Down Expand Up @@ -335,38 +336,3 @@ fn setup(
}),
);
}

/// Store handle of the normal to later modify its format in [`update_normal`].
#[derive(Resource)]
struct Normal(Option<Handle<Image>>);

/// 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<bool>,
mut images: ResMut<Assets<Image>>,
normal: Res<Normal>,
) {
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;
}
}
}

0 comments on commit 7cbc035

Please sign in to comment.