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?


1 Answer 1


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

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.