mmp / pbrt-v3

Source code for pbrt, the renderer described in the third edition of "Physically Based Rendering: From Theory To Implementation", by Matt Pharr, Wenzel Jakob, and Greg Humphreys.
http://pbrt.org
BSD 2-Clause "Simplified" License
4.86k stars 1.18k forks source link

UniformSampleOneLight: Scaling by nLights #280

Closed AakashKT closed 4 years ago

AakashKT commented 4 years ago

Referring to http://www.pbr-book.org/3ed-2018/Light_Transport_I_Surface_Reflection/Direct_Lighting.html

In the function UniformSampleOneLight(), shouldn't the final radiance be scaled by nLights, as explained? The code does not seem to have this.

Is this an error with the logic or was this removed from the code by mistake?

Thanks! Aakash

AakashKT commented 4 years ago

OK well, my bad sorry. The code seems to be different from the book, but it does include the scaling.

Spectrum UniformSampleOneLight(const Interaction &it, const Scene &scene,
                               MemoryArena &arena, Sampler &sampler,
                               bool handleMedia, const Distribution1D *lightDistrib) {
    ProfilePhase p(Prof::DirectLighting);
    // Randomly choose a single light to sample, _light_
    int nLights = int(scene.lights.size());
    if (nLights == 0) return Spectrum(0.f);
    int lightNum;
    Float lightPdf;
    if (lightDistrib) {
        lightNum = lightDistrib->SampleDiscrete(sampler.Get1D(), &lightPdf);
        if (lightPdf == 0) return Spectrum(0.f);
    } else {
        lightNum = std::min((int)(sampler.Get1D() * nLights), nLights - 1);
        lightPdf = Float(1) / nLights;
    }
    const std::shared_ptr<Light> &light = scene.lights[lightNum];
    Point2f uLight = sampler.Get2D();
    Point2f uScattering = sampler.Get2D();
    return EstimateDirect(it, uScattering, *light, uLight,
                          scene, sampler, arena, handleMedia) / lightPdf;
}

For those who are still confused, the scaling is done according to the probability of selection assigned to the lights. In the simple case, it just assigns uniform probability, making the pdf for each light equal to 1/nLights (the else statement above). The final radiance is then scaled by inverse of this pdf, which has the same effect of multiplying with nLights, in the simple case.

I believe this has been done to allow assignment of probability distributions to light selection. So probably the name of the function should be changed, since its not really Uniform sampling of one light?

Others can correct me if my explanation / understanding is wrong above! Cheers!