diff --git a/assets/shaders/array_texture.wgsl b/assets/shaders/array_texture.wgsl index f67e08aa06471b..7c0216f73e5923 100644 --- a/assets/shaders/array_texture.wgsl +++ b/assets/shaders/array_texture.wgsl @@ -43,7 +43,7 @@ fn fragment( double_sided, is_front, #ifdef VERTEX_TANGENTS -#ifdef STANDARDMATERIAL_NORMAL_MAP +#ifdef STANDARD_MATERIAL_NORMAL_MAP mesh.world_tangent, #endif #endif diff --git a/crates/bevy_pbr/src/pbr_material.rs b/crates/bevy_pbr/src/pbr_material.rs index ef106c010e7933..25cb24fc144474 100644 --- a/crates/bevy_pbr/src/pbr_material.rs +++ b/crates/bevy_pbr/src/pbr_material.rs @@ -740,6 +740,8 @@ pub struct StandardMaterialKey { cull_mode: Option, depth_bias: i32, relief_mapping: bool, + diffuse_transmission: bool, + specular_transmission: bool, } impl From<&StandardMaterial> for StandardMaterialKey { @@ -752,6 +754,8 @@ impl From<&StandardMaterial> for StandardMaterialKey { material.parallax_mapping_method, ParallaxMappingMethod::Relief { .. } ), + diffuse_transmission: material.diffuse_transmission > 0.0, + specular_transmission: material.specular_transmission > 0.0, } } } @@ -811,11 +815,24 @@ impl Material for StandardMaterial { let shader_defs = &mut fragment.shader_defs; if key.bind_group_data.normal_map { - shader_defs.push("STANDARDMATERIAL_NORMAL_MAP".into()); + shader_defs.push("STANDARD_MATERIAL_NORMAL_MAP".into()); } if key.bind_group_data.relief_mapping { shader_defs.push("RELIEF_MAPPING".into()); } + + if key.bind_group_data.diffuse_transmission { + shader_defs.push("STANDARD_MATERIAL_DIFFUSE_TRANSMISSION".into()); + } + + if key.bind_group_data.specular_transmission { + shader_defs.push("STANDARD_MATERIAL_SPECULAR_TRANSMISSION".into()); + } + + if key.bind_group_data.diffuse_transmission || key.bind_group_data.specular_transmission + { + shader_defs.push("STANDARD_MATERIAL_SPECULAR_OR_DIFFUSE_TRANSMISSION".into()); + } } descriptor.primitive.cull_mode = key.bind_group_data.cull_mode; if let Some(label) = &mut descriptor.label { diff --git a/crates/bevy_pbr/src/render/pbr_fragment.wgsl b/crates/bevy_pbr/src/render/pbr_fragment.wgsl index 169d42f0a6f817..be759d38b573e9 100644 --- a/crates/bevy_pbr/src/render/pbr_fragment.wgsl +++ b/crates/bevy_pbr/src/render/pbr_fragment.wgsl @@ -190,7 +190,7 @@ fn pbr_input_from_standard_material( double_sided, is_front, #ifdef VERTEX_TANGENTS -#ifdef STANDARDMATERIAL_NORMAL_MAP +#ifdef STANDARD_MATERIAL_NORMAL_MAP in.world_tangent, #endif #endif diff --git a/crates/bevy_pbr/src/render/pbr_functions.wgsl b/crates/bevy_pbr/src/render/pbr_functions.wgsl index eca7463d9b178c..78dbc9a82a70bc 100644 --- a/crates/bevy_pbr/src/render/pbr_functions.wgsl +++ b/crates/bevy_pbr/src/render/pbr_functions.wgsl @@ -50,7 +50,7 @@ fn prepare_world_normal( ) -> vec3 { var output: vec3 = world_normal; #ifndef VERTEX_TANGENTS -#ifndef STANDARDMATERIAL_NORMAL_MAP +#ifndef STANDARD_MATERIAL_NORMAL_MAP // NOTE: When NOT using normal-mapping, if looking at the back face of a double-sided // material, the normal needs to be inverted. This is a branchless version of that. output = (f32(!double_sided || is_front) * 2.0 - 1.0) * output; @@ -65,7 +65,7 @@ fn apply_normal_mapping( double_sided: bool, is_front: bool, #ifdef VERTEX_TANGENTS -#ifdef STANDARDMATERIAL_NORMAL_MAP +#ifdef STANDARD_MATERIAL_NORMAL_MAP world_tangent: vec4, #endif #endif @@ -83,7 +83,7 @@ fn apply_normal_mapping( var N: vec3 = world_normal; #ifdef VERTEX_TANGENTS -#ifdef STANDARDMATERIAL_NORMAL_MAP +#ifdef STANDARD_MATERIAL_NORMAL_MAP // NOTE: The mikktspace method of normal mapping explicitly requires that these NOT be // normalized nor any Gram-Schmidt applied to ensure the vertex normal is orthogonal to the // vertex tangent! Do not change this code unless you really know what you are doing. @@ -95,7 +95,7 @@ fn apply_normal_mapping( #ifdef VERTEX_TANGENTS #ifdef VERTEX_UVS -#ifdef STANDARDMATERIAL_NORMAL_MAP +#ifdef STANDARD_MATERIAL_NORMAL_MAP // Nt is the tangent-space normal. var Nt = textureSampleBias(pbr_bindings::normal_map_texture, pbr_bindings::normal_map_sampler, uv, mip_bias).rgb; if (standard_material_flags & pbr_types::STANDARD_MATERIAL_FLAGS_TWO_COMPONENT_NORMAL_MAP) != 0u { @@ -213,24 +213,24 @@ fn apply_pbr_lighting( let light_contrib = lighting::point_light(in.world_position.xyz, light_id, roughness, NdotV, in.N, in.V, R, F0, f_ab, diffuse_color); direct_light += light_contrib * shadow; - if diffuse_transmission > 0.0 { - // NOTE: We use the diffuse transmissive color, the second Lambertian lobe's calculated - // world position, inverted normal and view vectors, and the following simplified - // values for a fully diffuse transmitted light contribution approximation: - // - // roughness = 1.0; - // NdotV = 1.0; - // R = vec3(0.0) // doesn't really matter - // f_ab = vec2(0.1) - // F0 = vec3(0.0) - var transmitted_shadow: f32 = 1.0; - if ((in.flags & (MESH_FLAGS_SHADOW_RECEIVER_BIT | MESH_FLAGS_TRANSMITTED_SHADOW_RECEIVER_BIT)) == (MESH_FLAGS_SHADOW_RECEIVER_BIT | MESH_FLAGS_TRANSMITTED_SHADOW_RECEIVER_BIT) - && (view_bindings::point_lights.data[light_id].flags & mesh_view_types::POINT_LIGHT_FLAGS_SHADOWS_ENABLED_BIT) != 0u) { - transmitted_shadow = shadows::fetch_point_shadow(light_id, diffuse_transmissive_lobe_world_position, -in.world_normal); - } - let light_contrib = lighting::point_light(diffuse_transmissive_lobe_world_position.xyz, light_id, 1.0, 1.0, -in.N, -in.V, vec3(0.0), vec3(0.0), vec2(0.1), diffuse_transmissive_color); - transmitted_light += light_contrib * transmitted_shadow; +#ifdef STANDARD_MATERIAL_DIFFUSE_TRANSMISSION + // NOTE: We use the diffuse transmissive color, the second Lambertian lobe's calculated + // world position, inverted normal and view vectors, and the following simplified + // values for a fully diffuse transmitted light contribution approximation: + // + // roughness = 1.0; + // NdotV = 1.0; + // R = vec3(0.0) // doesn't really matter + // f_ab = vec2(0.1) + // F0 = vec3(0.0) + var transmitted_shadow: f32 = 1.0; + if ((in.flags & (MESH_FLAGS_SHADOW_RECEIVER_BIT | MESH_FLAGS_TRANSMITTED_SHADOW_RECEIVER_BIT)) == (MESH_FLAGS_SHADOW_RECEIVER_BIT | MESH_FLAGS_TRANSMITTED_SHADOW_RECEIVER_BIT) + && (view_bindings::point_lights.data[light_id].flags & mesh_view_types::POINT_LIGHT_FLAGS_SHADOWS_ENABLED_BIT) != 0u) { + transmitted_shadow = shadows::fetch_point_shadow(light_id, diffuse_transmissive_lobe_world_position, -in.world_normal); } + let transmitted_light_contrib = lighting::point_light(diffuse_transmissive_lobe_world_position.xyz, light_id, 1.0, 1.0, -in.N, -in.V, vec3(0.0), vec3(0.0), vec2(0.1), diffuse_transmissive_color); + transmitted_light += transmitted_light_contrib * transmitted_shadow; +#endif } // Spot lights (direct) @@ -245,24 +245,24 @@ fn apply_pbr_lighting( let light_contrib = lighting::spot_light(in.world_position.xyz, light_id, roughness, NdotV, in.N, in.V, R, F0, f_ab, diffuse_color); direct_light += light_contrib * shadow; - if diffuse_transmission > 0.0 { - // NOTE: We use the diffuse transmissive color, the second Lambertian lobe's calculated - // world position, inverted normal and view vectors, and the following simplified - // values for a fully diffuse transmitted light contribution approximation: - // - // roughness = 1.0; - // NdotV = 1.0; - // R = vec3(0.0) // doesn't really matter - // f_ab = vec2(0.1) - // F0 = vec3(0.0) - var transmitted_shadow: f32 = 1.0; - if ((in.flags & (MESH_FLAGS_SHADOW_RECEIVER_BIT | MESH_FLAGS_TRANSMITTED_SHADOW_RECEIVER_BIT)) == (MESH_FLAGS_SHADOW_RECEIVER_BIT | MESH_FLAGS_TRANSMITTED_SHADOW_RECEIVER_BIT) - && (view_bindings::point_lights.data[light_id].flags & mesh_view_types::POINT_LIGHT_FLAGS_SHADOWS_ENABLED_BIT) != 0u) { - transmitted_shadow = shadows::fetch_spot_shadow(light_id, diffuse_transmissive_lobe_world_position, -in.world_normal); - } - let light_contrib = lighting::spot_light(diffuse_transmissive_lobe_world_position.xyz, light_id, 1.0, 1.0, -in.N, -in.V, vec3(0.0), vec3(0.0), vec2(0.1), diffuse_transmissive_color); - transmitted_light += light_contrib * transmitted_shadow; +#ifdef STANDARD_MATERIAL_DIFFUSE_TRANSMISSION + // NOTE: We use the diffuse transmissive color, the second Lambertian lobe's calculated + // world position, inverted normal and view vectors, and the following simplified + // values for a fully diffuse transmitted light contribution approximation: + // + // roughness = 1.0; + // NdotV = 1.0; + // R = vec3(0.0) // doesn't really matter + // f_ab = vec2(0.1) + // F0 = vec3(0.0) + var transmitted_shadow: f32 = 1.0; + if ((in.flags & (MESH_FLAGS_SHADOW_RECEIVER_BIT | MESH_FLAGS_TRANSMITTED_SHADOW_RECEIVER_BIT)) == (MESH_FLAGS_SHADOW_RECEIVER_BIT | MESH_FLAGS_TRANSMITTED_SHADOW_RECEIVER_BIT) + && (view_bindings::point_lights.data[light_id].flags & mesh_view_types::POINT_LIGHT_FLAGS_SHADOWS_ENABLED_BIT) != 0u) { + transmitted_shadow = shadows::fetch_spot_shadow(light_id, diffuse_transmissive_lobe_world_position, -in.world_normal); } + let transmitted_light_contrib = lighting::spot_light(diffuse_transmissive_lobe_world_position.xyz, light_id, 1.0, 1.0, -in.N, -in.V, vec3(0.0), vec3(0.0), vec2(0.1), diffuse_transmissive_color); + transmitted_light += transmitted_light_contrib * transmitted_shadow; +#endif } // directional lights (direct) @@ -286,41 +286,41 @@ fn apply_pbr_lighting( #endif direct_light += light_contrib * shadow; - if diffuse_transmission > 0.0 { - // NOTE: We use the diffuse transmissive color, the second Lambertian lobe's calculated - // world position, inverted normal and view vectors, and the following simplified - // values for a fully diffuse transmitted light contribution approximation: - // - // roughness = 1.0; - // NdotV = 1.0; - // R = vec3(0.0) // doesn't really matter - // f_ab = vec2(0.1) - // F0 = vec3(0.0) - var transmitted_shadow: f32 = 1.0; - if ((in.flags & (MESH_FLAGS_SHADOW_RECEIVER_BIT | MESH_FLAGS_TRANSMITTED_SHADOW_RECEIVER_BIT)) == (MESH_FLAGS_SHADOW_RECEIVER_BIT | MESH_FLAGS_TRANSMITTED_SHADOW_RECEIVER_BIT) - && (view_bindings::lights.directional_lights[i].flags & mesh_view_types::DIRECTIONAL_LIGHT_FLAGS_SHADOWS_ENABLED_BIT) != 0u) { - transmitted_shadow = shadows::fetch_directional_shadow(i, diffuse_transmissive_lobe_world_position, -in.world_normal, view_z); - } - let light_contrib = lighting::directional_light(i, 1.0, 1.0, -in.N, -in.V, vec3(0.0), vec3(0.0), vec2(0.1), diffuse_transmissive_color); - transmitted_light += light_contrib * transmitted_shadow; - } - } - - // Ambient light (indirect) - var indirect_light = ambient::ambient_light(in.world_position, in.N, in.V, NdotV, diffuse_color, F0, perceptual_roughness, diffuse_occlusion); - - if diffuse_transmission > 0.0 { +#ifdef STANDARD_MATERIAL_DIFFUSE_TRANSMISSION // NOTE: We use the diffuse transmissive color, the second Lambertian lobe's calculated // world position, inverted normal and view vectors, and the following simplified // values for a fully diffuse transmitted light contribution approximation: // - // perceptual_roughness = 1.0; + // roughness = 1.0; // NdotV = 1.0; + // R = vec3(0.0) // doesn't really matter + // f_ab = vec2(0.1) // F0 = vec3(0.0) - // diffuse_occlusion = vec3(1.0) - transmitted_light += ambient::ambient_light(diffuse_transmissive_lobe_world_position, -in.N, -in.V, 1.0, diffuse_transmissive_color, vec3(0.0), 1.0, vec3(1.0)); + var transmitted_shadow: f32 = 1.0; + if ((in.flags & (MESH_FLAGS_SHADOW_RECEIVER_BIT | MESH_FLAGS_TRANSMITTED_SHADOW_RECEIVER_BIT)) == (MESH_FLAGS_SHADOW_RECEIVER_BIT | MESH_FLAGS_TRANSMITTED_SHADOW_RECEIVER_BIT) + && (view_bindings::lights.directional_lights[i].flags & mesh_view_types::DIRECTIONAL_LIGHT_FLAGS_SHADOWS_ENABLED_BIT) != 0u) { + transmitted_shadow = shadows::fetch_directional_shadow(i, diffuse_transmissive_lobe_world_position, -in.world_normal, view_z); + } + let transmitted_light_contrib = lighting::directional_light(i, 1.0, 1.0, -in.N, -in.V, vec3(0.0), vec3(0.0), vec2(0.1), diffuse_transmissive_color); + transmitted_light += transmitted_light_contrib * transmitted_shadow; +#endif } + // Ambient light (indirect) + var indirect_light = ambient::ambient_light(in.world_position, in.N, in.V, NdotV, diffuse_color, F0, perceptual_roughness, diffuse_occlusion); + +#ifdef STANDARD_MATERIAL_DIFFUSE_TRANSMISSION + // NOTE: We use the diffuse transmissive color, the second Lambertian lobe's calculated + // world position, inverted normal and view vectors, and the following simplified + // values for a fully diffuse transmitted light contribution approximation: + // + // perceptual_roughness = 1.0; + // NdotV = 1.0; + // F0 = vec3(0.0) + // diffuse_occlusion = vec3(1.0) + transmitted_light += ambient::ambient_light(diffuse_transmissive_lobe_world_position, -in.N, -in.V, 1.0, diffuse_transmissive_color, vec3(0.0), 1.0, vec3(1.0)); +#endif + // Environment map light (indirect) #ifdef ENVIRONMENT_MAP let environment_light = environment_map::environment_map_light( @@ -339,38 +339,42 @@ fn apply_pbr_lighting( // light in the call to `specular_transmissive_light()` below var specular_transmitted_environment_light = vec3(0.0); - if diffuse_transmission > 0.0 || specular_transmission > 0.0 { - // NOTE: We use the diffuse transmissive color, inverted normal and view vectors, - // and the following simplified values for the transmitted environment light contribution - // approximation: - // - // diffuse_color = vec3(1.0) // later we use `diffuse_transmissive_color` and `specular_transmissive_color` - // NdotV = 1.0; - // R = T // see definition below - // F0 = vec3(1.0) - // diffuse_occlusion = 1.0 - // - // (This one is slightly different from the other light types above, because the environment - // map light returns both diffuse and specular components separately, and we want to use both) - - let T = -normalize( - in.V + // start with view vector at entry point - refract(in.V, -in.N, 1.0 / ior) * thickness // add refracted vector scaled by thickness, towards exit point - ); // normalize to find exit point view vector - - let transmitted_environment_light = bevy_pbr::environment_map::environment_map_light( - perceptual_roughness, - roughness, - vec3(1.0), - 1.0, - f_ab, - -in.N, - T, - vec3(1.0), - in.world_position.xyz); - transmitted_light += transmitted_environment_light.diffuse * diffuse_transmissive_color; - specular_transmitted_environment_light = transmitted_environment_light.specular * specular_transmissive_color; - } +#ifdef STANDARD_MATERIAL_SPECULAR_OR_DIFFUSE_TRANSMISSION + // NOTE: We use the diffuse transmissive color, inverted normal and view vectors, + // and the following simplified values for the transmitted environment light contribution + // approximation: + // + // diffuse_color = vec3(1.0) // later we use `diffuse_transmissive_color` and `specular_transmissive_color` + // NdotV = 1.0; + // R = T // see definition below + // F0 = vec3(1.0) + // diffuse_occlusion = 1.0 + // + // (This one is slightly different from the other light types above, because the environment + // map light returns both diffuse and specular components separately, and we want to use both) + + let T = -normalize( + in.V + // start with view vector at entry point + refract(in.V, -in.N, 1.0 / ior) * thickness // add refracted vector scaled by thickness, towards exit point + ); // normalize to find exit point view vector + + let transmitted_environment_light = bevy_pbr::environment_map::environment_map_light( + perceptual_roughness, + roughness, + vec3(1.0), + 1.0, + f_ab, + -in.N, + T, + vec3(1.0), + in.world_position.xyz); +#ifdef STANDARD_MATERIAL_DIFFUSE_TRANSMISSION + transmitted_light += transmitted_environment_light.diffuse * diffuse_transmissive_color; +#endif +#ifdef STANDARD_MATERIAL_SPECULAR_TRANSMISSION + specular_transmitted_environment_light = transmitted_environment_light.specular * specular_transmissive_color; +#endif +#endif // STANDARD_MATERIAL_SPECULAR_OR_DIFFUSE_TRANSMISSION #else // If there's no environment map light, there's no transmitted environment // light specular component, so we can just hardcode it to zero. @@ -383,9 +387,8 @@ fn apply_pbr_lighting( let emissive_light = emissive.rgb * output_color.a; - if specular_transmission > 0.0 { - 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; - } +#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; if (in.material.flags & pbr_types::STANDARD_MATERIAL_FLAGS_ATTENUATION_ENABLED_BIT) != 0u { // We reuse the `atmospheric_fog()` function here, as it's fundamentally @@ -401,6 +404,7 @@ fn apply_pbr_lighting( vec3(0.0) // TODO: Pass in (pre-attenuated) scattered light contribution here ).rgb; } +#endif // Total light output_color = vec4( diff --git a/crates/bevy_pbr/src/render/pbr_prepass.wgsl b/crates/bevy_pbr/src/render/pbr_prepass.wgsl index e17826a3f44308..8be86b5af2175d 100644 --- a/crates/bevy_pbr/src/render/pbr_prepass.wgsl +++ b/crates/bevy_pbr/src/render/pbr_prepass.wgsl @@ -38,9 +38,9 @@ fn fragment( double_sided, is_front, #ifdef VERTEX_TANGENTS -#ifdef STANDARDMATERIAL_NORMAL_MAP +#ifdef STANDARD_MATERIAL_NORMAL_MAP in.world_tangent, -#endif // STANDARDMATERIAL_NORMAL_MAP +#endif // STANDARD_MATERIAL_NORMAL_MAP #endif // VERTEX_TANGENTS #ifdef VERTEX_UVS in.uv,