From dc1f76d9a2cf531e03c2c17b15461a3a63b1586b Mon Sep 17 00:00:00 2001 From: Marco Buono Date: Tue, 31 Oct 2023 06:44:40 -0300 Subject: [PATCH] Fix handling of `double_sided` for normal maps (#10326) # Objective Right now, we flip the `world_normal` in response to `double_sided && !is_front`, however when calculating `N` from tangents and the normal map, we don't flip the normal read from the normal map, which produces extremely weird results. ## Solution - Pass `double_sided` and `is_front` flags to the `apply_normal_mapping()` function and use them to conditionally flip `Nt` ## Comparison Note: These are from a custom scene running with the `transmission` branch, (#8015) I noticed lighting got pretty weird for the back side of translucent `double_sided` materials whenever I added a normal map. ### Before Screenshot 2023-10-31 at 01 26 06 ### After Screenshot 2023-10-31 at 01 25 42 --- ## Changelog - Fixed a bug where `StandardMaterial::double_sided` would interact incorrectly with normal maps, producing broken results. --- crates/bevy_pbr/src/render/pbr_fragment.wgsl | 2 ++ crates/bevy_pbr/src/render/pbr_functions.wgsl | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/crates/bevy_pbr/src/render/pbr_fragment.wgsl b/crates/bevy_pbr/src/render/pbr_fragment.wgsl index 47d4f6f6d8..d783d3bca5 100644 --- a/crates/bevy_pbr/src/render/pbr_fragment.wgsl +++ b/crates/bevy_pbr/src/render/pbr_fragment.wgsl @@ -148,6 +148,8 @@ fn pbr_input_from_standard_material( pbr_input.N = pbr_functions::apply_normal_mapping( pbr_bindings::material.flags, pbr_input.world_normal, + double_sided, + is_front, #ifdef VERTEX_TANGENTS #ifdef STANDARDMATERIAL_NORMAL_MAP in.world_tangent, diff --git a/crates/bevy_pbr/src/render/pbr_functions.wgsl b/crates/bevy_pbr/src/render/pbr_functions.wgsl index 9979f75be0..6b8c65459d 100644 --- a/crates/bevy_pbr/src/render/pbr_functions.wgsl +++ b/crates/bevy_pbr/src/render/pbr_functions.wgsl @@ -61,6 +61,8 @@ fn prepare_world_normal( fn apply_normal_mapping( standard_material_flags: u32, world_normal: vec3, + double_sided: bool, + is_front: bool, #ifdef VERTEX_TANGENTS #ifdef STANDARDMATERIAL_NORMAL_MAP world_tangent: vec4, @@ -106,6 +108,11 @@ fn apply_normal_mapping( if (standard_material_flags & pbr_types::STANDARD_MATERIAL_FLAGS_FLIP_NORMAL_MAP_Y) != 0u { Nt.y = -Nt.y; } + + if double_sided && !is_front { + Nt = -Nt; + } + // NOTE: The mikktspace method of normal mapping applies maps the tangent-space normal from // the normal map texture in this way to be an EXACT inverse of how the normal map baker // calculates the normal maps so there is no error introduced. Do not change this code