Multiple Importance Sampling Error back

Board: Board index ‹ Ray tracing ‹ General Development

(L) [2011/10/04] [JVillella] [Multiple Importance Sampling Error] Wayback!

Hello fellow tracers,
I have been stuck on this extremely annoying bug for a long time now. I am tying to get direct lighting to work using multiple importance sampling. So i sample lights and bsdf and then weight them. I dont want to abuse these forums by just slapping my code in here and asking for someone to fix it. However, I am getting super frustrated because i don't have a complete understanding on pdf's, MIS, etc. and at this point im almost doing trial and error. So i think i will just post my code and images and if someone figures it out, or has any ideas of the errors maybe they can guide me a bit.
So as for the error, its this image that gives it away.
[IMG #1 Image]
its bright around the edge, thats obviously incorrect. I was using this line of code -->  bsdf_pdf = bsdf.GetPDF(wi, wo, normal, flags);
then i tried this line instead --> bsdf_pdf = bsdf.GetPDF(wo, wi, normal, flags);    (btw, wi is from light and wo is towards camera)
and got this:
[IMG #2 Image]
i then decided to go back to the basics and didnt include pdf's or wieghting and used this line as my return statement --> return f * L * AbsDot(wi, normal);
i got this:
[IMG #3 Image]
It looks a bit better but not right. Lastly i tried this --> return (f * L * AbsDot(wi, normal) * light_pdf) / weight;
and got this:
[IMG #4 Image]
with 32 SPP it looks like this:
[IMG #5 Image]
if you want to see the code for the last image it is this:
RGBColour EstimateDirectLighting(const Vector3D &wo, const Intersection &isect, const BSDF &bsdf,
                                 const Light &light, const BxDFType &flags, const Scene &scene) {
    Normal normal = isect.OrientNormal(wo); //same hemi as wo
    RGBColour Ld(BLACK); //direct light, computed here and returned
    Vector3D wi; //incoming direction
    float light_pdf = 0.0f; float bsdf_pdf = 0.0f;
    ////////////////////////////////////////////////////////////////
    //...Sample Light Source using Multiple Importance Sampling...//
    ////////////////////////////////////////////////////////////////
    VisibilityTester visibility;
    RGBColour L = light.Sample_L(isect, &wi, &light_pdf, &visibility);
    if(!L.IsBlack() && light_pdf > 0.0f) { //L isn't black and pdf is non-zero
        if(!visibility.IsOccluded(scene)) { //if light is unoccluded
            RGBColour f = bsdf.f(wi, wo, flags);
            if(!f.IsBlack()) { //if bsdf isnt black
                //add direct light contribution
                if(light.IsDeltaLight()) { //lights that can't be sampled
                    Ld += f * L * (AbsDot(wi, normal) / light_pdf);
                } else {
//bsdf_pdf = bsdf.GetPDF(wo, wi, normal, flags);
bsdf_pdf = bsdf.GetPDF(wi, wo, normal, flags); //<---- OLD ONE. IT MAY CAUSE ERRORS?
                    float weight = PowerHeuristic(1.0, light_pdf, 1.0, bsdf_pdf);
                    Ld += f * L * (AbsDot(wi, normal) * weight / light_pdf);
return (f * L * AbsDot(wi, normal) * light_pdf) / weight;//(AbsDot(wi, normal) * weight / light_pdf);
//return f * L * AbsDot(wi, normal);//(AbsDot(wi, normal) * weight / light_pdf);

                }
            }
        }
    }
return Ld;
    ////////////////////////////////////////////////////////
    //...Sample BSDF using Multiple Importance Sampling...//
    ////////////////////////////////////////////////////////
    /* Compute following only if the light is not a represented
    by a delta distribtion because there's no chance that sampl-
    ing BSDF will return a direction that hits the light source */
    if(!light.IsDeltaLight()) {
        if(light_pdf == 0.0) {
            return Ld; //dont go any further
        }
        /* The modified value of sampled_type tells
        us what type of BxDF was sampled by the BSDF */
        BxDFType sampled_type;
        RGBColour f = bsdf.Sample_f(&wi, wo, isect, &bsdf_pdf, flags, &sampled_type);
        if(!f.IsBlack() && bsdf_pdf > 0.0) {
            float weight = 1.0f; //if sampled bxdf is of specular type, use weight of 1.0
            if(!sampled_type.get_SPECULAR()) { //specular BxDFs not sampled
                //notice light_pdf and bsdf_pdf have been flipped
                weight = PowerHeuristic(1.0, bsdf_pdf, 1.0, light_pdf);
            }
            //Add light contribution from sampling BSDF
            double t = 0.0; Intersection light_isect;
            Ray wi_ray(isect.hit_point, wi); //uses direction from bsdf.Sample_f
            if(scene.Intersect(wi_ray, &t, &light_isect)) {
                //if the hit object is the light source passed
                if(light_isect.object_ptr == light.GetObjectPtr()) {
                    //add emission from light source
                    L = light_isect.object_ptr->GetMaterial()->GetEmission();
                    if(!L.IsBlack()) {
                        Ld += f * L * AbsDot(wi, normal) * weight / bsdf_pdf;
                    }
                }
            }
        }
    }
    return Ld; //return direct lighting
}

sorry about the messy code. I was doing some debugging
Anyways if someone figures this out, I would be super happy.
Thanks for taking an interest in reading this [SMILEY :)]
From, Julian
[IMG #1]:Not scraped: https://web.archive.org/web/20111021151800im_/http://jvillella.files.wordpress.com/2011/10/old-pdf.jpg
[IMG #2]:Not scraped: https://web.archive.org/web/20111021151800im_/http://jvillella.files.wordpress.com/2011/10/new-pdf.jpg
[IMG #3]:Not scraped: https://web.archive.org/web/20111021151800im_/http://jvillella.files.wordpress.com/2011/10/no-pdf-and-no-weight.jpg
[IMG #4]:Not scraped: https://web.archive.org/web/20111021151800im_/http://jvillella.files.wordpress.com/2011/10/adjust.jpg
[IMG #5]:Not scraped: https://web.archive.org/web/20111021151800im_/http://jvillella.files.wordpress.com/2011/10/adjust_32spp.jpg
(L) [2011/10/04] [ingenious] [Multiple Importance Sampling Error] Wayback!

Can you please please show results on a more meaningful scene, such as a (even empty) Cornell box with an area light source on top? In this scene no one knows where the light source is, how large it is, how the picture should look like, etc.
Hm..  [SMILEY :-k] I can swear I've seen this code with slightly different class names somewhere...    [SMILEY 8)]
(L) [2011/10/04] [JVillella] [Multiple Importance Sampling Error] Wayback!

ya i made this after reading PBRT. My integrators are based on PBRT. Im still new to ray tracing and I need a little carrying along to write a ray tracer.
Ill post some pictures in a few moments.
(L) [2011/10/05] [JVillella] [Multiple Importance Sampling Error] Wayback!

Hmm, maybe if someone could just explain the purpose of the weighting and how they relate to the PDF. I can probably figure it out. Maybe I would understand it better this way. [SMILEY :)]
(L) [2011/10/05] [cignox1] [Multiple Importance Sampling Error] Wayback!

I can't be of much help here but I've noticed this in your code:
VisibilityTester visibility
Which makes me think that you have read the PBRT book (or PBRT/Luxrender code). The book (first edition, at least) offers a quite nice explanation of MIS...
EDIT: sorry, I did not see that you already said you followed that book...
(L) [2011/10/05] [viewon01] [Multiple Importance Sampling Error] Wayback!

Hi,
Are you sure that it is a MIS problem ?
It looks like a shadowing problem too ! Maybe play with the shadow ray precision. By example when you trace a shadow ray you must be sure that it does not start exactly from the sphere, but just after, otherwise you will have a shadow ray that intersect the sphere too ! Hum, maybe it is not related ! A cornell box or something like that can help you... because the effect can be very different depending of the kind of surface [SMILEY ;-)]
Try to isolate the code that do this problem, maybe do simple IS before.
(L) [2011/10/05] [brecht] [Multiple Importance Sampling Error] Wayback!

It's better to break up the problem and verify that the basics are working first. Check independently that BSDF sampling and light sampling are working correct, see if they are lighting the right side of the surface, have inverse square distance falloff and cosine angle falloff. Then check if they converge to the same image, and only once that's the case, add multiple importance sampling.
(L) [2011/10/05] [JVillella] [Multiple Importance Sampling Error] Wayback!

Thanks guys for your quick replies. I'll try a Cornell box tonight and post some pics. Would someone be able to explain really simply the purpose of the PDF and weighting, like how they all fit together. I did read PBRT and some other websites on this but to be honest it is over my head in terms of the mathematics. Maybe someone with more experience can put it as simply as possible for me. [SMILEY :)]
Thanks,
Julian
(L) [2011/10/05] [friedlinguini] [Multiple Importance Sampling Error] Wayback!

Suppose you're ray-tracing a glossy surface. You could cast a reflected ray in any direction, get an incoming radiance, multiply by the BRDF, cosine factor, and a constant normalization factor and call it a day. However, if there's a specular highlight you'll get pretty slow convergence, because the odds are pretty small that your reflected ray will hit the source of the highlight. However, if you fire more reflected rays close to the ideal reflected direction you're more likely to get those "important" paths. If you're doing something to fire rays with a particular density, then you're adjusting the probability density of ray directions, and that's where the PDF comes in. You can't just arbitrarily change the ray density and not expect it to affect your average result, so you divide your sample result by the PDF of that sample. If you're rendering, a very dark sample with a high PDF doesn't contribute much and is generally wasteful, while a bright sample combined with a low PDF will create a very bright spot in your image that will require many samples to average down to the correct value. You ideally want to massage your PDFs to generate most of your rays in directions that contribute significantly to the image without neglecting other directions. You minimize variance if your PDF is proportional to the sample value. Trying to match the PDF to the sample function is called importance sampling.
Unfortunately, when you're rendering you often have to generally have to multiply light contribution by a BRDF to get a sample value. There are ways to generate rays with a PDF proportional to the BRDF, and there are ways to generate rays with a PDF sort-of close to the directions of contributing light sources (by picking points on the light source, casting a shadow ray, etc.), but it's difficult to generate rays with a PDF proportional to the product of the two. You usually have to pick one or the other. This can lead to the high variance problems I mentioned. Each technique generates unbiased samples that estimate the reflected illumination, so taking a weighted average of the samples should still be unbiased. MIS attempts to pick weights for that weighted average that minimizes the variance of the combined estimate. The weights are generated by looking at the probability that a particular sample generated by a particular technique could have been generated by _any_ of the techniques being used. A bright sample might be generated with a low PDF using one technique, but with a high PDF using another. MIS adjusts the weight of such a sample so that it doesn't generate an overly bright pixel that will need many more samples to fix.
As others have suggested, it's best to start simple. Deal with one technique at a time (BRDF sampling OR explicit light source sampling) to get an intuition for the use of PDFs and importance sampling. Then move on to MIS. Check out Veach's paper on the subject ([LINK http://graphics.stanford.edu/papers/combine/]) and his thesis ([LINK http://graphics.stanford.edu/papers/veach_thesis/]) in addition to PBRT.

back