bevy_pbr: Support flipping tangent space normal map y for DirectX normal maps (#4433)
# Objective - Normal maps authored for DirectX use a left-handed convention and have their tangent space normal in the texture inverted from what we need. Support this. - Details here: https://doc.babylonjs.com/divingDeeper/materials/advanced/normalMaps ## Solution - Add a `StandardMaterial` `flip_normal_map_y` boolean field - Add a `STANDARDMATERIAL_FLIP_NORMAL_MAP_Y` flag to `StandardMaterialFlags` and in the PBR shader - Flip the y-component of the tangent space normal just after sampling it from the normal map texture ## Screenshots ### Before <img width="1392" alt="Screenshot 2022-04-06 at 21 04 44" src="https://user-images.githubusercontent.com/302146/162050314-e7bfaaf6-9ee1-4756-9821-f6f5ff78f508.png"> ### After <img width="1392" alt="Screenshot 2022-04-06 at 21 03 39" src="https://user-images.githubusercontent.com/302146/162050255-36ee0745-1d79-4fd2-9a1c-18085376b643.png"> --- ## Changelog - Added: Support for flipping the normal map texture y component for normal maps authored for use with DirectX
This commit is contained in:
parent
e7e74457c7
commit
579928e8e0
@ -47,6 +47,9 @@ pub struct StandardMaterial {
|
||||
/// defaults to 0.5 which is mapped to 4% reflectance in the shader
|
||||
pub reflectance: f32,
|
||||
pub normal_map_texture: Option<Handle<Image>>,
|
||||
/// Normal map textures authored for DirectX have their y-component flipped. Set this to flip
|
||||
/// it to right-handed conventions.
|
||||
pub flip_normal_map_y: bool,
|
||||
pub occlusion_texture: Option<Handle<Image>>,
|
||||
/// Support two-sided lighting by automatically flipping the normals for "back" faces
|
||||
/// within the PBR lighting shader.
|
||||
@ -84,6 +87,7 @@ impl Default for StandardMaterial {
|
||||
reflectance: 0.5,
|
||||
occlusion_texture: None,
|
||||
normal_map_texture: None,
|
||||
flip_normal_map_y: false,
|
||||
double_sided: false,
|
||||
cull_mode: Some(Face::Back),
|
||||
unlit: false,
|
||||
@ -124,6 +128,7 @@ bitflags::bitflags! {
|
||||
const ALPHA_MODE_MASK = (1 << 7);
|
||||
const ALPHA_MODE_BLEND = (1 << 8);
|
||||
const TWO_COMPONENT_NORMAL_MAP = (1 << 9);
|
||||
const FLIP_NORMAL_MAP_Y = (1 << 10);
|
||||
const NONE = 0;
|
||||
const UNINITIALIZED = 0xFFFF;
|
||||
}
|
||||
@ -262,6 +267,9 @@ impl RenderAsset for StandardMaterial {
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
if material.flip_normal_map_y {
|
||||
flags |= StandardMaterialFlags::FLIP_NORMAL_MAP_Y;
|
||||
}
|
||||
}
|
||||
// NOTE: 0.5 is from the glTF default - do we want this?
|
||||
let mut alpha_cutoff = 0.5;
|
||||
|
||||
@ -59,6 +59,7 @@ let STANDARD_MATERIAL_FLAGS_ALPHA_MODE_OPAQUE: u32 = 64u;
|
||||
let STANDARD_MATERIAL_FLAGS_ALPHA_MODE_MASK: u32 = 128u;
|
||||
let STANDARD_MATERIAL_FLAGS_ALPHA_MODE_BLEND: u32 = 256u;
|
||||
let STANDARD_MATERIAL_FLAGS_TWO_COMPONENT_NORMAL_MAP: u32 = 512u;
|
||||
let STANDARD_MATERIAL_FLAGS_FLIP_NORMAL_MAP_Y: u32 = 1024u;
|
||||
|
||||
[[group(1), binding(0)]]
|
||||
var<uniform> material: StandardMaterial;
|
||||
@ -525,6 +526,10 @@ fn fragment(in: FragmentInput) -> [[location(0)]] vec4<f32> {
|
||||
} else {
|
||||
Nt = textureSample(normal_map_texture, normal_map_sampler, in.uv).rgb * 2.0 - 1.0;
|
||||
}
|
||||
// Normal maps authored for DirectX require flipping the y component
|
||||
if ((material.flags & STANDARD_MATERIAL_FLAGS_FLIP_NORMAL_MAP_Y) != 0u) {
|
||||
Nt.y = -Nt.y;
|
||||
}
|
||||
N = normalize(TBN * Nt);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
Loading…
Reference in New Issue
Block a user