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:

with bloom:

			
			
This commit is contained in:
		
							parent
							
								
									47d6e967b2
								
							
						
					
					
						commit
						1fcf6a444f
					
				| @ -90,6 +90,13 @@ pub struct StandardMaterial { | |||||||
|     /// it just adds a value to the color seen on screen.
 |     /// it just adds a value to the color seen on screen.
 | ||||||
|     pub emissive: Color, |     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`].
 |     /// The UV channel to use for the [`StandardMaterial::emissive_texture`].
 | ||||||
|     ///
 |     ///
 | ||||||
|     /// Defaults to [`UvChannel::Uv0`].
 |     /// Defaults to [`UvChannel::Uv0`].
 | ||||||
| @ -683,6 +690,7 @@ impl Default for StandardMaterial { | |||||||
|             base_color_channel: UvChannel::Uv0, |             base_color_channel: UvChannel::Uv0, | ||||||
|             base_color_texture: None, |             base_color_texture: None, | ||||||
|             emissive: Color::BLACK, |             emissive: Color::BLACK, | ||||||
|  |             emissive_exposure_weight: 0.0, | ||||||
|             emissive_channel: UvChannel::Uv0, |             emissive_channel: UvChannel::Uv0, | ||||||
|             emissive_texture: None, |             emissive_texture: None, | ||||||
|             // Matches Blender's default roughness.
 |             // Matches Blender's default roughness.
 | ||||||
| @ -964,9 +972,12 @@ impl AsBindGroupShaderType<StandardMaterialUniform> for StandardMaterial { | |||||||
|             flags |= StandardMaterialFlags::ATTENUATION_ENABLED; |             flags |= StandardMaterialFlags::ATTENUATION_ENABLED; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         let mut emissive = LinearRgba::from(self.emissive).to_f32_array(); | ||||||
|  |         emissive[3] = self.emissive_exposure_weight; | ||||||
|  | 
 | ||||||
|         StandardMaterialUniform { |         StandardMaterialUniform { | ||||||
|             base_color: LinearRgba::from(self.base_color).to_f32_array().into(), |             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, |             roughness: self.perceptual_roughness, | ||||||
|             metallic: self.metallic, |             metallic: self.metallic, | ||||||
|             reflectance: self.reflectance, |             reflectance: self.reflectance, | ||||||
|  | |||||||
| @ -178,7 +178,6 @@ fn pbr_input_from_standard_material( | |||||||
|         pbr_input.material.alpha_cutoff = pbr_bindings::material.alpha_cutoff; |         pbr_input.material.alpha_cutoff = pbr_bindings::material.alpha_cutoff; | ||||||
| 
 | 
 | ||||||
|         // emissive |         // emissive | ||||||
|         // TODO use .a for exposure compensation in HDR |  | ||||||
|         var emissive: vec4<f32> = pbr_bindings::material.emissive; |         var emissive: vec4<f32> = pbr_bindings::material.emissive; | ||||||
| #ifdef VERTEX_UVS | #ifdef VERTEX_UVS | ||||||
|         if ((pbr_bindings::material.flags & pbr_types::STANDARD_MATERIAL_FLAGS_EMISSIVE_TEXTURE_BIT) != 0u) { |         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, |                 uv, | ||||||
| #endif | #endif | ||||||
|                 bias, |                 bias, | ||||||
|             ).rgb, 1.0); |             ).rgb, emissive.a); | ||||||
|         } |         } | ||||||
| #endif | #endif | ||||||
|         pbr_input.material.emissive = emissive; |         pbr_input.material.emissive = emissive; | ||||||
|  | |||||||
| @ -224,7 +224,6 @@ fn apply_pbr_lighting( | |||||||
| ) -> vec4<f32> { | ) -> vec4<f32> { | ||||||
|     var output_color: vec4<f32> = in.material.base_color; |     var output_color: vec4<f32> = in.material.base_color; | ||||||
| 
 | 
 | ||||||
|     // TODO use .a for exposure compensation in HDR |  | ||||||
|     let emissive = in.material.emissive; |     let emissive = in.material.emissive; | ||||||
| 
 | 
 | ||||||
|     // calculate non-linear roughness from linear perceptualRoughness |     // 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)); |     emissive_light = emissive_light * (0.04 + (1.0 - 0.04) * pow(1.0 - clearcoat_NdotV, 5.0)); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  |     emissive_light = emissive_light * mix(1.0, view_bindings::view.exposure, emissive.a); | ||||||
|  | 
 | ||||||
| #ifdef STANDARD_MATERIAL_SPECULAR_TRANSMISSION | #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; |     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 |     // Total light | ||||||
|     output_color = vec4<f32>( |     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 |         output_color.a | ||||||
|     ); |     ); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -41,15 +41,15 @@ fn setup_scene( | |||||||
|     )); |     )); | ||||||
| 
 | 
 | ||||||
|     let material_emissive1 = materials.add(StandardMaterial { |     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() |         ..default() | ||||||
|     }); |     }); | ||||||
|     let material_emissive2 = materials.add(StandardMaterial { |     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() |         ..default() | ||||||
|     }); |     }); | ||||||
|     let material_emissive3 = materials.add(StandardMaterial { |     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() |         ..default() | ||||||
|     }); |     }); | ||||||
|     let material_non_emissive = materials.add(StandardMaterial { |     let material_non_emissive = materials.add(StandardMaterial { | ||||||
|  | |||||||
| @ -35,11 +35,6 @@ fn add_lightmaps_to_meshes( | |||||||
| ) { | ) { | ||||||
|     let exposure = 250.0; |     let exposure = 250.0; | ||||||
|     for (entity, name, material) in meshes.iter() { |     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" { |         if &**name == "large_box" { | ||||||
|             materials.get_mut(material).unwrap().lightmap_exposure = exposure; |             materials.get_mut(material).unwrap().lightmap_exposure = exposure; | ||||||
|             commands.entity(entity).insert(Lightmap { |             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 sphere_mesh_direction = meshes.add(Sphere::new(0.1).mesh().uv(32, 18)); | ||||||
|     let red_emissive = materials.add(StandardMaterial { |     let red_emissive = materials.add(StandardMaterial { | ||||||
|         base_color: RED.into(), |         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() |         ..default() | ||||||
|     }); |     }); | ||||||
|     let maroon_emissive = materials.add(StandardMaterial { |     let maroon_emissive = materials.add(StandardMaterial { | ||||||
|         base_color: MAROON.into(), |         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() |         ..default() | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -137,8 +137,8 @@ fn setup( | |||||||
|     )); |     )); | ||||||
| 
 | 
 | ||||||
|     // Candle Flame
 |     // Candle Flame
 | ||||||
|     let scaled_white = LinearRgba::from(ANTIQUE_WHITE) * 80.; |     let scaled_white = LinearRgba::from(ANTIQUE_WHITE) * 20.; | ||||||
|     let scaled_orange = LinearRgba::from(ORANGE_RED) * 16.; |     let scaled_orange = LinearRgba::from(ORANGE_RED) * 4.; | ||||||
|     let emissive = LinearRgba { |     let emissive = LinearRgba { | ||||||
|         red: scaled_white.red + scaled_orange.red, |         red: scaled_white.red + scaled_orange.red, | ||||||
|         green: scaled_white.green + scaled_orange.green, |         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()), |                     mesh: meshes.add(Sphere::new(1.0).mesh().ico(5).unwrap()), | ||||||
|                     material: materials.add(StandardMaterial { |                     material: materials.add(StandardMaterial { | ||||||
|                         base_color: ORANGE_RED.into(), |                         base_color: ORANGE_RED.into(), | ||||||
|                         emissive: (LinearRgba::from(ORANGE_RED) * 18.).into(), |                         emissive: (LinearRgba::from(ORANGE_RED) * 2.).into(), | ||||||
|                         ..default() |                         ..default() | ||||||
|                     }), |                     }), | ||||||
|                     ..default() |                     ..default() | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Johannes Hackel
						Johannes Hackel