float ComputeHeuristic(float fpdf, float gpdf) { #if 0 return BalanceHeuristic(fpdf, gpdf); #else return PowerHeuristic(fpdf, gpdf); #endif }
Color3f Li(const Scene *scene, Sampler *sampler, const Ray3f &ray) const { /* Find the surface that is visible in the requested direction */ Intersection its; //check if the ray intersects the scene if (!scene->rayIntersect(ray, its)) { //check if a distant disk light is set const Emitter* distantsDisk = scene->getDistantEmitter(); if(distantsDisk == nullptr ) return Color3f(0.0f); //sample the distant disk light Vector3f d = ray.d; return distantsDisk->sampleL(d); } //get the Number of lights from the scene const std::vector<Emitter *> lights = scene->getEmitters(); uint32_t nLights = lights.size(); Color3f tp(1.0f, 1.0f, 1.0f); Color3f L(0.0f, 0.0f, 0.0f); Ray3f pathRay(ray.o, ray.d); bool deltaFlag = true; while(true) { if (its.mesh->isEmitter() && deltaFlag) { const Emitter* areaLightEM = its.mesh->getEmitter(); const areaLight* aEM = static_cast<const areaLight *> (areaLightEM); L += tp * aEM->sampleL(-pathRay.d, its.shFrame.n, its); } //Light sampling //randomly select a lightsource uint32_t var = uint32_t(std::min(sampler->next1D()*nLights, float(nLights) - 1.0f)); //init the light color Color3f Li(0.0f, 0.0f, 0.0f); Color3f Ld(1.0f, 1.0f, 1.0f); //create a sample for the light const BSDF* curBSDF = its.mesh->getBSDF(); const Point2f lightSample = sampler->next2D(); VisibilityTester vis; Vector3f wo; float lightpdf; float bsdfpdf; Normal3f n = its.shFrame.n; deltaFlag = curBSDF->isDeltaBSDF(); //sample the light { Li = lights[var]->sampleL(its.p, Epsilon, lightSample , &wo, &lightpdf, &vis); lightpdf /= float(nLights); //check if the pdf of the sample is greater than 0 and if the color is not black if(lightpdf > 0 && Li.maxCoeff() != 0.0f) { //calculate the cosine term wi in my case the vector to the light float cosTerm = std::abs(n.dot(wo)); const BSDFQueryRecord queryEM = BSDFQueryRecord(its.toLocal(- pathRay.d), its.toLocal(wo), EMeasure::ESolidAngle, sampler); Color3f f = curBSDF->eval(queryEM); if(f.maxCoeff() > 0.0f && f.minCoeff() >= 0.0f && vis.Unoccluded(scene)) { bsdfpdf = curBSDF->pdf(queryEM); float weight = BalanceHeuristic(float(1), lightpdf, float(1), bsdfpdf); if(curBSDF->isDeltaBSDF()) weight = 1.0f; if(bsdfpdf > 0.0f) { Ld = (weight * f * Li * cosTerm) / lightpdf; L += tp * Ld; } else { //cout << "bsdfpdf = " << bsdfpdf << endl; //cout << "f = " << f << endl; } } } } //Material part BSDFQueryRecord queryMats = BSDFQueryRecord(its.toLocal(-pathRay.d), Vector3f(0.0f), EMeasure::ESolidAngle, sampler); Color3f fi = curBSDF->sample(queryMats, sampler->next2D()); bsdfpdf = curBSDF->pdf(queryMats); lightpdf = 0.0f; if(fi.maxCoeff() > 0.0f && fi.minCoeff() >= 0.0f) { if(bsdfpdf > 0.0f) { Ray3f shadowRay(its.p, its.toWorld(queryMats.wo)); Intersection lightIsect; if (scene->rayIntersect(shadowRay, lightIsect)) { if(lightIsect.mesh->isEmitter()){ const Emitter* areaLightEMcur = lightIsect.mesh->getEmitter(); const areaLight* aEMcur = static_cast<const areaLight *> (areaLightEMcur); Li = aEMcur->sampleL(-shadowRay.d, lightIsect.shFrame.n, lightIsect); lightpdf = aEMcur->pdf(its.p, (lightIsect.p - its.p).normalized(), lightIsect.p, Normal3f(lightIsect.shFrame.n)); } } else { const Emitter* distantsDisk = scene->getDistantEmitter(); if(distantsDisk != nullptr ) { //check if THIS is right! Li = distantsDisk->sampleL(lightIsect.toWorld(queryMats.wo)); lightpdf = distantsDisk->pdf(Point3f(0.0f), wo, Point3f(0.0f), Normal3f(0.0f)); } } lightpdf /= float(nLights); //calculate the weights float weight = BalanceHeuristic(float(1), bsdfpdf, float(1), lightpdf); //check if the lightcolor is not black if(Li.maxCoeff() > 0.0f && lightpdf > 0.0f ) { //wo in my case the vector to the light Ld = weight * Li * fi; L += tp * Ld; } } tp *= fi; } else { break; } wo = its.toWorld(queryMats.wo); pathRay = Ray3f(its.p, wo); if (!scene->rayIntersect(pathRay, its)) { const Emitter* distantsDisk = scene->getDistantEmitter(); if(distantsDisk != nullptr ) { //sample the distant disk light Vector3f d = pathRay.d; L += tp * distantsDisk->sampleL(d); } break; } float maxCoeff = tp.maxCoeff(); float q = std::min(0.99f, maxCoeff); if(q < sampler->next1D()){ break; } tp /= q; } return L; }
// with direct illumination // this one actually does not do the right things on DI with MIS // left only for reference Spectrum PathTracer::IntegrationWithDI ( const Scene * thisScene, const Ray & ray, size_t currentDepth ) const { // Russian Roulette // probility to stop this path double rr = 0.01; double randnum = getUniformRandomNumber( 0.0, 1.0 ); if ( randnum < rr && currentDepth > 5 ) return Spectrum(); if ( currentDepth == maxDepth ) return Spectrum(); Intersection intersectionInfo; // check intersection between ray and scene if ( !thisScene->IntersectionWithScene( ray, intersectionInfo ) ) return Spectrum(); // if there is an intersection Spectrum intensity; Spectrum lightSourceSamplingContribution; Spectrum brdfSamplingContribution; double brdf_pdf = 0; double light_pdf = 0; double brdf_weight = 0; double light_weight = 0; Objects * obj = intersectionInfo.object; if ( obj->emitter ) { intensity += obj->emission; } BRDFModels * brdf = obj->brdf_model; // **************** evaluate direction illumination ****** if ( !obj->emitter ) EstimateDirectIllumination( thisScene, & intersectionInfo, ray, light_pdf, lightSourceSamplingContribution ); // ******************** end of direct illumination ********************** // BRDF sampling is evaluated twice???? Vector geometryNormalDirection; geometryNormalDirection = intersectionInfo.normal; Vector sampledNextDirection( 0, 0, 0 ); Attenuation attenuationFactor; attenuationFactor = brdf->SampleBRDF( ray.direction, sampledNextDirection, geometryNormalDirection, brdf_pdf ); Ray newRay( intersectionInfo.intersectionPoint, sampledNextDirection ); Spectrum Li = IntegrationWithDI( thisScene, newRay, currentDepth + 1 ); if ( !Li.isEmpty() ) { attenuationFactor.Scaled_by_Spectrum_Value( obj->material_type->color ); double cos_i = AbsDot( sampledNextDirection, geometryNormalDirection ); brdfSamplingContribution += Attenuate_Light_Spectrum( attenuationFactor, Li ) * cos_i; } if ( light_pdf == 0 && brdf_pdf == 0 ) { return intensity; } // MIS weight BalanceHeuristic( 1, light_pdf, 1, brdf_pdf, light_weight, brdf_weight ); intensity += lightSourceSamplingContribution * light_weight; intensity += brdfSamplingContribution * brdf_weight; intensity = ( currentDepth > 5 ) ? ( intensity / ( 1 - rr ) ) : intensity; ASSERT_NAN( intensity ); return intensity; }