1#define_import_path bevy_pbr::shadow_sampling 4 mesh_view_bindings as view_bindings, 5 utils::interleaved_gradient_noise, 8#import bevy_render::maths::{orthonormalize, PI} 11fn sample_shadow_map_hardware(light_local: vec2<f32>, depth: f32, array_index: i32) -> f32 { 12#ifdef NO_ARRAY_TEXTURES_SUPPORT 13 return textureSampleCompare( 14 view_bindings::directional_shadow_textures, 15 view_bindings::directional_shadow_textures_comparison_sampler, 20 return textureSampleCompareLevel( 21 view_bindings::directional_shadow_textures, 22 view_bindings::directional_shadow_textures_comparison_sampler, 32fn search_for_blockers_in_shadow_map_hardware( 33 light_local: vec2<f32>, 43#ifdef PCSS_SAMPLERS_AVAILABLE 45#ifdef NO_ARRAY_TEXTURES_SUPPORT 46 let sampled_depth = textureSampleLevel( 47 view_bindings::directional_shadow_textures, 48 view_bindings::directional_shadow_textures_linear_sampler, 52#else // NO_ARRAY_TEXTURES_SUPPORT 53 let sampled_depth = textureSampleLevel( 54 view_bindings::directional_shadow_textures, 55 view_bindings::directional_shadow_textures_linear_sampler, 60#endif // NO_ARRAY_TEXTURES_SUPPORT 61 return select(vec2(0.0), vec2(sampled_depth, 1.0), sampled_depth >= depth); 63#else // PCSS_SAMPLERS_AVAILABLE 65#endif // PCSS_SAMPLERS_AVAILABLE 71const SPOT_SHADOW_TEXEL_SIZE: f32 = 0.0134277345; 72const POINT_SHADOW_SCALE: f32 = 0.003; 73const POINT_SHADOW_TEMPORAL_OFFSET_SCALE: f32 = 0.5; 79const D3D_SAMPLE_POINT_POSITIONS: array<vec2<f32>, 8> = array( 93const D3D_SAMPLE_POINT_COEFFS: array<f32, 8> = array( 105fn sample_shadow_map_castano_thirteen(light_local: vec2<f32>, depth: f32, array_index: i32) -> f32 { 106 let shadow_map_size = vec2<f32>(textureDimensions(view_bindings::directional_shadow_textures)); 107 let inv_shadow_map_size = 1.0 / shadow_map_size; 109 let uv = light_local * shadow_map_size; 110 var base_uv = floor(uv + 0.5); 111 let s = (uv.x + 0.5 - base_uv.x); 112 let t = (uv.y + 0.5 - base_uv.y); 114 base_uv *= inv_shadow_map_size; 116 let uw0 = (4.0 - 3.0 * s); 118 let uw2 = (1.0 + 3.0 * s); 120 let u0 = (3.0 - 2.0 * s) / uw0 - 2.0; 121 let u1 = (3.0 + s) / uw1; 122 let u2 = s / uw2 + 2.0; 124 let vw0 = (4.0 - 3.0 * t); 126 let vw2 = (1.0 + 3.0 * t); 128 let v0 = (3.0 - 2.0 * t) / vw0 - 2.0; 129 let v1 = (3.0 + t) / vw1; 130 let v2 = t / vw2 + 2.0; 134 sum += uw0 * vw0 * sample_shadow_map_hardware(base_uv + (vec2(u0, v0) * inv_shadow_map_size), depth, array_index); 135 sum += uw1 * vw0 * sample_shadow_map_hardware(base_uv + (vec2(u1, v0) * inv_shadow_map_size), depth, array_index); 136 sum += uw2 * vw0 * sample_shadow_map_hardware(base_uv + (vec2(u2, v0) * inv_shadow_map_size), depth, array_index); 138 sum += uw0 * vw1 * sample_shadow_map_hardware(base_uv + (vec2(u0, v1) * inv_shadow_map_size), depth, array_index); 139 sum += uw1 * vw1 * sample_shadow_map_hardware(base_uv + (vec2(u1, v1) * inv_shadow_map_size), depth, array_index); 140 sum += uw2 * vw1 * sample_shadow_map_hardware(base_uv + (vec2(u2, v1) * inv_shadow_map_size), depth, array_index); 142 sum += uw0 * vw2 * sample_shadow_map_hardware(base_uv + (vec2(u0, v2) * inv_shadow_map_size), depth, array_index); 143 sum += uw1 * vw2 * sample_shadow_map_hardware(base_uv + (vec2(u1, v2) * inv_shadow_map_size), depth, array_index); 144 sum += uw2 * vw2 * sample_shadow_map_hardware(base_uv + (vec2(u2, v2) * inv_shadow_map_size), depth, array_index); 146 return sum * (1.0 / 144.0); 149fn map(min1: f32, max1: f32, min2: f32, max2: f32, value: f32) -> f32 { 150 return min2 + (value - min1) * (max2 - min2) / (max1 - min1); 156fn random_rotation_matrix(scale: vec2<f32>, temporal: bool) -> mat2x2<f32> { 157 let random_angle = 2.0 * PI * interleaved_gradient_noise( 158 scale, select(1u, view_bindings::globals.frame_count, temporal)); 159 let m = vec2(sin(random_angle), cos(random_angle)); 169fn calculate_uv_offset_scale_jimenez_fourteen(texel_size: f32, blur_size: f32) -> vec2<f32> { 170 let shadow_map_size = vec2<f32>(textureDimensions(view_bindings::directional_shadow_textures)); 173 let f = map(0.00390625, 0.022949219, 0.015, 0.035, texel_size); 174 return f * blur_size / (texel_size * shadow_map_size); 177fn sample_shadow_map_jimenez_fourteen( 178 light_local: vec2<f32>, 185 let shadow_map_size = vec2<f32>(textureDimensions(view_bindings::directional_shadow_textures)); 186 let rotation_matrix = random_rotation_matrix(light_local * shadow_map_size, temporal); 187 let uv_offset_scale = calculate_uv_offset_scale_jimenez_fourteen(texel_size, blur_size); 190 let sample_offset0 = (rotation_matrix * utils::SPIRAL_OFFSET_0_) * uv_offset_scale; 191 let sample_offset1 = (rotation_matrix * utils::SPIRAL_OFFSET_1_) * uv_offset_scale; 192 let sample_offset2 = (rotation_matrix * utils::SPIRAL_OFFSET_2_) * uv_offset_scale; 193 let sample_offset3 = (rotation_matrix * utils::SPIRAL_OFFSET_3_) * uv_offset_scale; 194 let sample_offset4 = (rotation_matrix * utils::SPIRAL_OFFSET_4_) * uv_offset_scale; 195 let sample_offset5 = (rotation_matrix * utils::SPIRAL_OFFSET_5_) * uv_offset_scale; 196 let sample_offset6 = (rotation_matrix * utils::SPIRAL_OFFSET_6_) * uv_offset_scale; 197 let sample_offset7 = (rotation_matrix * utils::SPIRAL_OFFSET_7_) * uv_offset_scale; 200 sum += sample_shadow_map_hardware(light_local + sample_offset0, depth, array_index); 201 sum += sample_shadow_map_hardware(light_local + sample_offset1, depth, array_index); 202 sum += sample_shadow_map_hardware(light_local + sample_offset2, depth, array_index); 203 sum += sample_shadow_map_hardware(light_local + sample_offset3, depth, array_index); 204 sum += sample_shadow_map_hardware(light_local + sample_offset4, depth, array_index); 205 sum += sample_shadow_map_hardware(light_local + sample_offset5, depth, array_index); 206 sum += sample_shadow_map_hardware(light_local + sample_offset6, depth, array_index); 207 sum += sample_shadow_map_hardware(light_local + sample_offset7, depth, array_index); 221fn search_for_blockers_in_shadow_map( 222 light_local: vec2<f32>, 228 let shadow_map_size = vec2<f32>(textureDimensions(view_bindings::directional_shadow_textures)); 229 let uv_offset_scale = search_size / (texel_size * shadow_map_size); 231 let offset0 = D3D_SAMPLE_POINT_POSITIONS[0] * uv_offset_scale; 232 let offset1 = D3D_SAMPLE_POINT_POSITIONS[1] * uv_offset_scale; 233 let offset2 = D3D_SAMPLE_POINT_POSITIONS[2] * uv_offset_scale; 234 let offset3 = D3D_SAMPLE_POINT_POSITIONS[3] * uv_offset_scale; 235 let offset4 = D3D_SAMPLE_POINT_POSITIONS[4] * uv_offset_scale; 236 let offset5 = D3D_SAMPLE_POINT_POSITIONS[5] * uv_offset_scale; 237 let offset6 = D3D_SAMPLE_POINT_POSITIONS[6] * uv_offset_scale; 238 let offset7 = D3D_SAMPLE_POINT_POSITIONS[7] * uv_offset_scale; 241 sum += search_for_blockers_in_shadow_map_hardware(light_local + offset0, depth, array_index); 242 sum += search_for_blockers_in_shadow_map_hardware(light_local + offset1, depth, array_index); 243 sum += search_for_blockers_in_shadow_map_hardware(light_local + offset2, depth, array_index); 244 sum += search_for_blockers_in_shadow_map_hardware(light_local + offset3, depth, array_index); 245 sum += search_for_blockers_in_shadow_map_hardware(light_local + offset4, depth, array_index); 246 sum += search_for_blockers_in_shadow_map_hardware(light_local + offset5, depth, array_index); 247 sum += search_for_blockers_in_shadow_map_hardware(light_local + offset6, depth, array_index); 248 sum += search_for_blockers_in_shadow_map_hardware(light_local + offset7, depth, array_index); 253 return sum.x / sum.y; 256fn sample_shadow_map(light_local: vec2<f32>, depth: f32, array_index: i32, texel_size: f32) -> f32 { 257#ifdef SHADOW_FILTER_METHOD_GAUSSIAN 258 return sample_shadow_map_castano_thirteen(light_local, depth, array_index); 259#else ifdef SHADOW_FILTER_METHOD_TEMPORAL 260 return sample_shadow_map_jimenez_fourteen( 261 light_local, depth, array_index, texel_size, 1.0, true); 262#else ifdef SHADOW_FILTER_METHOD_HARDWARE_2X2 263 return sample_shadow_map_hardware(light_local, depth, array_index); 284fn sample_shadow_map_pcss( 285 light_local: vec2<f32>, 292 let z_blocker = search_for_blockers_in_shadow_map( 293 light_local, depth, array_index, texel_size, light_size); 296 let blur_size = max((z_blocker - depth) * light_size / depth, 0.5); 303#ifdef SHADOW_FILTER_METHOD_TEMPORAL 304 return sample_shadow_map_jimenez_fourteen( 305 light_local, depth, array_index, texel_size, blur_size, true); 306#else // SHADOW_FILTER_METHOD_TEMPORAL 307 return sample_shadow_map_jimenez_fourteen( 308 light_local, depth, array_index, texel_size, blur_size, false); 309#endif // SHADOW_FILTER_METHOD_TEMPORAL 317fn sample_shadow_cubemap_hardware(light_local: vec3<f32>, depth: f32, light_id: u32) -> f32 { 318#ifdef NO_CUBE_ARRAY_TEXTURES_SUPPORT 319 return textureSampleCompare( 320 view_bindings::point_shadow_textures, 321 view_bindings::point_shadow_textures_comparison_sampler, 326 return textureSampleCompareLevel( 327 view_bindings::point_shadow_textures, 328 view_bindings::point_shadow_textures_comparison_sampler, 338fn search_for_blockers_in_shadow_cubemap_hardware( 339 light_local: vec3<f32>, 349#ifdef PCSS_SAMPLERS_AVAILABLE 351#ifdef NO_CUBE_ARRAY_TEXTURES_SUPPORT 352 let sampled_depth = textureSample( 353 view_bindings::point_shadow_textures, 354 view_bindings::point_shadow_textures_linear_sampler, 358 let sampled_depth = textureSample( 359 view_bindings::point_shadow_textures, 360 view_bindings::point_shadow_textures_linear_sampler, 366 return select(vec2(0.0), vec2(sampled_depth, 1.0), sampled_depth >= depth); 368#else // PCSS_SAMPLERS_AVAILABLE 370#endif // PCSS_SAMPLERS_AVAILABLE 375fn sample_shadow_cubemap_at_offset( 380 light_local: vec3<f32>, 384 return sample_shadow_cubemap_hardware( 385 light_local + position.x * x_basis + position.y * y_basis, 396fn search_for_blockers_in_shadow_cubemap_at_offset( 400 light_local: vec3<f32>, 404 return search_for_blockers_in_shadow_cubemap_hardware( 405 light_local + position.x * x_basis + position.y * y_basis, 416fn sample_shadow_cubemap_gaussian( 417 light_local: vec3<f32>, 420 distance_to_light: f32, 425 var up = vec3(0.0, 1.0, 0.0); 426 if (dot(up, normalize(light_local)) > 0.99) { 427 up = vec3(1.0, 0.0, 0.0); 429 let basis = orthonormalize(light_local, up) * scale * distance_to_light; 432 sum += sample_shadow_cubemap_at_offset( 433 D3D_SAMPLE_POINT_POSITIONS[0], D3D_SAMPLE_POINT_COEFFS[0], 434 basis[0], basis[1], light_local, depth, light_id); 435 sum += sample_shadow_cubemap_at_offset( 436 D3D_SAMPLE_POINT_POSITIONS[1], D3D_SAMPLE_POINT_COEFFS[1], 437 basis[0], basis[1], light_local, depth, light_id); 438 sum += sample_shadow_cubemap_at_offset( 439 D3D_SAMPLE_POINT_POSITIONS[2], D3D_SAMPLE_POINT_COEFFS[2], 440 basis[0], basis[1], light_local, depth, light_id); 441 sum += sample_shadow_cubemap_at_offset( 442 D3D_SAMPLE_POINT_POSITIONS[3], D3D_SAMPLE_POINT_COEFFS[3], 443 basis[0], basis[1], light_local, depth, light_id); 444 sum += sample_shadow_cubemap_at_offset( 445 D3D_SAMPLE_POINT_POSITIONS[4], D3D_SAMPLE_POINT_COEFFS[4], 446 basis[0], basis[1], light_local, depth, light_id); 447 sum += sample_shadow_cubemap_at_offset( 448 D3D_SAMPLE_POINT_POSITIONS[5], D3D_SAMPLE_POINT_COEFFS[5], 449 basis[0], basis[1], light_local, depth, light_id); 450 sum += sample_shadow_cubemap_at_offset( 451 D3D_SAMPLE_POINT_POSITIONS[6], D3D_SAMPLE_POINT_COEFFS[6], 452 basis[0], basis[1], light_local, depth, light_id); 453 sum += sample_shadow_cubemap_at_offset( 454 D3D_SAMPLE_POINT_POSITIONS[7], D3D_SAMPLE_POINT_COEFFS[7], 455 basis[0], basis[1], light_local, depth, light_id); 462fn sample_shadow_cubemap_jittered( 463 light_local: vec3<f32>, 466 distance_to_light: f32, 472 var up = vec3(0.0, 1.0, 0.0); 473 if (dot(up, normalize(light_local)) > 0.99) { 474 up = vec3(1.0, 0.0, 0.0); 476 let basis = orthonormalize(light_local, up) * scale * distance_to_light; 478 let rotation_matrix = random_rotation_matrix(vec2(1.0), temporal); 480 let sample_offset0 = rotation_matrix * utils::SPIRAL_OFFSET_0_ * 481 POINT_SHADOW_TEMPORAL_OFFSET_SCALE; 482 let sample_offset1 = rotation_matrix * utils::SPIRAL_OFFSET_1_ * 483 POINT_SHADOW_TEMPORAL_OFFSET_SCALE; 484 let sample_offset2 = rotation_matrix * utils::SPIRAL_OFFSET_2_ * 485 POINT_SHADOW_TEMPORAL_OFFSET_SCALE; 486 let sample_offset3 = rotation_matrix * utils::SPIRAL_OFFSET_3_ * 487 POINT_SHADOW_TEMPORAL_OFFSET_SCALE; 488 let sample_offset4 = rotation_matrix * utils::SPIRAL_OFFSET_4_ * 489 POINT_SHADOW_TEMPORAL_OFFSET_SCALE; 490 let sample_offset5 = rotation_matrix * utils::SPIRAL_OFFSET_5_ * 491 POINT_SHADOW_TEMPORAL_OFFSET_SCALE; 492 let sample_offset6 = rotation_matrix * utils::SPIRAL_OFFSET_6_ * 493 POINT_SHADOW_TEMPORAL_OFFSET_SCALE; 494 let sample_offset7 = rotation_matrix * utils::SPIRAL_OFFSET_7_ * 495 POINT_SHADOW_TEMPORAL_OFFSET_SCALE; 498 sum += sample_shadow_cubemap_at_offset( 499 sample_offset0, 0.125, basis[0], basis[1], light_local, depth, light_id); 500 sum += sample_shadow_cubemap_at_offset( 501 sample_offset1, 0.125, basis[0], basis[1], light_local, depth, light_id); 502 sum += sample_shadow_cubemap_at_offset( 503 sample_offset2, 0.125, basis[0], basis[1], light_local, depth, light_id); 504 sum += sample_shadow_cubemap_at_offset( 505 sample_offset3, 0.125, basis[0], basis[1], light_local, depth, light_id); 506 sum += sample_shadow_cubemap_at_offset( 507 sample_offset4, 0.125, basis[0], basis[1], light_local, depth, light_id); 508 sum += sample_shadow_cubemap_at_offset( 509 sample_offset5, 0.125, basis[0], basis[1], light_local, depth, light_id); 510 sum += sample_shadow_cubemap_at_offset( 511 sample_offset6, 0.125, basis[0], basis[1], light_local, depth, light_id); 512 sum += sample_shadow_cubemap_at_offset( 513 sample_offset7, 0.125, basis[0], basis[1], light_local, depth, light_id); 517fn sample_shadow_cubemap( 518 light_local: vec3<f32>, 519 distance_to_light: f32, 523#ifdef SHADOW_FILTER_METHOD_GAUSSIAN 524 return sample_shadow_cubemap_gaussian( 525 light_local, depth, POINT_SHADOW_SCALE, distance_to_light, light_id); 526#else ifdef SHADOW_FILTER_METHOD_TEMPORAL 527 return sample_shadow_cubemap_jittered( 528 light_local, depth, POINT_SHADOW_SCALE, distance_to_light, light_id, true); 529#else ifdef SHADOW_FILTER_METHOD_HARDWARE_2X2 530 return sample_shadow_cubemap_hardware(light_local, depth, light_id); 547fn search_for_blockers_in_shadow_cubemap( 548 light_local: vec3<f32>, 551 distance_to_light: f32, 556 var up = vec3(0.0, 1.0, 0.0); 557 if (dot(up, normalize(light_local)) > 0.99) { 558 up = vec3(1.0, 0.0, 0.0); 560 let basis = orthonormalize(light_local, up) * scale * distance_to_light; 562 var sum: vec2<f32> = vec2(0.0); 563 sum += search_for_blockers_in_shadow_cubemap_at_offset( 564 D3D_SAMPLE_POINT_POSITIONS[0], basis[0], basis[1], light_local, depth, light_id); 565 sum += search_for_blockers_in_shadow_cubemap_at_offset( 566 D3D_SAMPLE_POINT_POSITIONS[1], basis[0], basis[1], light_local, depth, light_id); 567 sum += search_for_blockers_in_shadow_cubemap_at_offset( 568 D3D_SAMPLE_POINT_POSITIONS[2], basis[0], basis[1], light_local, depth, light_id); 569 sum += search_for_blockers_in_shadow_cubemap_at_offset( 570 D3D_SAMPLE_POINT_POSITIONS[3], basis[0], basis[1], light_local, depth, light_id); 571 sum += search_for_blockers_in_shadow_cubemap_at_offset( 572 D3D_SAMPLE_POINT_POSITIONS[4], basis[0], basis[1], light_local, depth, light_id); 573 sum += search_for_blockers_in_shadow_cubemap_at_offset( 574 D3D_SAMPLE_POINT_POSITIONS[5], basis[0], basis[1], light_local, depth, light_id); 575 sum += search_for_blockers_in_shadow_cubemap_at_offset( 576 D3D_SAMPLE_POINT_POSITIONS[6], basis[0], basis[1], light_local, depth, light_id); 577 sum += search_for_blockers_in_shadow_cubemap_at_offset( 578 D3D_SAMPLE_POINT_POSITIONS[7], basis[0], basis[1], light_local, depth, light_id); 583 return sum.x / sum.y; 591fn sample_shadow_cubemap_pcss( 592 light_local: vec3<f32>, 593 distance_to_light: f32, 598 let z_blocker = search_for_blockers_in_shadow_cubemap( 599 light_local, depth, light_size, distance_to_light, light_id); 602 let blur_size = max((z_blocker - depth) * light_size / depth, 0.5); 604#ifdef SHADOW_FILTER_METHOD_TEMPORAL 605 return sample_shadow_cubemap_jittered( 606 light_local, depth, POINT_SHADOW_SCALE * blur_size, distance_to_light, light_id, true); 608 return sample_shadow_cubemap_jittered( 609 light_local, depth, POINT_SHADOW_SCALE * blur_size, distance_to_light, light_id, false);