Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gate diffuse and specular transmission behind shader defs #11627

Merged
merged 5 commits into from
Feb 2, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion assets/shaders/array_texture.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ fn fragment(
double_sided,
is_front,
#ifdef VERTEX_TANGENTS
#ifdef STANDARDMATERIAL_NORMAL_MAP
#ifdef STANDARD_MATERIAL_NORMAL_MAP
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a small drive-by fix for consistency with the instances of STANDARD_MATERIAL in the codebase.

mesh.world_tangent,
#endif
#endif
Expand Down
19 changes: 18 additions & 1 deletion crates/bevy_pbr/src/pbr_material.rs
Original file line number Diff line number Diff line change
Expand Up @@ -740,6 +740,8 @@ pub struct StandardMaterialKey {
cull_mode: Option<Face>,
depth_bias: i32,
relief_mapping: bool,
diffuse_transmission: bool,
specular_transmission: bool,
}

impl From<&StandardMaterial> for StandardMaterialKey {
Expand All @@ -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,
}
}
}
Expand Down Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_pbr/src/render/pbr_fragment.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
24 changes: 20 additions & 4 deletions crates/bevy_pbr/src/render/pbr_functions.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ fn prepare_world_normal(
) -> vec3<f32> {
var output: vec3<f32> = 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;
Expand All @@ -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<f32>,
#endif
#endif
Expand All @@ -83,7 +83,7 @@ fn apply_normal_mapping(
var N: vec3<f32> = 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.
Expand All @@ -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 {
Expand Down Expand Up @@ -213,6 +213,7 @@ 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;

#ifdef STANDARD_MATERIAL_DIFFUSE_TRANSMISSION
if diffuse_transmission > 0.0 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the shader def being present should mean it's > 0.0, could we remove the if from the shader? (same for the others)

Copy link
Contributor Author

@coreh coreh Feb 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, we could, but with the use of diffuse_transmission_texture and specular_transmission_texture it's possible for the per-fragment value of diffuse_transmission and specular_transmission to be 0, even when the shader def is present. In those cases without the if we'd do a bunch of computations or texture reads that would be immediately discarded.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure how much that really matters. I suspect the overhead of the if statement would be worse than any potential extra work on average. It's not a big deal either way, but it's probably worth removing still.

// NOTE: We use the diffuse transmissive color, the second Lambertian lobe's calculated
// world position, inverted normal and view vectors, and the following simplified
Expand All @@ -231,6 +232,7 @@ fn apply_pbr_lighting(
let light_contrib = lighting::point_light(diffuse_transmissive_lobe_world_position.xyz, light_id, 1.0, 1.0, -in.N, -in.V, vec3<f32>(0.0), vec3<f32>(0.0), vec2<f32>(0.1), diffuse_transmissive_color);
transmitted_light += light_contrib * transmitted_shadow;
}
#endif
}

// Spot lights (direct)
Expand All @@ -245,6 +247,7 @@ 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;

#ifdef STANDARD_MATERIAL_DIFFUSE_TRANSMISSION
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
Expand All @@ -263,6 +266,7 @@ fn apply_pbr_lighting(
let light_contrib = lighting::spot_light(diffuse_transmissive_lobe_world_position.xyz, light_id, 1.0, 1.0, -in.N, -in.V, vec3<f32>(0.0), vec3<f32>(0.0), vec2<f32>(0.1), diffuse_transmissive_color);
transmitted_light += light_contrib * transmitted_shadow;
}
#endif
}

// directional lights (direct)
Expand All @@ -286,6 +290,7 @@ fn apply_pbr_lighting(
#endif
direct_light += light_contrib * shadow;

#ifdef STANDARD_MATERIAL_DIFFUSE_TRANSMISSION
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
Expand All @@ -304,11 +309,13 @@ fn apply_pbr_lighting(
let light_contrib = lighting::directional_light(i, 1.0, 1.0, -in.N, -in.V, vec3<f32>(0.0), vec3<f32>(0.0), vec2<f32>(0.1), diffuse_transmissive_color);
transmitted_light += 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
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
Expand All @@ -320,6 +327,7 @@ fn apply_pbr_lighting(
// diffuse_occlusion = vec3<f32>(1.0)
transmitted_light += ambient::ambient_light(diffuse_transmissive_lobe_world_position, -in.N, -in.V, 1.0, diffuse_transmissive_color, vec3<f32>(0.0), 1.0, vec3<f32>(1.0));
}
#endif

// Environment map light (indirect)
#ifdef ENVIRONMENT_MAP
Expand All @@ -339,6 +347,7 @@ fn apply_pbr_lighting(
// light in the call to `specular_transmissive_light()` below
var specular_transmitted_environment_light = vec3<f32>(0.0);

#ifdef STANDARD_MATERIAL_SPECULAR_OR_DIFFUSE_TRANSMISSION
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
Expand Down Expand Up @@ -368,9 +377,14 @@ fn apply_pbr_lighting(
T,
vec3<f32>(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.
Expand All @@ -383,6 +397,7 @@ fn apply_pbr_lighting(

let emissive_light = emissive.rgb * output_color.a;

#ifdef STANDARD_MATERIAL_SPECULAR_TRANSMISSION
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;
}
Expand All @@ -401,6 +416,7 @@ fn apply_pbr_lighting(
vec3<f32>(0.0) // TODO: Pass in (pre-attenuated) scattered light contribution here
).rgb;
}
#endif

// Total light
output_color = vec4<f32>(
Expand Down
4 changes: 2 additions & 2 deletions crates/bevy_pbr/src/render/pbr_prepass.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down