u_int DistributedPath::Li(const Scene &scene, const Sample &sample) const { u_int nrContribs = 0; float zdepth = 0.f; Ray ray; float xi, yi; float rayWeight = sample.camera->GenerateRay(scene, sample, &ray, &xi, &yi); vector<SWCSpectrum> L(scene.lightGroups.size(), SWCSpectrum(0.f)); float alpha = 1.f; LiInternal(scene, sample, NULL, false, ray, L, &alpha, &zdepth, 0, true, nrContribs); for (u_int i = 0; i < L.size(); ++i) sample.AddContribution(xi, yi, XYZColor(sample.swl, L[i]) * rayWeight, alpha, zdepth, 0.f, bufferId, i); return nrContribs; }
void HitPoints::TraceEyePath(HitPoint *hp, const Sample &sample, float const invPixelPdf) { HitPointEyePass *hpep = &hp->eyePass; Scene &scene(*renderer->scene); const bool includeEnvironment = renderer->sppmi->includeEnvironment; const u_int maxDepth = renderer->sppmi->maxEyePathDepth; //-------------------------------------------------------------------------- // Following code is, given or taken, a copy of path integrator Li() method //-------------------------------------------------------------------------- // Declare common path integration variables const SpectrumWavelengths &sw(sample.swl); Ray ray; const float rayWeight = sample.camera->GenerateRay(scene, sample, &ray, &(hp->imageX), &(hp->imageY)); const float nLights = scene.lights.size(); const u_int lightGroupCount = scene.lightGroups.size(); vector<SWCSpectrum> Ld(lightGroupCount, 0.f); // Direct lighting samples variance vector<float> Vd(lightGroupCount, 0.f); SWCSpectrum pathThroughput(1.0f); // pathThroughput is normalised perpixel for the eyepass contribution, so no need for invPixelPdf normalisation; vector<SWCSpectrum> L(lightGroupCount, 0.f); vector<float> V(lightGroupCount, 0.f); float VContrib = .1f; bool scattered = false; hpep->alpha = 1.f; hpep->distance = INFINITY; u_int vertexIndex = 0; const Volume *volume = NULL; bool specularBounce = true; const bool enableDirectLightSampling = renderer->sppmi->directLightSampling; for (u_int pathLength = 0; ; ++pathLength) { const SWCSpectrum prevThroughput(pathThroughput); float *data = eyeSampler->GetLazyValues(sample, 0, pathLength); // Find next vertex of path Intersection isect; BSDF *bsdf; float spdf; sample.arena.Begin(); if (!scene.Intersect(sample, volume, scattered, ray, data[0], &isect, &bsdf, &spdf, NULL, &pathThroughput)) { pathThroughput /= spdf; // Dade - now I know ray.maxt and I can call volumeIntegrator SWCSpectrum Lv; u_int g = scene.volumeIntegrator->Li(scene, ray, sample, &Lv, &hpep->alpha); if (!Lv.Black()) { Lv *= prevThroughput; L[g] += Lv; } // Stop path sampling since no intersection was found // Possibly add horizon in render & reflections if (!enableDirectLightSampling || ( (includeEnvironment || vertexIndex > 0) && specularBounce)) { BSDF *ibsdf; for (u_int i = 0; i < nLights; ++i) { SWCSpectrum Le(pathThroughput); if (scene.lights[i]->Le(scene, sample, ray, &ibsdf, NULL, NULL, &Le)) L[scene.lights[i]->group] += Le; } } // Set alpha channel if (vertexIndex == 0) hpep->alpha = 0.f; hp->SetConstant(); break; } sample.arena.End(); scattered = bsdf->dgShading.scattered; pathThroughput /= spdf; if (vertexIndex == 0) hpep->distance = ray.maxt * ray.d.Length(); SWCSpectrum Lv; const u_int g = scene.volumeIntegrator->Li(scene, ray, sample, &Lv, &hpep->alpha); if (!Lv.Black()) { Lv *= prevThroughput; L[g] += Lv; } // Possibly add emitted light at path vertex Vector wo(-ray.d); if (specularBounce) { BSDF *ibsdf; SWCSpectrum Le(pathThroughput); if (isect.Le(sample, ray, &ibsdf, NULL, NULL, &Le)) { L[isect.arealight->group] += Le; V[isect.arealight->group] += Le.Filter(sw) * VContrib; } } const Point &p = bsdf->dgShading.p; const Normal &n = bsdf->dgShading.nn; // Estimate direct lighting if (renderer->sppmi->directLightSampling && (nLights > 0)) { for (u_int i = 0; i < lightGroupCount; ++i) { Ld[i] = 0.f; Vd[i] = 0.f; } renderer->sppmi->hints.SampleLights(scene, sample, p, n, wo, bsdf, pathLength, pathThroughput, Ld, &Vd); for (u_int i = 0; i < lightGroupCount; ++i) { L[i] += Ld[i]; V[i] += Vd[i] * VContrib; } } // Choose between storing or bouncing the hitpoint on the surface bool const has_store_component = bsdf->NumComponents(store_component) > 0; bool const has_bounce_component = bsdf->NumComponents(bounce_component) > 0; float pdf_event; bool store; if (has_store_component && has_bounce_component) { // There is both bounce and store component, we choose with a // random number // TODO: do this by importance store = data[4] < .5f; pdf_event = 0.5; } else { // If there is only bounce/store component, we bounce/store // accordingly store = has_store_component; pdf_event = 1.f; } if(store) { hp->SetSurface(); hpep->pathThroughput = pathThroughput * rayWeight / pdf_event * invPixelPdf; hpep->wo = wo; hpep->bsdf = bsdf; hpep->single = sw.single; sample.arena.Commit(); break; } // Sample BSDF to get new path direction Vector wi; float pdf; BxDFType flags; SWCSpectrum f; if (pathLength == maxDepth || !bsdf->SampleF(sw, wo, &wi, data[1], data[2], data[3], &f, &pdf, bounce_component, &flags, NULL, true)) { hp->SetConstant(); break; } if (flags != (BSDF_TRANSMISSION | BSDF_SPECULAR) || !(bsdf->Pdf(sw, wi, wo, BxDFType(BSDF_TRANSMISSION | BSDF_SPECULAR)) > 0.f)) { ++vertexIndex; specularBounce = (flags & BSDF_SPECULAR) != 0; } pathThroughput *= f / pdf_event; if (pathThroughput.Black()) { hp->SetConstant(); break; } ray = Ray(p, wi); ray.time = sample.realTime; volume = bsdf->GetVolume(wi); } for(unsigned int i = 0; i < lightGroupCount; ++i) { if (!L[i].Black()) V[i] /= L[i].Filter(sw); sample.AddContribution(hp->imageX, hp->imageY, XYZColor(sw, L[i]) * rayWeight, hp->eyePass.alpha, hp->eyePass.distance, 0, renderer->sppmi->bufferEyeId, i); } }