55#import bevy_solari :: gbuffer_utils :: gpixel_resolve
66#import bevy_solari :: sampling :: {sample_random_light , random_emissive_light_pdf , sample_ggx_vndf , ggx_vndf_pdf , power_heuristic }
77#import bevy_solari :: scene_bindings :: {trace_ray , resolve_ray_hit_full , ResolvedRayHitFull , RAY_T_MIN , RAY_T_MAX }
8- #import bevy_solari :: world_cache :: {query_world_cache , WORLD_CACHE_CELL_LIFETIME }
8+ #import bevy_solari :: world_cache :: {query_world_cache , get_cell_size , WORLD_CACHE_CELL_LIFETIME }
99
1010@group (1 ) @binding (0 ) var view_output : texture_storage_2d <rgba16float , read_write >;
1111@group (1 ) @binding (5 ) var <storage , read_write > gi_reservoirs_a : array <Reservoir >;
@@ -16,7 +16,7 @@ struct PushConstants { frame_index: u32, reset: u32 }
1616var <push_constant > constants : PushConstants ;
1717
1818const DIFFUSE_GI_REUSE_ROUGHNESS_THRESHOLD : f32 = 0 .4 ;
19- const WORLD_CACHE_TERMINATION_ROUGHNESS_THRESHOLD : f32 = 0 .4 ;
19+ const TERMINATE_IN_WORLD_CACHE_THRESHOLD : f32 = 0 .03 ;
2020
2121@compute @workgroup_size (8 , 8 , 1 )
2222fn specular_gi (@builtin (global_invocation_id ) global_id : vec3 <u32 >) {
@@ -31,7 +31,8 @@ fn specular_gi(@builtin(global_invocation_id) global_id: vec3<u32>) {
3131 }
3232 let surface = gpixel_resolve (textureLoad (gbuffer , global_id . xy , 0 ), depth , global_id . xy , view . main_pass_viewport . zw , view . world_from_clip );
3333
34- let wo = normalize (view . world_position - surface . world_position );
34+ let wo_unnormalized = view . world_position - surface . world_position ;
35+ let wo = normalize (wo_unnormalized );
3536
3637 var radiance : vec3 <f32 >;
3738 var wi : vec3 <f32 >;
@@ -51,7 +52,12 @@ fn specular_gi(@builtin(global_invocation_id) global_id: vec3<u32>) {
5152 wi = wi_tangent . x * T + wi_tangent . y * B + wi_tangent . z * N ;
5253 let pdf = ggx_vndf_pdf (wo_tangent , wi_tangent , surface . material . roughness );
5354
54- radiance = trace_glossy_path (surface . world_position , wi , & rng ) / pdf ;
55+ // https://d1qx31qr3h6wln.cloudfront.net/publications/mueller21realtime.pdf#subsection.3.4, equation (4)
56+ let cos_theta = saturate (dot (wo , surface . world_normal ));
57+ var a0 = dot (wo_unnormalized , wo_unnormalized ) / (4 .0 * PI * cos_theta );
58+ a0 *= TERMINATE_IN_WORLD_CACHE_THRESHOLD ;
59+
60+ radiance = trace_glossy_path (surface . world_position , wi , pdf , a0 , & rng ) / pdf ;
5561 }
5662
5763 let brdf = evaluate_specular_brdf (surface . world_normal , wo , wi , surface . material . base_color , surface . material . metallic ,
@@ -68,11 +74,12 @@ fn specular_gi(@builtin(global_invocation_id) global_id: vec3<u32>) {
6874#endif
6975}
7076
71- fn trace_glossy_path (initial_ray_origin : vec3 <f32 >, initial_wi : vec3 <f32 >, rng : ptr <function , u32 >) -> vec3 <f32 > {
77+ fn trace_glossy_path (initial_ray_origin : vec3 <f32 >, initial_wi : vec3 <f32 >, initial_p_bounce : f32 , a0 : f32 , rng : ptr <function , u32 >) -> vec3 <f32 > {
7278 var ray_origin = initial_ray_origin ;
7379 var wi = initial_wi ;
80+ var p_bounce = initial_p_bounce ;
7481 var surface_perfectly_specular = false ;
75- var p_bounce = 0 .0 ;
82+ var path_spread = 0 .0 ;
7683
7784 // Trace up to three bounces, getting the net throughput from them
7885 var radiance = vec3 (0 .0 );
@@ -99,8 +106,11 @@ fn trace_glossy_path(initial_ray_origin: vec3<f32>, initial_wi: vec3<f32>, rng:
99106 // Should not perform NEE for mirror-like surfaces
100107 surface_perfectly_specular = ray_hit . material . roughness <= 0 .001 && ray_hit . material . metallic > 0 .9999 ;
101108
102- if ray_hit . material . roughness > WORLD_CACHE_TERMINATION_ROUGHNESS_THRESHOLD && i != 0u {
103- // Surface is very rough, terminate path in the world cache
109+ // https://d1qx31qr3h6wln.cloudfront.net/publications/mueller21realtime.pdf#subsection.3.4, equation (3)
110+ path_spread += sqrt ((ray . t * ray . t ) / (p_bounce * wo_tangent . z ));
111+
112+ if path_spread * path_spread > a0 * get_cell_size (ray_hit . world_position , view . world_position ) {
113+ // Path spread is wide enough, terminate path in the world cache
104114 let diffuse_brdf = ray_hit . material . base_color / PI ;
105115 radiance += throughput * diffuse_brdf * query_world_cache (ray_hit . world_position , ray_hit . geometric_world_normal , view . world_position , WORLD_CACHE_CELL_LIFETIME , rng );
106116 break ;
0 commit comments