mirror of
https://github.com/bevyengine/bevy
synced 2024-11-25 14:10:19 +00:00
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
4f021583f1/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)
This commit is contained in:
parent
47d6e967b2
commit
1fcf6a444f
8 changed files with 24 additions and 18 deletions
|
@ -90,6 +90,13 @@ pub struct StandardMaterial {
|
|||
/// it just adds a value to the color seen on screen.
|
||||
pub emissive: Color,
|
||||
|
||||
/// The weight in which the camera exposure influences the emissive color.
|
||||
/// A value of `0.0` means the emissive color is not affected by the camera exposure.
|
||||
/// In opposition, a value of `1.0` means the emissive color is multiplied by the camera exposure.
|
||||
///
|
||||
/// Defaults to `0.0`
|
||||
pub emissive_exposure_weight: f32,
|
||||
|
||||
/// The UV channel to use for the [`StandardMaterial::emissive_texture`].
|
||||
///
|
||||
/// Defaults to [`UvChannel::Uv0`].
|
||||
|
@ -683,6 +690,7 @@ impl Default for StandardMaterial {
|
|||
base_color_channel: UvChannel::Uv0,
|
||||
base_color_texture: None,
|
||||
emissive: Color::BLACK,
|
||||
emissive_exposure_weight: 0.0,
|
||||
emissive_channel: UvChannel::Uv0,
|
||||
emissive_texture: None,
|
||||
// Matches Blender's default roughness.
|
||||
|
@ -964,9 +972,12 @@ impl AsBindGroupShaderType<StandardMaterialUniform> for StandardMaterial {
|
|||
flags |= StandardMaterialFlags::ATTENUATION_ENABLED;
|
||||
}
|
||||
|
||||
let mut emissive = LinearRgba::from(self.emissive).to_f32_array();
|
||||
emissive[3] = self.emissive_exposure_weight;
|
||||
|
||||
StandardMaterialUniform {
|
||||
base_color: LinearRgba::from(self.base_color).to_f32_array().into(),
|
||||
emissive: LinearRgba::from(self.emissive).to_f32_array().into(),
|
||||
emissive: emissive.into(),
|
||||
roughness: self.perceptual_roughness,
|
||||
metallic: self.metallic,
|
||||
reflectance: self.reflectance,
|
||||
|
|
|
@ -178,7 +178,6 @@ fn pbr_input_from_standard_material(
|
|||
pbr_input.material.alpha_cutoff = pbr_bindings::material.alpha_cutoff;
|
||||
|
||||
// emissive
|
||||
// TODO use .a for exposure compensation in HDR
|
||||
var emissive: vec4<f32> = pbr_bindings::material.emissive;
|
||||
#ifdef VERTEX_UVS
|
||||
if ((pbr_bindings::material.flags & pbr_types::STANDARD_MATERIAL_FLAGS_EMISSIVE_TEXTURE_BIT) != 0u) {
|
||||
|
@ -191,7 +190,7 @@ fn pbr_input_from_standard_material(
|
|||
uv,
|
||||
#endif
|
||||
bias,
|
||||
).rgb, 1.0);
|
||||
).rgb, emissive.a);
|
||||
}
|
||||
#endif
|
||||
pbr_input.material.emissive = emissive;
|
||||
|
|
|
@ -224,7 +224,6 @@ fn apply_pbr_lighting(
|
|||
) -> vec4<f32> {
|
||||
var output_color: vec4<f32> = in.material.base_color;
|
||||
|
||||
// TODO use .a for exposure compensation in HDR
|
||||
let emissive = in.material.emissive;
|
||||
|
||||
// calculate non-linear roughness from linear perceptualRoughness
|
||||
|
@ -564,6 +563,8 @@ fn apply_pbr_lighting(
|
|||
emissive_light = emissive_light * (0.04 + (1.0 - 0.04) * pow(1.0 - clearcoat_NdotV, 5.0));
|
||||
#endif
|
||||
|
||||
emissive_light = emissive_light * mix(1.0, view_bindings::view.exposure, emissive.a);
|
||||
|
||||
#ifdef STANDARD_MATERIAL_SPECULAR_TRANSMISSION
|
||||
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;
|
||||
|
||||
|
@ -585,7 +586,7 @@ fn apply_pbr_lighting(
|
|||
|
||||
// Total light
|
||||
output_color = vec4<f32>(
|
||||
view_bindings::view.exposure * (transmitted_light + direct_light + indirect_light + emissive_light),
|
||||
(view_bindings::view.exposure * (transmitted_light + direct_light + indirect_light)) + emissive_light,
|
||||
output_color.a
|
||||
);
|
||||
|
||||
|
|
|
@ -41,15 +41,15 @@ fn setup_scene(
|
|||
));
|
||||
|
||||
let material_emissive1 = materials.add(StandardMaterial {
|
||||
emissive: Color::linear_rgb(23000.0, 9000.0, 3000.0), // 4. Put something bright in a dark environment to see the effect
|
||||
emissive: Color::linear_rgb(13.99, 5.32, 2.0), // 4. Put something bright in a dark environment to see the effect
|
||||
..default()
|
||||
});
|
||||
let material_emissive2 = materials.add(StandardMaterial {
|
||||
emissive: Color::linear_rgb(3000.0, 23000.0, 9000.0),
|
||||
emissive: Color::linear_rgb(2.0, 13.99, 5.32),
|
||||
..default()
|
||||
});
|
||||
let material_emissive3 = materials.add(StandardMaterial {
|
||||
emissive: Color::linear_rgb(9000.0, 3000.0, 23000.0),
|
||||
emissive: Color::linear_rgb(5.32, 2.0, 13.99),
|
||||
..default()
|
||||
});
|
||||
let material_non_emissive = materials.add(StandardMaterial {
|
||||
|
|
|
@ -35,11 +35,6 @@ fn add_lightmaps_to_meshes(
|
|||
) {
|
||||
let exposure = 250.0;
|
||||
for (entity, name, material) in meshes.iter() {
|
||||
if &**name == "Light" {
|
||||
materials.get_mut(material).unwrap().emissive = Color::Srgba(Srgba::WHITE * exposure);
|
||||
continue;
|
||||
}
|
||||
|
||||
if &**name == "large_box" {
|
||||
materials.get_mut(material).unwrap().lightmap_exposure = exposure;
|
||||
commands.entity(entity).insert(Lightmap {
|
||||
|
|
|
@ -79,12 +79,12 @@ fn setup(
|
|||
let sphere_mesh_direction = meshes.add(Sphere::new(0.1).mesh().uv(32, 18));
|
||||
let red_emissive = materials.add(StandardMaterial {
|
||||
base_color: RED.into(),
|
||||
emissive: Color::linear_rgba(100.0, 0.0, 0.0, 0.0),
|
||||
emissive: Color::linear_rgba(1.0, 0.0, 0.0, 0.0),
|
||||
..default()
|
||||
});
|
||||
let maroon_emissive = materials.add(StandardMaterial {
|
||||
base_color: MAROON.into(),
|
||||
emissive: Color::linear_rgba(50.0, 0.0, 0.0, 0.0),
|
||||
emissive: Color::linear_rgba(0.369, 0.0, 0.0, 0.0),
|
||||
..default()
|
||||
});
|
||||
|
||||
|
|
|
@ -137,8 +137,8 @@ fn setup(
|
|||
));
|
||||
|
||||
// Candle Flame
|
||||
let scaled_white = LinearRgba::from(ANTIQUE_WHITE) * 80.;
|
||||
let scaled_orange = LinearRgba::from(ORANGE_RED) * 16.;
|
||||
let scaled_white = LinearRgba::from(ANTIQUE_WHITE) * 20.;
|
||||
let scaled_orange = LinearRgba::from(ORANGE_RED) * 4.;
|
||||
let emissive = LinearRgba {
|
||||
red: scaled_white.red + scaled_orange.red,
|
||||
green: scaled_white.green + scaled_orange.green,
|
||||
|
|
|
@ -99,7 +99,7 @@ fn generate_bodies(
|
|||
mesh: meshes.add(Sphere::new(1.0).mesh().ico(5).unwrap()),
|
||||
material: materials.add(StandardMaterial {
|
||||
base_color: ORANGE_RED.into(),
|
||||
emissive: (LinearRgba::from(ORANGE_RED) * 18.).into(),
|
||||
emissive: (LinearRgba::from(ORANGE_RED) * 2.).into(),
|
||||
..default()
|
||||
}),
|
||||
..default()
|
||||
|
|
Loading…
Reference in a new issue