diff --git a/crates/bevy_pbr/src/render/pbr_functions.wgsl b/crates/bevy_pbr/src/render/pbr_functions.wgsl index 2c862958dd223..7b9d4b3fdb368 100644 --- a/crates/bevy_pbr/src/render/pbr_functions.wgsl +++ b/crates/bevy_pbr/src/render/pbr_functions.wgsl @@ -468,6 +468,7 @@ fn apply_pbr_lighting( && (view_bindings::clusterable_objects.data[light_id].flags & mesh_view_types::POINT_LIGHT_FLAGS_SHADOWS_ENABLED_BIT) != 0u) { shadow = shadows::fetch_spot_shadow( + in.frag_coord.xy, light_id, in.world_position, in.world_normal, @@ -492,6 +493,7 @@ fn apply_pbr_lighting( 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::clusterable_objects.data[light_id].flags & mesh_view_types::POINT_LIGHT_FLAGS_SHADOWS_ENABLED_BIT) != 0u) { transmitted_shadow = shadows::fetch_spot_shadow( + in.frag_coord.xy, light_id, diffuse_transmissive_lobe_world_position, -in.world_normal, @@ -526,7 +528,13 @@ fn apply_pbr_lighting( var shadow: f32 = 1.0; if ((in.flags & MESH_FLAGS_SHADOW_RECEIVER_BIT) != 0u && (view_bindings::lights.directional_lights[i].flags & mesh_view_types::DIRECTIONAL_LIGHT_FLAGS_SHADOWS_ENABLED_BIT) != 0u) { - shadow = shadows::fetch_directional_shadow(i, in.world_position, in.world_normal, view_z); + shadow = shadows::fetch_directional_shadow( + in.frag_coord.xy, + i, + in.world_position, + in.world_normal, + view_z, + ); } var light_contrib = lighting::directional_light(i, &lighting_input, enable_diffuse); @@ -549,7 +557,13 @@ fn apply_pbr_lighting( 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); + transmitted_shadow = shadows::fetch_directional_shadow( + in.frag_coord.xy, + i, + diffuse_transmissive_lobe_world_position, + -in.world_normal, + view_z, + ); } let transmitted_light_contrib = @@ -612,7 +626,7 @@ fn apply_pbr_lighting( #else // SCREEN_SPACE_REFLECTIONS let use_ssr = false; #endif // SCREEN_SPACE_REFLECTIONS - + if (!use_ssr) { #ifdef STANDARD_MATERIAL_ANISOTROPY var bent_normal_lighting_input = lighting_input; diff --git a/crates/bevy_pbr/src/render/shadow_sampling.wgsl b/crates/bevy_pbr/src/render/shadow_sampling.wgsl index 2b35e57037408..b4114118edfe2 100644 --- a/crates/bevy_pbr/src/render/shadow_sampling.wgsl +++ b/crates/bevy_pbr/src/render/shadow_sampling.wgsl @@ -175,6 +175,7 @@ fn calculate_uv_offset_scale_jimenez_fourteen(texel_size: f32, blur_size: f32) - } fn sample_shadow_map_jimenez_fourteen( + frag_coord_xy: vec2, light_local: vec2, depth: f32, array_index: i32, @@ -182,8 +183,7 @@ fn sample_shadow_map_jimenez_fourteen( blur_size: f32, temporal: bool, ) -> f32 { - let shadow_map_size = vec2(textureDimensions(view_bindings::directional_shadow_textures)); - let rotation_matrix = random_rotation_matrix(light_local * shadow_map_size, temporal); + let rotation_matrix = random_rotation_matrix(frag_coord_xy, temporal); let uv_offset_scale = calculate_uv_offset_scale_jimenez_fourteen(texel_size, blur_size); // https://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare (slides 120-135) @@ -208,6 +208,8 @@ fn sample_shadow_map_jimenez_fourteen( return sum / 8.0; } +const PENUMBRA_FILTER_SIZE: vec2 = vec2(128.0f); + // Performs the blocker search portion of percentage-closer soft shadows (PCSS). // This is the variation used for directional lights. // @@ -219,23 +221,23 @@ fn sample_shadow_map_jimenez_fourteen( // // `search_size` is the size of the search region in texels. fn search_for_blockers_in_shadow_map( + frag_coord_xy: vec2, light_local: vec2, depth: f32, array_index: i32, - texel_size: f32, - search_size: f32, ) -> f32 { let shadow_map_size = vec2(textureDimensions(view_bindings::directional_shadow_textures)); - let uv_offset_scale = search_size / (texel_size * shadow_map_size); - - let offset0 = D3D_SAMPLE_POINT_POSITIONS[0] * uv_offset_scale; - let offset1 = D3D_SAMPLE_POINT_POSITIONS[1] * uv_offset_scale; - let offset2 = D3D_SAMPLE_POINT_POSITIONS[2] * uv_offset_scale; - let offset3 = D3D_SAMPLE_POINT_POSITIONS[3] * uv_offset_scale; - let offset4 = D3D_SAMPLE_POINT_POSITIONS[4] * uv_offset_scale; - let offset5 = D3D_SAMPLE_POINT_POSITIONS[5] * uv_offset_scale; - let offset6 = D3D_SAMPLE_POINT_POSITIONS[6] * uv_offset_scale; - let offset7 = D3D_SAMPLE_POINT_POSITIONS[7] * uv_offset_scale; + let rotation_matrix = random_rotation_matrix(frag_coord_xy, false); + let uv_offset_scale = PENUMBRA_FILTER_SIZE / shadow_map_size; + + let offset0 = rotation_matrix * D3D_SAMPLE_POINT_POSITIONS[0] * uv_offset_scale; + let offset1 = rotation_matrix * D3D_SAMPLE_POINT_POSITIONS[1] * uv_offset_scale; + let offset2 = rotation_matrix * D3D_SAMPLE_POINT_POSITIONS[2] * uv_offset_scale; + let offset3 = rotation_matrix * D3D_SAMPLE_POINT_POSITIONS[3] * uv_offset_scale; + let offset4 = rotation_matrix * D3D_SAMPLE_POINT_POSITIONS[4] * uv_offset_scale; + let offset5 = rotation_matrix * D3D_SAMPLE_POINT_POSITIONS[5] * uv_offset_scale; + let offset6 = rotation_matrix * D3D_SAMPLE_POINT_POSITIONS[6] * uv_offset_scale; + let offset7 = rotation_matrix * D3D_SAMPLE_POINT_POSITIONS[7] * uv_offset_scale; var sum = vec2(0.0); sum += search_for_blockers_in_shadow_map_hardware(light_local + offset0, depth, array_index); @@ -253,12 +255,18 @@ fn search_for_blockers_in_shadow_map( return sum.x / sum.y; } -fn sample_shadow_map(light_local: vec2, depth: f32, array_index: i32, texel_size: f32) -> f32 { +fn sample_shadow_map( + frag_coord_xy: vec2, + light_local: vec2, + depth: f32, + array_index: i32, + texel_size: f32, +) -> f32 { #ifdef SHADOW_FILTER_METHOD_GAUSSIAN return sample_shadow_map_castano_thirteen(light_local, depth, array_index); #else ifdef SHADOW_FILTER_METHOD_TEMPORAL return sample_shadow_map_jimenez_fourteen( - light_local, depth, array_index, texel_size, 1.0, true); + frag_coord_xy, light_local, depth, array_index, texel_size, 1.0, true); #else ifdef SHADOW_FILTER_METHOD_HARDWARE_2X2 return sample_shadow_map_hardware(light_local, depth, array_index); #else @@ -282,6 +290,7 @@ fn sample_shadow_map(light_local: vec2, depth: f32, array_index: i32, texel // A good overview of the technique: // fn sample_shadow_map_pcss( + frag_coord_xy: vec2, light_local: vec2, depth: f32, array_index: i32, @@ -289,8 +298,7 @@ fn sample_shadow_map_pcss( light_size: f32, ) -> f32 { // Determine the average Z value of the closest blocker. - let z_blocker = search_for_blockers_in_shadow_map( - light_local, depth, array_index, texel_size, light_size); + let z_blocker = search_for_blockers_in_shadow_map(frag_coord_xy, light_local, depth, array_index); // Don't let the blur size go below 0.5, or shadows will look unacceptably aliased. let blur_size = max((z_blocker - depth) * light_size / depth, 0.5); @@ -302,10 +310,10 @@ fn sample_shadow_map_pcss( // provide better blurs. #ifdef SHADOW_FILTER_METHOD_TEMPORAL return sample_shadow_map_jimenez_fourteen( - light_local, depth, array_index, texel_size, blur_size, true); + frag_coord_xy, light_local, depth, array_index, texel_size, blur_size, true); #else // SHADOW_FILTER_METHOD_TEMPORAL return sample_shadow_map_jimenez_fourteen( - light_local, depth, array_index, texel_size, blur_size, false); + frag_coord_xy, light_local, depth, array_index, texel_size, blur_size, false); #endif // SHADOW_FILTER_METHOD_TEMPORAL } diff --git a/crates/bevy_pbr/src/render/shadows.wgsl b/crates/bevy_pbr/src/render/shadows.wgsl index a3727b45af526..276f7745cf3ab 100644 --- a/crates/bevy_pbr/src/render/shadows.wgsl +++ b/crates/bevy_pbr/src/render/shadows.wgsl @@ -63,6 +63,7 @@ fn fetch_point_shadow(light_id: u32, frag_position: vec4, surface_normal: v } fn fetch_spot_shadow( + frag_coord_xy: vec2, light_id: u32, frag_position: vec4, surface_normal: vec3, @@ -108,10 +109,22 @@ fn fetch_spot_shadow( let array_index = i32(light_id) + view_bindings::lights.spot_light_shadowmap_offset; if ((*light).soft_shadow_size > 0.0) { return sample_shadow_map_pcss( - shadow_uv, depth, array_index, SPOT_SHADOW_TEXEL_SIZE, (*light).soft_shadow_size); + frag_coord_xy, + shadow_uv, + depth, + array_index, + SPOT_SHADOW_TEXEL_SIZE, + (*light).soft_shadow_size, + ); } - return sample_shadow_map(shadow_uv, depth, array_index, SPOT_SHADOW_TEXEL_SIZE); + return sample_shadow_map( + frag_coord_xy, + shadow_uv, + depth, + array_index, + SPOT_SHADOW_TEXEL_SIZE, + ); } fn get_cascade_index(light_id: u32, view_z: f32) -> u32 { @@ -159,6 +172,7 @@ fn world_to_directional_light_local( } fn sample_directional_cascade( + frag_coord_xy: vec2, light_id: u32, cascade_index: u32, frag_position: vec4, @@ -183,13 +197,31 @@ fn sample_directional_cascade( // If soft shadows are enabled, use the PCSS path. if ((*light).soft_shadow_size > 0.0) { return sample_shadow_map_pcss( - light_local.xy, light_local.z, array_index, texel_size, (*light).soft_shadow_size); + frag_coord_xy, + light_local.xy, + light_local.z, + array_index, + texel_size, + (*light).soft_shadow_size, + ); } - return sample_shadow_map(light_local.xy, light_local.z, array_index, texel_size); + return sample_shadow_map( + frag_coord_xy, + light_local.xy, + light_local.z, + array_index, + texel_size, + ); } -fn fetch_directional_shadow(light_id: u32, frag_position: vec4, surface_normal: vec3, view_z: f32) -> f32 { +fn fetch_directional_shadow( + frag_coord_xy: vec2, + light_id: u32, + frag_position: vec4, + surface_normal: vec3, + view_z: f32, +) -> f32 { let light = &view_bindings::lights.directional_lights[light_id]; let cascade_index = get_cascade_index(light_id, view_z); @@ -197,7 +229,13 @@ fn fetch_directional_shadow(light_id: u32, frag_position: vec4, surface_nor return 1.0; } - var shadow = sample_directional_cascade(light_id, cascade_index, frag_position, surface_normal); + var shadow = sample_directional_cascade( + frag_coord_xy, + light_id, + cascade_index, + frag_position, + surface_normal, + ); // Blend with the next cascade, if there is one. let next_cascade_index = cascade_index + 1u; @@ -205,7 +243,13 @@ fn fetch_directional_shadow(light_id: u32, frag_position: vec4, surface_nor let this_far_bound = (*light).cascades[cascade_index].far_bound; let next_near_bound = (1.0 - (*light).cascades_overlap_proportion) * this_far_bound; if (-view_z >= next_near_bound) { - let next_shadow = sample_directional_cascade(light_id, next_cascade_index, frag_position, surface_normal); + let next_shadow = sample_directional_cascade( + frag_coord_xy, + light_id, + next_cascade_index, + frag_position, + surface_normal, + ); shadow = mix(shadow, next_shadow, (-view_z - next_near_bound) / (this_far_bound - next_near_bound)); } } diff --git a/crates/bevy_pbr/src/volumetric_fog/volumetric_fog.wgsl b/crates/bevy_pbr/src/volumetric_fog/volumetric_fog.wgsl index 12294cd088b1a..71105afea4ca5 100644 --- a/crates/bevy_pbr/src/volumetric_fog/volumetric_fog.wgsl +++ b/crates/bevy_pbr/src/volumetric_fog/volumetric_fog.wgsl @@ -20,7 +20,7 @@ } #import bevy_pbr::mesh_functions::{get_world_from_local, mesh_position_local_to_clip} #import bevy_pbr::mesh_view_bindings::{ - globals, lights, view, clusterable_objects, + globals, lights, view, clusterable_objects, atmosphere_data, atmosphere_transmittance_texture, atmosphere_transmittance_sampler } #import bevy_pbr::mesh_view_types::{ @@ -312,7 +312,7 @@ fn fragment(@builtin(position) position: vec4) -> @location(0) vec4 { let r = length(P_as); let local_up = normalize(P_as); let mu_light = dot(L, local_up); - + let transmittance = sample_transmittance_lut(r, mu_light); let sun_visibility = calculate_visible_sun_ratio(atmosphere_data.atmosphere, r, mu_light, (*light).sun_disk_angular_size); light_factors_per_step *= transmittance * sun_visibility; @@ -391,7 +391,11 @@ fn fragment(@builtin(position) position: vec4) -> @location(0) vec4 { var shadow: f32 = 1.0; if (((*light).flags & POINT_LIGHT_FLAGS_SHADOWS_ENABLED_BIT) != 0u) { - shadow = fetch_spot_shadow_without_normal(light_id, vec4(P_world, 1.0)); + shadow = fetch_spot_shadow_without_normal( + frag_coord.xy, + light_id, + vec4(P_world, 1.0), + ); } local_light_attenuation *= spot_attenuation * shadow; } @@ -455,7 +459,11 @@ fn fetch_point_shadow_without_normal(light_id: u32, frag_position: vec4) -> return sample_shadow_cubemap(frag_ls * flip_z, distance_to_light, depth, light_id); } -fn fetch_spot_shadow_without_normal(light_id: u32, frag_position: vec4) -> f32 { +fn fetch_spot_shadow_without_normal( + frag_coord_xy: vec2, + light_id: u32, + frag_position: vec4, +) -> f32 { let light = &clusterable_objects.data[light_id]; let surface_to_light = (*light).position_radius.xyz - frag_position.xyz; @@ -502,6 +510,7 @@ fn fetch_spot_shadow_without_normal(light_id: u32, frag_position: vec4) -> let depth = 0.1 / -projected_position.z; return sample_shadow_map( + frag_coord_xy, shadow_uv, depth, i32(light_id) + lights.spot_light_shadowmap_offset, @@ -513,7 +522,7 @@ fn fetch_spot_shadow_without_normal(light_id: u32, frag_position: vec4) -> fn sample_transmittance_lut(r: f32, mu: f32) -> vec3 { let uv = transmittance_lut_r_mu_to_uv(atmosphere_data.atmosphere, r, mu); return textureSampleLevel( - atmosphere_transmittance_texture, + atmosphere_transmittance_texture, atmosphere_transmittance_sampler, uv, 0.0).rgb; } -#endif // ATMOSPHERE \ No newline at end of file +#endif // ATMOSPHERE