11#define_import_path bevy_solari :: specular_gi
22
33#import bevy_pbr :: pbr_functions :: {calculate_tbn_mikktspace , calculate_diffuse_color , calculate_F0 }
4- #import bevy_pbr :: prepass_bindings :: PreviousViewUniforms
54#import bevy_render :: maths :: {orthonormalize , PI }
65#import bevy_render :: view :: View
76#import bevy_solari :: brdf :: {evaluate_brdf , evaluate_specular_brdf }
1716
1817const DIFFUSE_GI_REUSE_ROUGHNESS_THRESHOLD : f32 = 0 .4 ;
1918const SPECULAR_GI_FOR_DI_ROUGHNESS_THRESHOLD : f32 = 0 .0225 ;
20- const TERMINATE_IN_WORLD_CACHE_THRESHOLD : f32 = 0 .03 ;
2119
2220@compute @workgroup_size (8 , 8 , 1 )
2321fn specular_gi (@builtin (global_invocation_id ) global_id : vec3 <u32 >) {
@@ -33,7 +31,8 @@ fn specular_gi(@builtin(global_invocation_id) global_id: vec3<u32>) {
3331 let surface = gpixel_resolve (textureLoad (gbuffer , global_id . xy , 0 ), depth , global_id . xy , view . main_pass_viewport . zw , view . world_from_clip );
3432
3533 let wo_unnormalized = view . world_position - surface . world_position ;
36- let wo = normalize (wo_unnormalized );
34+ let wo_length = length (wo_unnormalized );
35+ let wo = wo_unnormalized / wo_length ;
3736
3837 var radiance : vec3 <f32 >;
3938 var wi : vec3 <f32 >;
@@ -53,12 +52,7 @@ fn specular_gi(@builtin(global_invocation_id) global_id: vec3<u32>) {
5352 wi = wi_tangent . x * T + wi_tangent . y * B + wi_tangent . z * N ;
5453 let pdf = ggx_vndf_pdf (wo_tangent , wi_tangent , surface . material . roughness );
5554
56- // https://d1qx31qr3h6wln.cloudfront.net/publications/mueller21realtime.pdf#subsection.3.4, equation (4)
57- let cos_theta = saturate (dot (wo , surface . world_normal ));
58- var a0 = dot (wo_unnormalized , wo_unnormalized ) / (4 .0 * PI * cos_theta );
59- a0 *= TERMINATE_IN_WORLD_CACHE_THRESHOLD ;
60-
61- radiance = trace_glossy_path (global_id . xy , surface , wi , pdf , a0 , & rng ) / pdf ;
55+ radiance = trace_glossy_path (global_id . xy , surface , wo_length , wi , pdf , & rng ) / pdf ;
6256 }
6357
6458 let brdf = evaluate_specular_brdf (surface . world_normal , wo , wi , surface . material . base_color , surface . material . metallic ,
@@ -74,15 +68,15 @@ fn specular_gi(@builtin(global_invocation_id) global_id: vec3<u32>) {
7468#endif
7569}
7670
77- fn trace_glossy_path (pixel_id : vec2 <u32 >, primary_surface : ResolvedGPixel , initial_wi : vec3 < f32 >, initial_p_bounce : f32 , a0 : f32 , rng : ptr <function , u32 >) -> vec3 <f32 > {
71+ fn trace_glossy_path (pixel_id : vec2 <u32 >, primary_surface : ResolvedGPixel , initial_ray_t : f32 , initial_wi : vec3 < f32 >, initial_p_bounce : f32 , rng : ptr <function , u32 >) -> vec3 <f32 > {
7872 var radiance = vec3 (0 .0 );
7973 var throughput = vec3 (1 .0 );
8074
8175 var ray_origin = primary_surface . world_position ;
8276 var wi = initial_wi ;
8377 var p_bounce = initial_p_bounce ;
8478 var surface_perfect_mirror = false ;
85- var path_spread = 0 .0 ;
79+ var path_spread = path_spread_heuristic ( initial_ray_t , primary_surface . material . roughness ) ;
8680
8781#ifdef DLSS_RR_GUIDE_BUFFERS
8882 var mirror_rotations = reflection_matrix (primary_surface . world_normal );
@@ -111,9 +105,6 @@ fn trace_glossy_path(pixel_id: vec2<u32>, primary_surface: ResolvedGPixel, initi
111105 // Should not perform NEE for mirror-like surfaces
112106 surface_perfect_mirror = ray_hit . material . roughness <= MIRROR_ROUGHNESS_THRESHOLD && ray_hit . material . metallic > 0 .9999 ;
113107
114- // https://d1qx31qr3h6wln.cloudfront.net/publications/mueller21realtime.pdf#subsection.3.4, equation (3)
115- path_spread += sqrt ((ray . t * ray . t ) / (p_bounce * wo_tangent . z ));
116-
117108 // Primary surface replacement for perfect mirrors
118109 // https://developer.nvidia.com/blog/rendering-perfect-reflections-and-refractions-in-path-traced-games/#primary_surface_replacement
119110#ifdef DLSS_RR_GUIDE_BUFFERS
@@ -127,8 +118,12 @@ fn trace_glossy_path(pixel_id: vec2<u32>, primary_surface: ResolvedGPixel, initi
127118 }
128119#endif
129120
130- if path_spread * path_spread > a0 * get_cell_size (ray_hit . world_position , view . world_position ) {
131- // Path spread is wide enough, terminate path in the world cache
121+ // Terminate path in the world cache if the ray is long enough and the path spread is large enough
122+ let world_cache_cell_size = get_cell_size (ray_hit . world_position , view . world_position );
123+ let ray_longer_than_cell = ray . t > sqrt (3 .0 ) * world_cache_cell_size ;
124+ let path_spread_large_enough = path_spread > world_cache_cell_size * world_cache_cell_size ;
125+
126+ if ray_longer_than_cell && path_spread_large_enough {
132127 let diffuse_brdf = ray_hit . material . base_color / PI ;
133128 radiance += throughput * diffuse_brdf * query_world_cache (ray_hit . world_position , ray_hit . geometric_world_normal , view . world_position , ray . t , WORLD_CACHE_CELL_LIFETIME , rng );
134129 break ;
@@ -148,8 +143,10 @@ fn trace_glossy_path(pixel_id: vec2<u32>, primary_surface: ResolvedGPixel, initi
148143 // Update throughput for next bounce
149144 p_bounce = ggx_vndf_pdf (wo_tangent , wi_tangent , ray_hit . material . roughness );
150145 let brdf = evaluate_brdf (N , wo , wi , ray_hit . material );
151- let cos_theta = saturate (dot (wi , N ));
152- throughput *= (brdf * cos_theta ) / p_bounce ;
146+ throughput *= brdf / p_bounce ;
147+
148+ // Path spread increase
149+ path_spread += path_spread_heuristic (ray . t , ray_hit . material . roughness );
153150 }
154151
155152 return radiance ;
@@ -186,6 +183,12 @@ fn nee_mis_weight(inverse_p_light: f32, brdf_rays_can_hit: bool, wo_tangent: vec
186183 return power_heuristic (p_light , p_bounce );
187184}
188185
186+ fn path_spread_heuristic (ray_t : f32 , roughness : f32 ) -> f32 {
187+ let alpha_squared = min (roughness * roughness , 0 .99 );
188+ let distance_squared = ray_t * ray_t ;
189+ return distance_squared * 0 .5 * (alpha_squared / (1 .0 - alpha_squared ));
190+ }
191+
189192#ifdef DLSS_RR_GUIDE_BUFFERS
190193// https://en.wikipedia.org/wiki/Householder_transformation
191194fn reflection_matrix (plane_normal : vec3f ) -> mat3x3 <f32 > {
0 commit comments