Spectrum BidirIntegrator::Li(const Scene *scene, const RayDifferential &ray, const Sample *sample, float *alpha) const { Spectrum L(0.); // Generate eye and light sub-paths BidirVertex eyePath[MAX_VERTS], lightPath[MAX_VERTS]; int nEye = generatePath(scene, ray, sample, eyeBSDFOffset, eyeBSDFCompOffset, eyePath, MAX_VERTS); if (nEye == 0) { *alpha = 0.; return L; } *alpha = 1; // Choose light for bidirectional path int lightNum = Floor2Int(sample->oneD[lightNumOffset][0] * scene->lights.size()); lightNum = min(lightNum, (int)scene->lights.size() - 1); Light *light = scene->lights[lightNum]; float lightWeight = float(scene->lights.size()); // Sample ray from light source to start light path Ray lightRay; float lightPdf; float u[4]; u[0] = sample->twoD[lightPosOffset][0]; u[1] = sample->twoD[lightPosOffset][1]; u[2] = sample->twoD[lightDirOffset][0]; u[3] = sample->twoD[lightDirOffset][1]; Spectrum Le = light->Sample_L(scene, u[0], u[1], u[2], u[3], &lightRay, &lightPdf); if (lightPdf == 0.) return 0.f; Le = lightWeight / lightPdf; int nLight = generatePath(scene, lightRay, sample, lightBSDFOffset, lightBSDFCompOffset, lightPath, MAX_VERTS); // Connect bidirectional path prefixes and evaluate throughput Spectrum directWt(1.0); for (int i = 1; i <= nEye; ++i) { // Handle direct lighting for bidirectional integrator directWt /= eyePath[i-1].rrWeight; L += directWt * UniformSampleOneLight(scene, eyePath[i-1].p, eyePath[i-1].ng, eyePath[i-1].wi, eyePath[i-1].bsdf, sample, directLightOffset[i-1], directLightNumOffset[i-1], directBSDFOffset[i-1], directBSDFCompOffset[i-1]) / weightPath(eyePath, i, lightPath, 0); directWt *= eyePath[i-1].bsdf->f(eyePath[i-1].wi, eyePath[i-1].wo) * AbsDot(eyePath[i-1].wo, eyePath[i-1].ng) / eyePath[i-1].bsdfWeight; for (int j = 1; j <= nLight; ++j) L += Le * evalPath(scene, eyePath, i, lightPath, j) / weightPath(eyePath, i, lightPath, j); } return L; }
glm::vec3 BidirectionalIntegrator::TraceRay(Ray r, unsigned int depth) { Intersection isx = intersection_engine->GetIntersection(r); if(isx.t < 0) return glm::vec3(0); else if(isx.object_hit->material->is_light_source) { return isx.object_hit->material->base_color * isx.texture_color; } glm::vec3 resultColor(0); for(Geometry* light : scene->lights) { std::vector<PathNode> eyePath = generateEyePath(r); std::vector<PathNode> lightPath = generateLightPath(light); if(!eyePath.empty() && !lightPath.empty()) { PathNode* node = &lightPath[0]; float lightPdf = light->RayPDF(node->isx,Ray(node->isx.point,node->dirIn_world)); glm::vec3 Le(0); if(lightPdf != 0) Le = light->material->base_color * light->material->intensity / lightPdf; glm::vec3 directWt(1.0f); for(int i=1;i<=eyePath.size();i++) { node = &eyePath[i-1]; Ray ray(light->transform.position(), - node->dirIn_world); resultColor += directWt * EstimateDirectLight(node->isx, ray, light) / WeightPath(i,0); directWt *= node->F * glm::abs(glm::dot(node->dirOut_world,node->isx.normal)) / node->pdf; for(int j=1;j<=lightPath.size();j++) { resultColor += Le * EvaluatePath(eyePath,i,lightPath,j) / WeightPath(i,j); } } } else { continue; } } return resultColor; }