Skip to content

Commit

Permalink
bevy_pbr: Add support for 2-component normal map textures
Browse files Browse the repository at this point in the history
In another branch there is work on adding calculation of vertex tangents using
the mikktspace algorithm. This algorithm works in a precise way and does not
normalize the tangent-space normals in order to exactly invert the calculations
done when creating the vertex tangent. If this level of precision is needed,
then a 3-component normal map must be used. Otherwise, a 2-component normal map
may be used, or the vertex tangents must be calculated in such a way as to
account for 2-component normal maps and the subsequent derivation of the third
component assuming the tangent-space normal is a unit normal.
  • Loading branch information
superdump committed Feb 13, 2022
1 parent 8f7e398 commit 5f73672
Show file tree
Hide file tree
Showing 5 changed files with 32 additions and 1 deletion.
17 changes: 17 additions & 0 deletions crates/bevy_pbr/src/pbr_material.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ bitflags::bitflags! {
const ALPHA_MODE_OPAQUE = (1 << 6);
const ALPHA_MODE_MASK = (1 << 7);
const ALPHA_MODE_BLEND = (1 << 8);
const TWO_COMPONENT_NORMAL_MAP = (1 << 9);
const NONE = 0;
const UNINITIALIZED = 0xFFFF;
}
Expand Down Expand Up @@ -235,6 +236,22 @@ impl RenderAsset for StandardMaterial {
flags |= StandardMaterialFlags::UNLIT;
}
let has_normal_map = material.normal_map_texture.is_some();
if has_normal_map {
match gpu_images
.get(material.normal_map_texture.as_ref().unwrap())
.unwrap()
.texture_format
{
// All 2-component unorm formats
TextureFormat::Rg8Unorm
| TextureFormat::Rg16Unorm
| TextureFormat::Bc5RgUnorm
| TextureFormat::EacRg11Unorm => {
flags |= StandardMaterialFlags::TWO_COMPONENT_NORMAL_MAP
}
_ => {}
}
}
// NOTE: 0.5 is from the glTF default - do we want this?
let mut alpha_cutoff = 0.5;
match material.alpha_mode {
Expand Down
1 change: 1 addition & 0 deletions crates/bevy_pbr/src/render/mesh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@ impl FromWorld for MeshPipeline {
GpuImage {
texture,
texture_view,
texture_format: image.texture_descriptor.format,
sampler,
size: Size::new(
image.texture_descriptor.size.width as f32,
Expand Down
12 changes: 11 additions & 1 deletion crates/bevy_pbr/src/render/pbr.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ let STANDARD_MATERIAL_FLAGS_UNLIT_BIT: u32 = 32u;
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;

[[group(1), binding(0)]]
var<uniform> material: StandardMaterial;
Expand Down Expand Up @@ -513,7 +514,16 @@ fn fragment(in: FragmentInput) -> [[location(0)]] vec4<f32> {
#ifdef VERTEX_TANGENTS
#ifdef STANDARDMATERIAL_NORMAL_MAP
let TBN = mat3x3<f32>(T, B, N);
N = TBN * normalize(textureSample(normal_map_texture, normal_map_sampler, in.uv).rgb * 2.0 - 1.0);
// Nt is the tangent-space normal.
var Nt: vec3<f32>;
if ((material.flags & STANDARD_MATERIAL_FLAGS_TWO_COMPONENT_NORMAL_MAP) != 0u) {
// Only use the xy components and derive z for 2-component normal maps.
Nt = vec3<f32>(textureSample(normal_map_texture, normal_map_sampler, in.uv).rg * 2.0 - 1.0, 0.0);
Nt.z = sqrt(1.0 - Nt.x * Nt.x - Nt.y * Nt.y);
} else {
Nt = textureSample(normal_map_texture, normal_map_sampler, in.uv).rgb * 2.0 - 1.0;
}
N = TBN * Nt;
#endif
#endif

Expand Down
2 changes: 2 additions & 0 deletions crates/bevy_render/src/texture/image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,7 @@ impl TextureFormatPixelInfo for TextureFormat {
pub struct GpuImage {
pub texture: Texture,
pub texture_view: TextureView,
pub texture_format: TextureFormat,
pub sampler: Sampler,
pub size: Size,
}
Expand Down Expand Up @@ -602,6 +603,7 @@ impl RenderAsset for Image {
Ok(GpuImage {
texture,
texture_view,
texture_format: image.texture_descriptor.format,
sampler,
size,
})
Expand Down
1 change: 1 addition & 0 deletions crates/bevy_sprite/src/mesh2d/mesh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ impl FromWorld for Mesh2dPipeline {
GpuImage {
texture,
texture_view,
texture_format: image.texture_descriptor.format,
sampler,
size: Size::new(
image.texture_descriptor.size.width as f32,
Expand Down

0 comments on commit 5f73672

Please sign in to comment.