Skip to content

Commit 1fcf6a4

Browse files
authored
Add emissive_exposure_weight to the StandardMaterial (#13350)
# Objective - The emissive color gets multiplied by the camera exposure value. But this cancels out almost any emissive effect. - Fixes #13133 - Closes PR #13337 ## Solution - Add emissive_exposure_weight to the StandardMaterial - In the shader this value is stored in the alpha channel of the emissive color. - This value defines how much the exposure influences the emissive color. - It's equal to Google's Filament: https://google.github.io/filament/Materials.html#emissive https://github.com/google/filament/blob/4f021583f1c721486baaa9291be5943216c244ec/shaders/src/shading_lit.fs#L287 ## Testing - The result of [EmissiveStrengthTest](https://github.com/KhronosGroup/glTF-Sample-Models/tree/main/2.0/EmissiveStrengthTest) with the default value of 0.0: without bloom: ![emissive_fix](https://github.com/bevyengine/bevy/assets/688816/8f8c131a-464a-4d7b-a9e4-4e28d679ee5d) with bloom: ![emissive_fix_bloom](https://github.com/bevyengine/bevy/assets/688816/89f200ee-3bd5-4daa-bf64-8999b56df3fa)
1 parent 47d6e96 commit 1fcf6a4

File tree

8 files changed

+24
-18
lines changed

8 files changed

+24
-18
lines changed

crates/bevy_pbr/src/pbr_material.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,13 @@ pub struct StandardMaterial {
9090
/// it just adds a value to the color seen on screen.
9191
pub emissive: Color,
9292

93+
/// The weight in which the camera exposure influences the emissive color.
94+
/// A value of `0.0` means the emissive color is not affected by the camera exposure.
95+
/// In opposition, a value of `1.0` means the emissive color is multiplied by the camera exposure.
96+
///
97+
/// Defaults to `0.0`
98+
pub emissive_exposure_weight: f32,
99+
93100
/// The UV channel to use for the [`StandardMaterial::emissive_texture`].
94101
///
95102
/// Defaults to [`UvChannel::Uv0`].
@@ -683,6 +690,7 @@ impl Default for StandardMaterial {
683690
base_color_channel: UvChannel::Uv0,
684691
base_color_texture: None,
685692
emissive: Color::BLACK,
693+
emissive_exposure_weight: 0.0,
686694
emissive_channel: UvChannel::Uv0,
687695
emissive_texture: None,
688696
// Matches Blender's default roughness.
@@ -964,9 +972,12 @@ impl AsBindGroupShaderType<StandardMaterialUniform> for StandardMaterial {
964972
flags |= StandardMaterialFlags::ATTENUATION_ENABLED;
965973
}
966974

975+
let mut emissive = LinearRgba::from(self.emissive).to_f32_array();
976+
emissive[3] = self.emissive_exposure_weight;
977+
967978
StandardMaterialUniform {
968979
base_color: LinearRgba::from(self.base_color).to_f32_array().into(),
969-
emissive: LinearRgba::from(self.emissive).to_f32_array().into(),
980+
emissive: emissive.into(),
970981
roughness: self.perceptual_roughness,
971982
metallic: self.metallic,
972983
reflectance: self.reflectance,

crates/bevy_pbr/src/render/pbr_fragment.wgsl

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,6 @@ fn pbr_input_from_standard_material(
178178
pbr_input.material.alpha_cutoff = pbr_bindings::material.alpha_cutoff;
179179

180180
// emissive
181-
// TODO use .a for exposure compensation in HDR
182181
var emissive: vec4<f32> = pbr_bindings::material.emissive;
183182
#ifdef VERTEX_UVS
184183
if ((pbr_bindings::material.flags & pbr_types::STANDARD_MATERIAL_FLAGS_EMISSIVE_TEXTURE_BIT) != 0u) {
@@ -191,7 +190,7 @@ fn pbr_input_from_standard_material(
191190
uv,
192191
#endif
193192
bias,
194-
).rgb, 1.0);
193+
).rgb, emissive.a);
195194
}
196195
#endif
197196
pbr_input.material.emissive = emissive;

crates/bevy_pbr/src/render/pbr_functions.wgsl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,6 @@ fn apply_pbr_lighting(
224224
) -> vec4<f32> {
225225
var output_color: vec4<f32> = in.material.base_color;
226226

227-
// TODO use .a for exposure compensation in HDR
228227
let emissive = in.material.emissive;
229228

230229
// calculate non-linear roughness from linear perceptualRoughness
@@ -564,6 +563,8 @@ fn apply_pbr_lighting(
564563
emissive_light = emissive_light * (0.04 + (1.0 - 0.04) * pow(1.0 - clearcoat_NdotV, 5.0));
565564
#endif
566565

566+
emissive_light = emissive_light * mix(1.0, view_bindings::view.exposure, emissive.a);
567+
567568
#ifdef STANDARD_MATERIAL_SPECULAR_TRANSMISSION
568569
transmitted_light += transmission::specular_transmissive_light(in.world_position, in.frag_coord.xyz, view_z, in.N, in.V, F0, ior, thickness, perceptual_roughness, specular_transmissive_color, specular_transmitted_environment_light).rgb;
569570

@@ -585,7 +586,7 @@ fn apply_pbr_lighting(
585586

586587
// Total light
587588
output_color = vec4<f32>(
588-
view_bindings::view.exposure * (transmitted_light + direct_light + indirect_light + emissive_light),
589+
(view_bindings::view.exposure * (transmitted_light + direct_light + indirect_light)) + emissive_light,
589590
output_color.a
590591
);
591592

examples/3d/bloom_3d.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,15 @@ fn setup_scene(
4141
));
4242

4343
let material_emissive1 = materials.add(StandardMaterial {
44-
emissive: Color::linear_rgb(23000.0, 9000.0, 3000.0), // 4. Put something bright in a dark environment to see the effect
44+
emissive: Color::linear_rgb(13.99, 5.32, 2.0), // 4. Put something bright in a dark environment to see the effect
4545
..default()
4646
});
4747
let material_emissive2 = materials.add(StandardMaterial {
48-
emissive: Color::linear_rgb(3000.0, 23000.0, 9000.0),
48+
emissive: Color::linear_rgb(2.0, 13.99, 5.32),
4949
..default()
5050
});
5151
let material_emissive3 = materials.add(StandardMaterial {
52-
emissive: Color::linear_rgb(9000.0, 3000.0, 23000.0),
52+
emissive: Color::linear_rgb(5.32, 2.0, 13.99),
5353
..default()
5454
});
5555
let material_non_emissive = materials.add(StandardMaterial {

examples/3d/lightmaps.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,6 @@ fn add_lightmaps_to_meshes(
3535
) {
3636
let exposure = 250.0;
3737
for (entity, name, material) in meshes.iter() {
38-
if &**name == "Light" {
39-
materials.get_mut(material).unwrap().emissive = Color::Srgba(Srgba::WHITE * exposure);
40-
continue;
41-
}
42-
4338
if &**name == "large_box" {
4439
materials.get_mut(material).unwrap().lightmap_exposure = exposure;
4540
commands.entity(entity).insert(Lightmap {

examples/3d/spotlight.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,12 +79,12 @@ fn setup(
7979
let sphere_mesh_direction = meshes.add(Sphere::new(0.1).mesh().uv(32, 18));
8080
let red_emissive = materials.add(StandardMaterial {
8181
base_color: RED.into(),
82-
emissive: Color::linear_rgba(100.0, 0.0, 0.0, 0.0),
82+
emissive: Color::linear_rgba(1.0, 0.0, 0.0, 0.0),
8383
..default()
8484
});
8585
let maroon_emissive = materials.add(StandardMaterial {
8686
base_color: MAROON.into(),
87-
emissive: Color::linear_rgba(50.0, 0.0, 0.0, 0.0),
87+
emissive: Color::linear_rgba(0.369, 0.0, 0.0, 0.0),
8888
..default()
8989
});
9090

examples/3d/transmission.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,8 @@ fn setup(
137137
));
138138

139139
// Candle Flame
140-
let scaled_white = LinearRgba::from(ANTIQUE_WHITE) * 80.;
141-
let scaled_orange = LinearRgba::from(ORANGE_RED) * 16.;
140+
let scaled_white = LinearRgba::from(ANTIQUE_WHITE) * 20.;
141+
let scaled_orange = LinearRgba::from(ORANGE_RED) * 4.;
142142
let emissive = LinearRgba {
143143
red: scaled_white.red + scaled_orange.red,
144144
green: scaled_white.green + scaled_orange.green,

examples/ecs/iter_combinations.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ fn generate_bodies(
9999
mesh: meshes.add(Sphere::new(1.0).mesh().ico(5).unwrap()),
100100
material: materials.add(StandardMaterial {
101101
base_color: ORANGE_RED.into(),
102-
emissive: (LinearRgba::from(ORANGE_RED) * 18.).into(),
102+
emissive: (LinearRgba::from(ORANGE_RED) * 2.).into(),
103103
..default()
104104
}),
105105
..default()

0 commit comments

Comments
 (0)