1+ #define_import_path bevy_solari :: specular_gi
2+
13#import bevy_pbr :: pbr_functions :: calculate_tbn_mikktspace
24#import bevy_render :: maths :: {orthonormalize , PI }
35#import bevy_render :: view :: View
@@ -16,6 +18,7 @@ struct PushConstants { frame_index: u32, reset: u32 }
1618var < push_constant > constants : PushConstants ;
1719
1820const DIFFUSE_GI_REUSE_ROUGHNESS_THRESHOLD : f32 = 0 .4 ;
21+ const SPECULAR_GI_FOR_DI_ROUGHNESS_THRESHOLD : f32 = 0 .0225 ;
1922const TERMINATE_IN_WORLD_CACHE_THRESHOLD : f32 = 0 .03 ;
2023
2124@compute @workgroup_size (8 , 8 , 1 )
@@ -57,7 +60,7 @@ fn specular_gi(@builtin(global_invocation_id) global_id: vec3<u32>) {
5760 var a0 = dot (wo_unnormalized , wo_unnormalized ) / (4 .0 * PI * cos_theta );
5861 a0 *= TERMINATE_IN_WORLD_CACHE_THRESHOLD ;
5962
60- radiance = trace_glossy_path (surface . world_position , wi , pdf , a0 , & rng ) / pdf ;
63+ radiance = trace_glossy_path (surface . world_position , wi , surface . material . roughness , pdf , a0 , & rng ) / pdf ;
6164 }
6265
6366 let brdf = evaluate_specular_brdf (surface . world_normal , wo , wi , surface . material . base_color , surface . material . metallic ,
@@ -74,7 +77,7 @@ fn specular_gi(@builtin(global_invocation_id) global_id: vec3<u32>) {
7477#endif
7578}
7679
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 > {
80+ fn trace_glossy_path (initial_ray_origin : vec3 <f32 >, initial_wi : vec3 <f32 >, initial_roughness : f32 , initial_p_bounce : f32 , a0 : f32 , rng : ptr <function , u32 >) -> vec3 <f32 > {
7881 var ray_origin = initial_ray_origin ;
7982 var wi = initial_wi ;
8083 var p_bounce = initial_p_bounce ;
@@ -98,10 +101,9 @@ fn trace_glossy_path(initial_ray_origin: vec3<f32>, initial_wi: vec3<f32>, initi
98101 let wo = - wi ;
99102 let wo_tangent = vec3 (dot (wo , T ), dot (wo , B ), dot (wo , N ));
100103
101- // Add emissive contribution (but not on the first bounce, since ReSTIR DI handles that)
102- if i != 0u {
103- radiance += throughput * emissive_mis_weight (p_bounce , ray_hit , surface_perfectly_specular ) * ray_hit . material . emissive ;
104- }
104+ // Add emissive contribution
105+ let mis_weight = emissive_mis_weight (i , initial_roughness , p_bounce , ray_hit , surface_perfectly_specular );
106+ radiance += throughput * mis_weight * ray_hit . material . emissive ;
105107
106108 // Should not perform NEE for mirror-like surfaces
107109 surface_perfectly_specular = ray_hit . material . roughness <= 0 .001 && ray_hit . material . metallic > 0 .9999 ;
@@ -137,11 +139,20 @@ fn trace_glossy_path(initial_ray_origin: vec3<f32>, initial_wi: vec3<f32>, initi
137139 return radiance ;
138140}
139141
140- fn emissive_mis_weight (p_bounce : f32 , ray_hit : ResolvedRayHitFull , previous_surface_perfectly_specular : bool ) -> f32 {
141- if previous_surface_perfectly_specular { return 1 .0 ; }
142+ fn emissive_mis_weight (i : u32 , initial_roughness : f32 , p_bounce : f32 , ray_hit : ResolvedRayHitFull , previous_surface_perfectly_specular : bool ) -> f32 {
143+ if i != 0u {
144+ if previous_surface_perfectly_specular { return 1 .0 ; }
142145
143- let p_light = random_emissive_light_pdf (ray_hit );
144- return power_heuristic (p_bounce , p_light );
146+ let p_light = random_emissive_light_pdf (ray_hit );
147+ return power_heuristic (p_bounce , p_light );
148+ } else {
149+ // The first bounce gets MIS weight 0.0 or 1.0 depending on if ReSTIR DI shaded using the specular lobe or not
150+ if initial_roughness <= SPECULAR_GI_FOR_DI_ROUGHNESS_THRESHOLD {
151+ return 1 .0 ;
152+ } else {
153+ return 0 .0 ;
154+ }
155+ }
145156}
146157
147158fn nee_mis_weight (inverse_p_light : f32 , brdf_rays_can_hit : bool , wo_tangent : vec3 <f32 >, wi : vec3 <f32 >, ray_hit : ResolvedRayHitFull , TBN : mat3x3 <f32 >) -> f32 {
0 commit comments