# Confusion about PDF defined in solid angle / area measure

When using MIS, we always want to express the PDF value in a unified measure in order not to render the ratio between them meaningless. Yet when I read through chapter 16 of PBR-book, I got confused by how to choose the correct measure.

First, I see that in subpath connection s == 1 (only one vertex on the light path is used) case, we first need to sample (sort of like) direct component if the light vertex is connectible:

Spectrum lightWeight = light->Sample_Li(pt.GetInteraction(), sampler.Get2D(),
&wi, &pdf, &vis);


Here, pdf is computed in Sample_Li method, and it is later used for

sampled = Vertex::CreateLight(ei, lightWeight / (pdf * lightPdf), 0);


Typical MC estimation step, right? In unidirectional path tracing, pdf * lightPdf is defined in solid angle measure, so after sampling a vertex on an area source (with pdf = 1. / area), we should convert the pdf to solid angle measure using length^2 / cos. However, in pbrt-v3, Sample_Li seems to return pdf defined in area measure. Here I quote the code from lights/diffusive.cpp in pbrt-v3:

Interaction pShape = shape->Sample(ref, u, pdf);


And the sample method (for example, if the shape is triangle):

Interaction Triangle::Sample(const Point2f &u, Float *pdf) const {
/** ... */
*pdf = 1 / Area();
/** ... */
}


To me, it doesn't seem like the conversion is done. To make it even more confusing, pbr-book says:

Like Sample_Li(), the PDF value this method returns is defined with respect to solid angle at the reference point. [reference]

And yes, Sample_Wi() does return pdf defined in solid angle measure:

// pdf calculation defined in Sample_Wi
*pdf = (dist * dist) / (AbsDot(lensIntr.n, *wi) * lensArea);


Yet, lightWeight seems to be divided by pdf returned by Sample_Li(), which seems to be defined in area measure. This is baffling me a lot? Did misunderstand anything here? Is this some kind of weird mechanism in BDPT?

Actually,shape->Sample(ref, u, pdf) returns the pdf in solid angle measure.The sample function in sample is actually this.

Interaction Shape::Sample(const Interaction &ref, const Point2f &u,
Float *pdf) const {
Interaction intr = Sample(u, pdf);
Vector3f wi = intr.p - ref.p;
if (wi.LengthSquared() == 0)
*pdf = 0;
else {
wi = Normalize(wi);
// Convert from area measure, as returned by the Sample() call
// above, to solid angle measure.
*pdf *= DistanceSquared(ref.p, intr.p) / AbsDot(intr.n, -wi);
if (std::isinf(*pdf)) *pdf = 0.f;
}
return intr;
}


This function will call virtual function sample( virtual Interaction Sample(const Point2f &u, Float *pdf) const = 0;) ,which is also the function in your triangle example.So the virtual function computes pdf in area measure,and the non-virtual function comverts pdf to the solid angle measute

• Thanks, I think you are right. Mar 15, 2023 at 13:05