std::vector<PathNode> BidirectionalIntegrator::generateEyePath(Ray r) { std::vector<PathNode> eyePath; eyePath.clear(); Intersection isx = intersection_engine->GetIntersection(r); int depth=0; while(depth<max_depth && isx.t > 0) { // store the path node PathNode node; node.isx = isx; node.dirIn_world = -r.direction; node.dirIn_local = isx.ToLocalNormalCoordinate(-r.direction); node.F = isx.object_hit->material->SampleAndEvaluateScatteredEnergy(isx,node.dirIn_local,node.dirOut_local,node.pdf); node.dirOut_world = isx.ToWorldNormalCoordinate(node.dirOut_local); if(node.pdf != 0) eyePath.push_back(node); else break; //update r r = Ray(isx.point + glm::sign(glm::dot(node.dirOut_world,isx.normal)) * isx.normal*1e-3f, node.dirOut_world); // update isx and depth info depth++; isx = intersection_engine->GetIntersection(r); } return eyePath; }
// MIS: sampling BRDF glm::vec3 BidirectionalIntegrator::MIS_SampleBRDF(Intersection &intersection, Ray &r, Geometry* &light) { if(Number_BRDF == 0) return glm::vec3(0); // Direct light estimator: sample BRDF glm::vec3 sum_brdf_sample(0.0f); for(int i = 0; i < Number_BRDF; i++) { glm::vec3 wo_local = intersection.ToLocalNormalCoordinate(-r.direction); glm::vec3 wj_local; float pdf_brdf; glm::vec3 F = intersection.object_hit->material->SampleAndEvaluateScatteredEnergy(intersection,wo_local,wj_local,pdf_brdf); glm::vec3 wj_world = intersection.ToWorldNormalCoordinate(wj_local); glm::vec3 wo_world = - r.direction; Intersection isxOnLight = intersection_engine->GetIntersection(Ray(intersection.point+float(1e-3)*intersection.normal, wj_world)); if(isxOnLight.t > 0 && isxOnLight.object_hit == light && pdf_brdf > 0) { float temp,pdf_light = light->RayPDF(intersection, Ray(intersection.point, wj_world)); float W = PowerHeuristic(pdf_brdf,float(Number_BRDF),pdf_light,float(Number_Light)); glm::vec3 Ld = light->material->EvaluateScatteredEnergy(isxOnLight,wo_world,-wj_world,temp); if(pdf_light > 0 ) { if(isinf(pdf_brdf)) // delta specular surface { sum_brdf_sample = sum_brdf_sample + F * Ld * float(fabs(glm::dot(wj_world, intersection.normal))) / pdf_light; } else { sum_brdf_sample = sum_brdf_sample + W * F * Ld * float(fabs(glm::dot(wj_world,intersection.normal))) / pdf_brdf; } } } } return sum_brdf_sample / float(Number_BRDF); }
std::vector<PathNode> BidirectionalIntegrator::generateLightPath(Geometry* &light) { std::vector<PathNode> lightPath; lightPath.clear(); Intersection lightSample = light->RandomSampleOnSurface(uniform_distribution(generator),uniform_distribution(generator)); Ray r(lightSample.point, lightSample.point - light->transform.position()); Intersection isx = intersection_engine->GetIntersection(r); int depth = 0; while(isx.t > 0 && depth < max_depth) { // store pathnode on the light path PathNode node; node.isx = isx; node.dirIn_world = -r.direction; node.dirIn_local = isx.ToLocalNormalCoordinate(-r.direction); node.F = isx.object_hit->material->SampleAndEvaluateScatteredEnergy(isx,node.dirIn_local,node.dirOut_local,node.pdf); node.dirOut_world = isx.ToWorldNormalCoordinate(node.dirOut_local); if(node.pdf != 0) lightPath.push_back(node); else break; //update r r = Ray(isx.point + glm::sign(glm::dot(node.dirOut_world,isx.normal)) * isx.normal*1e-3f, node.dirOut_world); // update isx and depth info depth++; isx = intersection_engine->GetIntersection(r); } return lightPath; }