@@ -39,6 +39,7 @@ struct ReSTIRPTSample
3939 uint64 seed; // RNG seed for hybrid shift replay
4040
4141 const Light* light = nullptr ;
42+ bool is_infinite_light = false ;
4243
4344 Intersection isect;
4445 Vec3 wi = Vec3::zero; // Incident direction to reconnection vertex
@@ -193,18 +194,8 @@ ReSTIRPTIntegrator::ReSTIRPTIntegrator(
193194 , max_bounces{ max_bounces }
194195 , rr_min_bounces{ rr_min_bounces }
195196 , spatial_radius{ std::max (0 .0f , spatial_radius) }
197+ , num_spatial_samples{ std::max (1 , spatial_samples) }
196198{
197- // Assume scene contains area lights only
198- BulbitAssert (area_lights.Size () == all_lights.size ());
199-
200- if (spatial_samples <= 0 )
201- {
202- num_spatial_samples = std::min (2 , int32 (pi * Sqr (spatial_radius) * 0 .05f ));
203- }
204- else
205- {
206- num_spatial_samples = spatial_samples;
207- }
208199}
209200
210201Rendering* ReSTIRPTIntegrator::Render (Allocator& alloc, const Camera* camera)
@@ -283,6 +274,91 @@ Rendering* ReSTIRPTIntegrator::Render(Allocator& alloc, const Camera* camera)
283274 if (bounce == 0 )
284275 {
285276 vp.isect .primitive = nullptr ;
277+ for (Light* light : infinite_lights)
278+ {
279+ vp.Le += light->Le (ray);
280+ }
281+ }
282+ else
283+ {
284+ int32 vertex_index = bounce + 1 ;
285+ for (Light* light : infinite_lights)
286+ {
287+ Spectrum Le = light->Le (ray);
288+ if (Le.IsBlack ())
289+ {
290+ continue ;
291+ }
292+
293+ Spectrum L;
294+ if (specular_bounce)
295+ {
296+ L = Le;
297+ }
298+ else
299+ {
300+ Float light_pdf = light_sampler->EvaluatePMF (light) * light->EvaluatePDF_Li (ray);
301+ Float mis_weight = BalanceHeuristic (1 , prev_bsdf_pdf, 1 , light_pdf);
302+ L = mis_weight * Le;
303+ }
304+
305+ ReSTIRPTSample sample;
306+ sample.seed = seed;
307+ sample.is_infinite_light = true ;
308+ if (reconnection_vertex > 0 )
309+ {
310+ sample.reconnection_vertex = reconnection_vertex;
311+ if (vertex_index == reconnection_vertex)
312+ {
313+ // Reconnection vertex is the light vertex (infinite light)
314+ sample.flag = bsdf_sampled | light_vertex;
315+ sample.light = light;
316+ sample.isect .primitive = nullptr ;
317+ sample.isect .point = ray.o + ray.d ;
318+ sample.isect .normal = Vec3::zero;
319+ sample.wi = ray.d ;
320+ sample.L = Le;
321+ sample.jacobian = rc_jacobian;
322+ }
323+ else if (vertex_index == reconnection_vertex + 1 )
324+ {
325+ // Reconnection vertex is previous vertex
326+ sample.flag = bsdf_sampled | preceding_light_vertex;
327+ sample.light = light;
328+ sample.isect = rc_isect;
329+ sample.wi = rc_wi;
330+ sample.L = Le;
331+ sample.jacobian = rc_jacobian;
332+ }
333+ else
334+ {
335+ // Reconnection vertex is set far before the light vertex
336+ sample.flag = mid_vertex;
337+ sample.light = nullptr ;
338+ sample.isect = rc_isect;
339+ sample.wi = rc_wi;
340+ sample.L = rc_beta * L;
341+ sample.jacobian = rc_jacobian;
342+ }
343+ }
344+ else
345+ {
346+ // Reconnection vertex is the light vertex
347+ sample.reconnection_vertex = prev_diffuse ? vertex_index : -1 ;
348+ sample.flag = bsdf_sampled | light_vertex;
349+ sample.light = light;
350+ sample.isect .primitive = nullptr ;
351+ sample.isect .point = ray.o + ray.d ;
352+ sample.isect .normal = Vec3::zero;
353+ sample.wi = ray.d ;
354+ sample.L = Le;
355+ sample.jacobian = 1 / prev_bsdf_pdf;
356+ }
357+
358+ sample.contribution = beta * L;
359+ sample.p_hat = sample.contribution .Luminance ();
360+ reservoir.Add (sample, sample.p_hat );
361+ }
286362 }
287363
288364 break ;
@@ -469,6 +545,7 @@ Rendering* ReSTIRPTIntegrator::Render(Allocator& alloc, const Camera* camera)
469545 // Reconnection vertex is preceding the light vertex
470546 sample.flag = light_sampled | preceding_light_vertex;
471547 sample.light = sampled_light.light ;
548+ sample.is_infinite_light = sampled_light.light ->IsInfiniteLight ();
472549 sample.isect = rc_isect;
473550 sample.wi = light_sample.wi ;
474551 sample.L = light_sample.Li ;
@@ -491,13 +568,25 @@ Rendering* ReSTIRPTIntegrator::Render(Allocator& alloc, const Camera* camera)
491568 sample.reconnection_vertex = is_diffuse ? (vertex_index + 1 ) : -1 ;
492569 sample.flag = light_sampled | light_vertex;
493570 sample.light = sampled_light.light ;
571+ sample.is_infinite_light = sampled_light.light ->IsInfiniteLight ();
494572 sample.isect .primitive = nullptr ;
495- sample.isect .point = light_sample.point ;
496- sample.isect .normal = light_sample.normal ;
497- sample.wi = Vec3::zero;
573+ if (sample.is_infinite_light )
574+ {
575+ sample.isect .point = isect.point + light_sample.wi ;
576+ sample.isect .normal = Vec3::zero;
577+ sample.wi = light_sample.wi ;
578+ sample.jacobian = 1 / light_pdf;
579+ }
580+ else
581+ {
582+ sample.isect .point = light_sample.point ;
583+ sample.isect .normal = light_sample.normal ;
584+ sample.wi = Vec3::zero;
585+ sample.jacobian =
586+ (Sqr (light_sample.visibility ) / AbsDot (light_sample.normal , light_sample.wi )) /
587+ light_pdf;
588+ }
498589 sample.L = light_sample.Li ;
499- sample.jacobian =
500- (Sqr (light_sample.visibility ) / AbsDot (light_sample.normal , light_sample.wi )) / light_pdf;
501590 }
502591
503592 sample.contribution = beta * f_cos * L;
@@ -728,34 +817,59 @@ Rendering* ReSTIRPTIntegrator::Render(Allocator& alloc, const Camera* camera)
728817 return false ;
729818 }
730819
731- // wo: y_{k-1} -> y_{k-2}
732- // wi: y_{k-1} -> x_k
733- // sample.wi: x_k -> x_{k+1}
734- Vec3 wi = source_sample.isect .point - replay.isect .point ;
735- Float d2 = Length2 (wi);
736- Float d = std::sqrt (d2);
737- wi /= d;
738-
739820 BSDF bsdf;
740821 if (!replay.isect .GetBSDF (&bsdf, replay.wo , bsdf_alloc))
741822 {
742823 return false ;
743824 }
744825
745- Ray shadow_ray (replay.isect .point , wi);
746- if (IntersectAny (shadow_ray, Ray::epsilon, d - Ray::epsilon))
826+ // wo: y_{k-1} -> y_{k-2}
827+ // wi: y_{k-1} -> x_k
828+ // source_sample.wi: x_k -> x_{k+1}
829+ Vec3 wi;
830+ Ray shadow_ray;
831+ Float jacobian = 0 ;
832+ if ((source_sample.flag & light_vertex) && source_sample.is_infinite_light )
747833 {
748- return false ;
749- }
834+ wi = source_sample. wi ;
835+ shadow_ray = Ray (replay. isect . point , wi);
750836
751- Float bsdf_pdf = bsdf.PDF (replay.wo , wi);
752- if (bsdf_pdf == 0 )
837+ // Infinite lights are connected in solid angle measure
838+ Intersection shadow_isect;
839+ while (Intersect (&shadow_isect, shadow_ray, Ray::epsilon, infinity))
840+ {
841+ if (shadow_isect.primitive ->GetMaterial ())
842+ {
843+ return false ;
844+ }
845+
846+ shadow_ray.o = shadow_isect.point ;
847+ }
848+
849+ jacobian = 1 ;
850+ }
851+ else
753852 {
754- return false ;
853+ wi = source_sample.isect .point - replay.isect .point ;
854+ Float d2 = Length2 (wi);
855+ Float d = std::sqrt (d2);
856+ wi /= d;
857+
858+ shadow_ray = Ray (replay.isect .point , wi);
859+ if (IntersectAny (shadow_ray, Ray::epsilon, d - Ray::epsilon))
860+ {
861+ return false ;
862+ }
863+
864+ jacobian = std::max (0 .0f , (Dot (source_sample.isect .normal , -wi) / d2));
865+ if (jacobian == 0 )
866+ {
867+ return false ;
868+ }
755869 }
756870
757- Float jacobian = std::max ( 0 . 0f , ( Dot (source_sample. isect . normal , -wi) / d2) );
758- if (jacobian == 0 )
871+ Float bsdf_pdf = bsdf. PDF (replay. wo , wi );
872+ if (bsdf_pdf == 0 )
759873 {
760874 return false ;
761875 }
@@ -990,7 +1104,7 @@ Rendering* ReSTIRPTIntegrator::Render(Allocator& alloc, const Camera* camera)
9901104
9911105 if (!vp.isect .primitive )
9921106 {
993- progress->film .AddSample (pixel, Spectrum::black );
1107+ progress->film .AddSample (pixel, vp. primary_weight * vp. Le );
9941108 continue ;
9951109 }
9961110
0 commit comments