Skip to content

Commit 28dded1

Browse files
committed
ReSTIR PT wip: Support infinite lights
1 parent d668999 commit 28dded1

File tree

1 file changed

+148
-34
lines changed

1 file changed

+148
-34
lines changed

src/integrator/restir_pt_integrator.cpp

Lines changed: 148 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -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

210201
Rendering* 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

Comments
 (0)