1import package::render::{ 2 mesh_view_bindings as view_bindings, 3 utils::interleaved_gradient_noise, 6import bevy_render::maths::{orthonormalize, PI}; 9fn sample_shadow_map_hardware(light_local: vec2<f32>, depth: f32, array_index: i32) -> f32 { 10 @if(NO_ARRAY_TEXTURES_SUPPORT) 11 return textureSampleCompare( 12 view_bindings::directional_shadow_textures, 13 view_bindings::directional_shadow_textures_comparison_sampler, 18 return textureSampleCompareLevel( 19 view_bindings::directional_shadow_textures, 20 view_bindings::directional_shadow_textures_comparison_sampler, 29fn search_for_blockers_in_shadow_map_hardware( 30 light_local: vec2<f32>, 40 @if(PCSS_SAMPLERS_AVAILABLE) { 42 @if(NO_ARRAY_TEXTURES_SUPPORT) 43 let sampled_depth = textureSampleLevel( 44 view_bindings::directional_shadow_textures, 45 view_bindings::directional_shadow_textures_linear_sampler, 50 let sampled_depth = textureSampleLevel( 51 view_bindings::directional_shadow_textures, 52 view_bindings::directional_shadow_textures_linear_sampler, 57 return select(vec2(0.0), vec2(sampled_depth, 1.0), sampled_depth >= depth); 67const SPOT_SHADOW_TEXEL_SIZE: f32 = 0.0134277345; 68const POINT_SHADOW_SCALE: f32 = 0.003; 69const POINT_SHADOW_TEMPORAL_OFFSET_SCALE: f32 = 0.5; 75const D3D_SAMPLE_POINT_POSITIONS: array<vec2<f32>, 8> = array( 89const D3D_SAMPLE_POINT_COEFFS: array<f32, 8> = array( 101fn sample_shadow_map_castano_thirteen(light_local: vec2<f32>, depth: f32, array_index: i32) -> f32 { 102 let shadow_map_size = vec2<f32>(textureDimensions(view_bindings::directional_shadow_textures)); 103 let inv_shadow_map_size = 1.0 / shadow_map_size; 105 let uv = light_local * shadow_map_size; 106 var base_uv = floor(uv + 0.5); 107 let s = (uv.x + 0.5 - base_uv.x); 108 let t = (uv.y + 0.5 - base_uv.y); 110 base_uv *= inv_shadow_map_size; 112 let uw0 = (4.0 - 3.0 * s); 114 let uw2 = (1.0 + 3.0 * s); 116 let u0 = (3.0 - 2.0 * s) / uw0 - 2.0; 117 let u1 = (3.0 + s) / uw1; 118 let u2 = s / uw2 + 2.0; 120 let vw0 = (4.0 - 3.0 * t); 122 let vw2 = (1.0 + 3.0 * t); 124 let v0 = (3.0 - 2.0 * t) / vw0 - 2.0; 125 let v1 = (3.0 + t) / vw1; 126 let v2 = t / vw2 + 2.0; 130 sum += uw0 * vw0 * sample_shadow_map_hardware(base_uv + (vec2(u0, v0) * inv_shadow_map_size), depth, array_index); 131 sum += uw1 * vw0 * sample_shadow_map_hardware(base_uv + (vec2(u1, v0) * inv_shadow_map_size), depth, array_index); 132 sum += uw2 * vw0 * sample_shadow_map_hardware(base_uv + (vec2(u2, v0) * inv_shadow_map_size), depth, array_index); 134 sum += uw0 * vw1 * sample_shadow_map_hardware(base_uv + (vec2(u0, v1) * inv_shadow_map_size), depth, array_index); 135 sum += uw1 * vw1 * sample_shadow_map_hardware(base_uv + (vec2(u1, v1) * inv_shadow_map_size), depth, array_index); 136 sum += uw2 * vw1 * sample_shadow_map_hardware(base_uv + (vec2(u2, v1) * inv_shadow_map_size), depth, array_index); 138 sum += uw0 * vw2 * sample_shadow_map_hardware(base_uv + (vec2(u0, v2) * inv_shadow_map_size), depth, array_index); 139 sum += uw1 * vw2 * sample_shadow_map_hardware(base_uv + (vec2(u1, v2) * inv_shadow_map_size), depth, array_index); 140 sum += uw2 * vw2 * sample_shadow_map_hardware(base_uv + (vec2(u2, v2) * inv_shadow_map_size), depth, array_index); 142 return sum * (1.0 / 144.0); 145fn map(min1: f32, max1: f32, min2: f32, max2: f32, value: f32) -> f32 { 146 return min2 + (value - min1) * (max2 - min2) / (max1 - min1); 152fn random_rotation_matrix(scale: vec2<f32>, temporal: bool) -> mat2x2<f32> { 153 let random_angle = 2.0 * PI * interleaved_gradient_noise( 154 scale, select(1u, view_bindings::globals.frame_count, temporal)); 155 let m = vec2(sin(random_angle), cos(random_angle)); 165fn calculate_uv_offset_scale_jimenez_fourteen(texel_size: f32, blur_size: f32) -> vec2<f32> { 166 let shadow_map_size = vec2<f32>(textureDimensions(view_bindings::directional_shadow_textures)); 169 let f = map(0.00390625, 0.022949219, 0.015, 0.035, texel_size); 170 return f * blur_size / (texel_size * shadow_map_size); 173fn sample_shadow_map_jimenez_fourteen( 174 light_local: vec2<f32>, 177 frag_coord_xy: vec2<f32>, 182 let rotation_matrix = random_rotation_matrix(frag_coord_xy, temporal); 183 let uv_offset_scale = calculate_uv_offset_scale_jimenez_fourteen(texel_size, blur_size); 186 let sample_offset0 = (rotation_matrix * utils::SPIRAL_OFFSET_0_) * uv_offset_scale; 187 let sample_offset1 = (rotation_matrix * utils::SPIRAL_OFFSET_1_) * uv_offset_scale; 188 let sample_offset2 = (rotation_matrix * utils::SPIRAL_OFFSET_2_) * uv_offset_scale; 189 let sample_offset3 = (rotation_matrix * utils::SPIRAL_OFFSET_3_) * uv_offset_scale; 190 let sample_offset4 = (rotation_matrix * utils::SPIRAL_OFFSET_4_) * uv_offset_scale; 191 let sample_offset5 = (rotation_matrix * utils::SPIRAL_OFFSET_5_) * uv_offset_scale; 192 let sample_offset6 = (rotation_matrix * utils::SPIRAL_OFFSET_6_) * uv_offset_scale; 193 let sample_offset7 = (rotation_matrix * utils::SPIRAL_OFFSET_7_) * uv_offset_scale; 196 sum += sample_shadow_map_hardware(light_local + sample_offset0, depth, array_index); 197 sum += sample_shadow_map_hardware(light_local + sample_offset1, depth, array_index); 198 sum += sample_shadow_map_hardware(light_local + sample_offset2, depth, array_index); 199 sum += sample_shadow_map_hardware(light_local + sample_offset3, depth, array_index); 200 sum += sample_shadow_map_hardware(light_local + sample_offset4, depth, array_index); 201 sum += sample_shadow_map_hardware(light_local + sample_offset5, depth, array_index); 202 sum += sample_shadow_map_hardware(light_local + sample_offset6, depth, array_index); 203 sum += sample_shadow_map_hardware(light_local + sample_offset7, depth, array_index); 217fn search_for_blockers_in_shadow_map( 218 light_local: vec2<f32>, 224 let shadow_map_size = vec2<f32>(textureDimensions(view_bindings::directional_shadow_textures)); 225 let uv_offset_scale = search_size / (texel_size * shadow_map_size); 227 let offset0 = D3D_SAMPLE_POINT_POSITIONS[0] * uv_offset_scale; 228 let offset1 = D3D_SAMPLE_POINT_POSITIONS[1] * uv_offset_scale; 229 let offset2 = D3D_SAMPLE_POINT_POSITIONS[2] * uv_offset_scale; 230 let offset3 = D3D_SAMPLE_POINT_POSITIONS[3] * uv_offset_scale; 231 let offset4 = D3D_SAMPLE_POINT_POSITIONS[4] * uv_offset_scale; 232 let offset5 = D3D_SAMPLE_POINT_POSITIONS[5] * uv_offset_scale; 233 let offset6 = D3D_SAMPLE_POINT_POSITIONS[6] * uv_offset_scale; 234 let offset7 = D3D_SAMPLE_POINT_POSITIONS[7] * uv_offset_scale; 237 sum += search_for_blockers_in_shadow_map_hardware(light_local + offset0, depth, array_index); 238 sum += search_for_blockers_in_shadow_map_hardware(light_local + offset1, depth, array_index); 239 sum += search_for_blockers_in_shadow_map_hardware(light_local + offset2, depth, array_index); 240 sum += search_for_blockers_in_shadow_map_hardware(light_local + offset3, depth, array_index); 241 sum += search_for_blockers_in_shadow_map_hardware(light_local + offset4, depth, array_index); 242 sum += search_for_blockers_in_shadow_map_hardware(light_local + offset5, depth, array_index); 243 sum += search_for_blockers_in_shadow_map_hardware(light_local + offset6, depth, array_index); 244 sum += search_for_blockers_in_shadow_map_hardware(light_local + offset7, depth, array_index); 249 return sum.x / sum.y; 253 light_local: vec2<f32>, 256 frag_coord_xy: vec2<f32>, 259 @if(SHADOW_FILTER_METHOD_GAUSSIAN) 260 return sample_shadow_map_castano_thirteen(light_local, depth, array_index); 261 @elif(SHADOW_FILTER_METHOD_TEMPORAL) 262 return sample_shadow_map_jimenez_fourteen( 263 light_local, depth, array_index, frag_coord_xy, texel_size, 1.0, true); 264 @elif(SHADOW_FILTER_METHOD_HARDWARE_2X2) 265 return sample_shadow_map_hardware(light_local, depth, array_index); 285fn sample_shadow_map_pcss( 286 light_local: vec2<f32>, 289 frag_coord_xy: vec2<f32>, 294 let z_blocker = search_for_blockers_in_shadow_map( 295 light_local, depth, array_index, texel_size, light_size); 298 let blur_size = max((z_blocker - depth) * light_size / depth, 0.5); 305 @if(SHADOW_FILTER_METHOD_TEMPORAL) 306 return sample_shadow_map_jimenez_fourteen( 307 light_local, depth, array_index, frag_coord_xy, texel_size, blur_size, true); 309 return sample_shadow_map_jimenez_fourteen( 310 light_local, depth, array_index, frag_coord_xy, texel_size, blur_size, false); 318fn sample_shadow_cubemap_hardware(light_local: vec3<f32>, depth: f32, light_id: u32) -> f32 { 319 @if(NO_CUBE_ARRAY_TEXTURES_SUPPORT) 320 return textureSampleCompare( 321 view_bindings::point_shadow_textures, 322 view_bindings::point_shadow_textures_comparison_sampler, 327 return textureSampleCompareLevel( 328 view_bindings::point_shadow_textures, 329 view_bindings::point_shadow_textures_comparison_sampler, 338fn search_for_blockers_in_shadow_cubemap_hardware( 339 light_local: vec3<f32>, 349 @if(PCSS_SAMPLERS_AVAILABLE) { 351 @if(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, 365 return select(vec2(0.0), vec2(sampled_depth, 1.0), sampled_depth >= depth); 374fn sample_shadow_cubemap_at_offset( 379 light_local: vec3<f32>, 383 return sample_shadow_cubemap_hardware( 384 light_local + position.x * x_basis + position.y * y_basis, 395fn search_for_blockers_in_shadow_cubemap_at_offset( 399 light_local: vec3<f32>, 403 return search_for_blockers_in_shadow_cubemap_hardware( 404 light_local + position.x * x_basis + position.y * y_basis, 415fn sample_shadow_cubemap_gaussian( 416 light_local: vec3<f32>, 419 distance_to_light: f32, 424 let basis = orthonormalize(normalize(light_local)) * scale * distance_to_light; 427 sum += sample_shadow_cubemap_at_offset( 428 D3D_SAMPLE_POINT_POSITIONS[0], D3D_SAMPLE_POINT_COEFFS[0], 429 basis[0], basis[1], light_local, depth, light_id); 430 sum += sample_shadow_cubemap_at_offset( 431 D3D_SAMPLE_POINT_POSITIONS[1], D3D_SAMPLE_POINT_COEFFS[1], 432 basis[0], basis[1], light_local, depth, light_id); 433 sum += sample_shadow_cubemap_at_offset( 434 D3D_SAMPLE_POINT_POSITIONS[2], D3D_SAMPLE_POINT_COEFFS[2], 435 basis[0], basis[1], light_local, depth, light_id); 436 sum += sample_shadow_cubemap_at_offset( 437 D3D_SAMPLE_POINT_POSITIONS[3], D3D_SAMPLE_POINT_COEFFS[3], 438 basis[0], basis[1], light_local, depth, light_id); 439 sum += sample_shadow_cubemap_at_offset( 440 D3D_SAMPLE_POINT_POSITIONS[4], D3D_SAMPLE_POINT_COEFFS[4], 441 basis[0], basis[1], light_local, depth, light_id); 442 sum += sample_shadow_cubemap_at_offset( 443 D3D_SAMPLE_POINT_POSITIONS[5], D3D_SAMPLE_POINT_COEFFS[5], 444 basis[0], basis[1], light_local, depth, light_id); 445 sum += sample_shadow_cubemap_at_offset( 446 D3D_SAMPLE_POINT_POSITIONS[6], D3D_SAMPLE_POINT_COEFFS[6], 447 basis[0], basis[1], light_local, depth, light_id); 448 sum += sample_shadow_cubemap_at_offset( 449 D3D_SAMPLE_POINT_POSITIONS[7], D3D_SAMPLE_POINT_COEFFS[7], 450 basis[0], basis[1], light_local, depth, light_id); 457fn sample_shadow_cubemap_jittered( 458 light_local: vec3<f32>, 460 frag_coord_xy: vec2<f32>, 462 distance_to_light: f32, 466 let rotation_matrix = random_rotation_matrix(frag_coord_xy, temporal); 468 let sample_offset0 = rotation_matrix * utils::SPIRAL_OFFSET_0_ * 469 POINT_SHADOW_TEMPORAL_OFFSET_SCALE; 470 let sample_offset1 = rotation_matrix * utils::SPIRAL_OFFSET_1_ * 471 POINT_SHADOW_TEMPORAL_OFFSET_SCALE; 472 let sample_offset2 = rotation_matrix * utils::SPIRAL_OFFSET_2_ * 473 POINT_SHADOW_TEMPORAL_OFFSET_SCALE; 474 let sample_offset3 = rotation_matrix * utils::SPIRAL_OFFSET_3_ * 475 POINT_SHADOW_TEMPORAL_OFFSET_SCALE; 476 let sample_offset4 = rotation_matrix * utils::SPIRAL_OFFSET_4_ * 477 POINT_SHADOW_TEMPORAL_OFFSET_SCALE; 478 let sample_offset5 = rotation_matrix * utils::SPIRAL_OFFSET_5_ * 479 POINT_SHADOW_TEMPORAL_OFFSET_SCALE; 480 let sample_offset6 = rotation_matrix * utils::SPIRAL_OFFSET_6_ * 481 POINT_SHADOW_TEMPORAL_OFFSET_SCALE; 482 let sample_offset7 = rotation_matrix * utils::SPIRAL_OFFSET_7_ * 483 POINT_SHADOW_TEMPORAL_OFFSET_SCALE; 487 let basis = orthonormalize(normalize(light_local)) * scale * distance_to_light; 490 sum += sample_shadow_cubemap_at_offset( 491 sample_offset0, 0.125, basis[0], basis[1], light_local, depth, light_id); 492 sum += sample_shadow_cubemap_at_offset( 493 sample_offset1, 0.125, basis[0], basis[1], light_local, depth, light_id); 494 sum += sample_shadow_cubemap_at_offset( 495 sample_offset2, 0.125, basis[0], basis[1], light_local, depth, light_id); 496 sum += sample_shadow_cubemap_at_offset( 497 sample_offset3, 0.125, basis[0], basis[1], light_local, depth, light_id); 498 sum += sample_shadow_cubemap_at_offset( 499 sample_offset4, 0.125, basis[0], basis[1], light_local, depth, light_id); 500 sum += sample_shadow_cubemap_at_offset( 501 sample_offset5, 0.125, basis[0], basis[1], light_local, depth, light_id); 502 sum += sample_shadow_cubemap_at_offset( 503 sample_offset6, 0.125, basis[0], basis[1], light_local, depth, light_id); 504 sum += sample_shadow_cubemap_at_offset( 505 sample_offset7, 0.125, basis[0], basis[1], light_local, depth, light_id); 509fn sample_shadow_cubemap( 510 light_local: vec3<f32>, 511 distance_to_light: f32, 514 frag_coord_xy: vec2<f32>, 516 @if(SHADOW_FILTER_METHOD_GAUSSIAN) 517 return sample_shadow_cubemap_gaussian( 518 light_local, depth, POINT_SHADOW_SCALE, distance_to_light, light_id); 519 @elif(SHADOW_FILTER_METHOD_TEMPORAL) 520 return sample_shadow_cubemap_jittered( 521 light_local, depth, frag_coord_xy, POINT_SHADOW_SCALE, distance_to_light, light_id, true); 522 @elif(SHADOW_FILTER_METHOD_HARDWARE_2X2) 523 return sample_shadow_cubemap_hardware(light_local, depth, light_id); 539fn search_for_blockers_in_shadow_cubemap( 540 light_local: vec3<f32>, 543 distance_to_light: f32, 548 let basis = orthonormalize(normalize(light_local)) * scale * distance_to_light; 550 var sum: vec2<f32> = vec2(0.0); 551 sum += search_for_blockers_in_shadow_cubemap_at_offset( 552 D3D_SAMPLE_POINT_POSITIONS[0], basis[0], basis[1], light_local, depth, light_id); 553 sum += search_for_blockers_in_shadow_cubemap_at_offset( 554 D3D_SAMPLE_POINT_POSITIONS[1], basis[0], basis[1], light_local, depth, light_id); 555 sum += search_for_blockers_in_shadow_cubemap_at_offset( 556 D3D_SAMPLE_POINT_POSITIONS[2], basis[0], basis[1], light_local, depth, light_id); 557 sum += search_for_blockers_in_shadow_cubemap_at_offset( 558 D3D_SAMPLE_POINT_POSITIONS[3], basis[0], basis[1], light_local, depth, light_id); 559 sum += search_for_blockers_in_shadow_cubemap_at_offset( 560 D3D_SAMPLE_POINT_POSITIONS[4], basis[0], basis[1], light_local, depth, light_id); 561 sum += search_for_blockers_in_shadow_cubemap_at_offset( 562 D3D_SAMPLE_POINT_POSITIONS[5], basis[0], basis[1], light_local, depth, light_id); 563 sum += search_for_blockers_in_shadow_cubemap_at_offset( 564 D3D_SAMPLE_POINT_POSITIONS[6], basis[0], basis[1], light_local, depth, light_id); 565 sum += search_for_blockers_in_shadow_cubemap_at_offset( 566 D3D_SAMPLE_POINT_POSITIONS[7], basis[0], basis[1], light_local, depth, light_id); 571 return sum.x / sum.y; 579fn sample_shadow_cubemap_pcss( 580 light_local: vec3<f32>, 581 distance_to_light: f32, 585 frag_coord_xy: vec2<f32>, 587 let z_blocker = search_for_blockers_in_shadow_cubemap( 588 light_local, depth, light_size, distance_to_light, light_id); 591 let blur_size = max((z_blocker - depth) * light_size / depth, 0.5); 593 @if(SHADOW_FILTER_METHOD_TEMPORAL) 594 return sample_shadow_cubemap_jittered( 595 light_local, depth, frag_coord_xy, POINT_SHADOW_SCALE * blur_size, distance_to_light, light_id, true); 597 return sample_shadow_cubemap_jittered( 598 light_local, depth, frag_coord_xy, POINT_SHADOW_SCALE * blur_size, distance_to_light, light_id, false);