(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