diff --git a/crates/bevy_pbr/src/solari/global_illumination/screen_probes_interpolate.wgsl b/crates/bevy_pbr/src/solari/global_illumination/screen_probes_interpolate.wgsl index 4bf89538a442b..55903fb1bb030 100644 --- a/crates/bevy_pbr/src/solari/global_illumination/screen_probes_interpolate.wgsl +++ b/crates/bevy_pbr/src/solari/global_illumination/screen_probes_interpolate.wgsl @@ -28,12 +28,20 @@ fn interpolate_screen_probes(@builtin(global_invocation_id) global_id: vec3 let bl_probe_sample = get_probe_irradiance(bl_probe_id, pixel_world_normal, probe_count); let br_probe_sample = get_probe_irradiance(br_probe_id, pixel_world_normal, probe_count); - let probe_plane_distance_weights = vec4( - plane_distance_weight(tl_probe_id, pixel_world_position, pixel_world_normal), - plane_distance_weight(tr_probe_id, pixel_world_position, pixel_world_normal), - plane_distance_weight(bl_probe_id, pixel_world_position, pixel_world_normal), - plane_distance_weight(br_probe_id, pixel_world_position, pixel_world_normal), + let pixel_depth_linear = view.projection[3][2] / pixel_depth; + let probe_depths = view.projection[3][2] / vec4( + get_probe_depth(tl_probe_id), + get_probe_depth(tr_probe_id), + get_probe_depth(bl_probe_id), + get_probe_depth(br_probe_id), ); + let probe_depth_weights = exp(-abs(probe_depths - pixel_depth_linear) * 100.0); + let probe_normal_weights = pow(vec4( + max(0.0, dot(pixel_world_normal, get_probe_normal(tl_probe_id))), + max(0.0, dot(pixel_world_normal, get_probe_normal(tr_probe_id))), + max(0.0, dot(pixel_world_normal, get_probe_normal(bl_probe_id))), + max(0.0, dot(pixel_world_normal, get_probe_normal(br_probe_id))), + ), vec4(8.0)); let r = fract(probe_id_f); let probe_weights = vec4( @@ -41,7 +49,7 @@ fn interpolate_screen_probes(@builtin(global_invocation_id) global_id: vec3 r.x * (1.0 - r.y), (1.0 - r.x) * r.y, r.x * r.y, - ) * probe_plane_distance_weights; + ) * probe_depth_weights * probe_normal_weights; var irradiance = (tl_probe_sample * probe_weights.x) + (tr_probe_sample * probe_weights.y) + (bl_probe_sample * probe_weights.z) + (br_probe_sample * probe_weights.w); irradiance /= dot(vec4(1.0), probe_weights); @@ -78,15 +86,14 @@ fn get_probe_irradiance(probe_id: vec2, pixel_world_normal: vec3, prob return irradiance; } -fn plane_distance_weight(probe_id: vec2, pixel_world_position: vec3, pixel_world_normal: vec3) -> f32 { +fn get_probe_depth(probe_id: vec2) -> f32 { var probe_center_pixel_id = (probe_id * 8u) + 3u; probe_center_pixel_id = min(probe_center_pixel_id, vec2(view.viewport.zw) - 1u); + return textureLoad(depth_buffer, probe_center_pixel_id, 0i); +} - let probe_depth = textureLoad(depth_buffer, probe_center_pixel_id, 0i); - let probe_center_uv = (vec2(probe_center_pixel_id) + 0.5) / view.viewport.zw; - let probe_world_position = depth_to_world_position(probe_depth, probe_center_uv); - - let plane_distance = abs(dot(probe_world_position - pixel_world_position, pixel_world_normal)); - - return 1.0; // TODO +fn get_probe_normal(probe_id: vec2) -> vec3 { + var probe_center_pixel_id = (probe_id * 8u) + 3u; + probe_center_pixel_id = min(probe_center_pixel_id, vec2(view.viewport.zw) - 1u); + return normalize(textureLoad(normals_buffer, probe_center_pixel_id, 0i).xyz * 2.0 - vec3(1.0)); } diff --git a/crates/bevy_pbr/src/solari/global_illumination/screen_probes_merge_casades.wgsl b/crates/bevy_pbr/src/solari/global_illumination/screen_probes_merge_casades.wgsl index df005805dc8a6..55f00cd05b5ea 100644 --- a/crates/bevy_pbr/src/solari/global_illumination/screen_probes_merge_casades.wgsl +++ b/crates/bevy_pbr/src/solari/global_illumination/screen_probes_merge_casades.wgsl @@ -38,14 +38,14 @@ fn merge_screen_probe_cascades( let bl_probe_sample = sample_upper_probe((bl_probe_id * upper_probe_size) + upper_probe_offset); let br_probe_sample = sample_upper_probe((br_probe_id * upper_probe_size) + upper_probe_offset); - let lower_probe_depth = get_probe_depth(((global_id.xy / lower_probe_size) * lower_probe_size) + ((lower_probe_size >> 1u) - 1u)); - let probe_depths = vec4( + let lower_probe_depth = view.projection[3][2] / get_probe_depth(((global_id.xy / lower_probe_size) * lower_probe_size) + ((lower_probe_size >> 1u) - 1u)); + let probe_depths = view.projection[3][2] / vec4( get_probe_depth((tl_probe_id * upper_probe_size) + (lower_probe_size - 1u)), get_probe_depth((tr_probe_id * upper_probe_size) + (lower_probe_size - 1u)), get_probe_depth((bl_probe_id * upper_probe_size) + (lower_probe_size - 1u)), get_probe_depth((br_probe_id * upper_probe_size) + (lower_probe_size - 1u)), ); - let probe_depth_weights = pow(saturate(1.0 - abs(probe_depths - lower_probe_depth) / lower_probe_depth), vec4(f32(lower_probe_size))); + let probe_depth_weights = exp(-abs(probe_depths - lower_probe_depth) * 3.5); let r = fract(upper_probe_id_f); let probe_weights = vec4( @@ -92,8 +92,7 @@ fn sample_upper_probe_texture(cell_id: vec2) -> vec4 { fn get_probe_depth(pixel_id: vec2) -> f32 { let pixel_id_clamped = min(pixel_id, vec2(view.viewport.zw) - 1u); - let depth = textureLoad(depth_buffer, pixel_id_clamped, 0i); - return view.projection[3][2] / depth; + return textureLoad(depth_buffer, pixel_id_clamped, 0i); } // TODO: Replace with subgroup/wave ops when supported diff --git a/crates/bevy_pbr/src/solari/global_illumination/screen_probes_update.wgsl b/crates/bevy_pbr/src/solari/global_illumination/screen_probes_update.wgsl index e2671a0f413ce..99e1891b7f747 100644 --- a/crates/bevy_pbr/src/solari/global_illumination/screen_probes_update.wgsl +++ b/crates/bevy_pbr/src/solari/global_illumination/screen_probes_update.wgsl @@ -47,13 +47,13 @@ fn update_screen_probes(@builtin(global_invocation_id) global_id: vec3) { ); let current_depth = view.projection[3][2] / probe_depth; - let probe_depths = vec4( + let probe_depths = view.projection[3][2] / vec4( get_probe_previous_depth((tl_probe_id * probe_size) + probe_center_cell_offset), get_probe_previous_depth((tr_probe_id * probe_size) + probe_center_cell_offset), get_probe_previous_depth((bl_probe_id * probe_size) + probe_center_cell_offset), get_probe_previous_depth((br_probe_id * probe_size) + probe_center_cell_offset), ); - let probe_depth_weights = pow(saturate(1.0 - abs(probe_depths - current_depth) / current_depth), vec4(f32(probe_size))); + let probe_depth_weights = exp(-abs(probe_depths - current_depth) * 100.0); let r = fract(reprojected_probe_id_f); let probe_weights = vec4( @@ -114,6 +114,5 @@ fn get_probe_confidence(pixel_id: vec2) -> f32 { fn get_probe_previous_depth(pixel_id: vec2) -> f32 { // TODO: Need to use previous view here let pixel_id_clamped = min(pixel_id, vec2(view.viewport.zw) - 1u); - let depth = textureLoad(previous_depth_buffer, pixel_id_clamped, 0i); - return view.projection[3][2] / depth; + return textureLoad(previous_depth_buffer, pixel_id_clamped, 0i); } diff --git a/crates/bevy_pbr/src/solari/todo.txt b/crates/bevy_pbr/src/solari/todo.txt index e21c0a8706dff..0b7a33356b5db 100644 --- a/crates/bevy_pbr/src/solari/todo.txt +++ b/crates/bevy_pbr/src/solari/todo.txt @@ -1,7 +1,3 @@ -* Consider the weighing functions used for reprojecting/merging/interpolating - * Plane distance used in interpolating seems to do nothing right now - * Ghosting during reprojection - * World cache improvements * Tie world cache to camera, use a log scale for cell size * Short trace distance for sampling from other cells @@ -9,9 +5,11 @@ * Light sources and other cache entries via choosing a random slice of world_cache_active_cell_indices * Think about hashing ray direction, instead of hit position * If visible last frame, reproject last frame's lighting +* Screen cache interpolation weights + * Use plane distance over depth weights? + * Relax reprojection weights for higher cascades? * Screen cache improvements - * Deinterleaved layout for faster upper probe texture reads when merging? - * Jitter per-pixel offset into the interpolation for use with TAA? + * Deinterleaved layout for faster upper probe textupbre reads when merging? * Consider 4x4 probes for the first cascade * 1/2 or 1/4 checkerboard probe update rate * Faster temporal reactivity