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); } }
void DistributedPath::LiInternal(const Scene &scene, const Sample &sample, const Volume *volume, bool scattered, const Ray &ray, vector<SWCSpectrum> &L, float *alpha, float *zdepth, u_int rayDepth, bool includeEmit, u_int &nrContribs) const { Intersection isect; BSDF *bsdf; const float time = ray.time; // save time for motion blur const SpectrumWavelengths &sw(sample.swl); SWCSpectrum Lt(1.f); float spdf; if (scene.Intersect(sample, volume, scattered, ray, sample.sampler->GetOneD(sample, scatterOffset, rayDepth), &isect, &bsdf, &spdf, NULL, &Lt)) { // Evaluate BSDF at hit point Vector wo = -ray.d; const Point &p = bsdf->dgShading.p; const Normal &n = bsdf->dgShading.nn; if (rayDepth == 0) { // Set Zbuf depth const Vector zv(p - ray.o); *zdepth = zv.Length(); // Override alpha if(bsdf->compParams->oA) *alpha = bsdf->compParams->A; // Compute emitted light if ray hit an area light source with Visibility check if(bsdf->compParams->tVl && includeEmit) { BSDF *ibsdf; SWCSpectrum Le(1.f); if (isect.Le(sample, ray, &ibsdf, NULL, NULL, &Le)) { L[isect.arealight->group] += Le; ++nrContribs; } } // Visibility check if(!bsdf->compParams->tVm) { if (!bsdf->compParams->oA) *alpha = 0.f; return; } } else { // Compute emitted light if ray hit an area light source with Visibility check if(bsdf->compParams->tiVl && includeEmit) { BSDF *ibsdf; SWCSpectrum Le(1.f); if (isect.Le(sample, ray, &ibsdf, NULL, NULL, &Le)) { L[isect.arealight->group] += Le; ++nrContribs; } } // Visibility check if(!bsdf->compParams->tiVm) return; } // Compute direct lighting for _DistributedPath_ integrator if (scene.lights.size() > 0) { const u_int samples = rayDepth > 0 ? indirectSamples : directSamples; const float invsamples = 1.f / samples; float lightSample[2], lightNum; float bsdfSample[2], bsdfComponent; for (u_int i = 0; i < samples; ++i) { // get samples if (rayDepth > 0) { const u_int index = i * rayDepth; sample.sampler->GetTwoD(sample, indirectLightSampleOffset, index, lightSample); lightNum = sample.sampler->GetOneD(sample, indirectLightNumOffset, index); sample.sampler->GetTwoD(sample, indirectBsdfSampleOffset, index, bsdfSample); bsdfComponent = sample.sampler->GetOneD(sample, indirectBsdfComponentOffset, index); } else { sample.sampler->GetTwoD(sample, lightSampleOffset, i, lightSample); lightNum = sample.sampler->GetOneD(sample, lightNumOffset, i); sample.sampler->GetTwoD(sample, bsdfSampleOffset, i, bsdfSample); bsdfComponent = sample.sampler->GetOneD(sample, bsdfComponentOffset, i); } // Apply direct lighting strategy switch (lightStrategy) { case SAMPLE_ALL_UNIFORM: for (u_int i = 0; i < scene.lights.size(); ++i) { const SWCSpectrum Ld(EstimateDirect(scene, *(scene.lights[i]), sample, p, n, wo, bsdf, lightSample[0], lightSample[1], lightNum, bsdfSample[0], bsdfSample[1], bsdfComponent)); if (!Ld.Black()) { L[scene.lights[i]->group] += invsamples * Ld; ++nrContribs; } // TODO add bsdf selection flags } break; case SAMPLE_ONE_UNIFORM: { SWCSpectrum Ld; u_int g = UniformSampleOneLight(scene, sample, p, n, wo, bsdf, lightSample, &lightNum, bsdfSample, &bsdfComponent, &Ld); if (!Ld.Black()) { L[g] += invsamples * Ld; ++nrContribs; } break; } default: break; } } } // trace Diffuse reflection & transmission rays if (rayDepth < diffuseReflectDepth) { ComputeEvent(scene, sample, bsdf, wo, diffuseReflectSamples, indirectDiffuseReflectSampleOffset, indirectDiffuseReflectComponentOffset, diffuseReflectSampleOffset, diffuseReflectComponentOffset, BxDFType(BSDF_REFLECTION | BSDF_DIFFUSE), diffuseReflectReject, diffuseReflectRejectThreshold, L, alpha, zdepth, rayDepth, nrContribs); } if (rayDepth < diffuseRefractDepth) { ComputeEvent(scene, sample, bsdf, wo, diffuseRefractSamples, indirectDiffuseRefractSampleOffset, indirectDiffuseRefractComponentOffset, diffuseRefractSampleOffset, diffuseRefractComponentOffset, BxDFType(BSDF_TRANSMISSION | BSDF_DIFFUSE), diffuseRefractReject, diffuseRefractRejectThreshold, L, alpha, zdepth, rayDepth, nrContribs); } // trace Glossy reflection & transmission rays if (rayDepth < glossyReflectDepth) { ComputeEvent(scene, sample, bsdf, wo, glossyReflectSamples, indirectGlossyReflectSampleOffset, indirectGlossyReflectComponentOffset, glossyReflectSampleOffset, glossyReflectComponentOffset, BxDFType(BSDF_REFLECTION | BSDF_GLOSSY), glossyReflectReject, glossyReflectRejectThreshold, L, alpha, zdepth, rayDepth, nrContribs); } if (rayDepth < glossyRefractDepth) { ComputeEvent(scene, sample, bsdf, wo, glossyRefractSamples, indirectGlossyRefractSampleOffset, indirectGlossyRefractComponentOffset, glossyRefractSampleOffset, glossyRefractComponentOffset, BxDFType(BSDF_TRANSMISSION | BSDF_GLOSSY), glossyRefractReject, glossyRefractRejectThreshold, L, alpha, zdepth, rayDepth, nrContribs); } // trace specular reflection & transmission rays if (rayDepth < specularReflectDepth) { float pdf; Vector wi; SWCSpectrum f; if (bsdf->SampleF(sw, wo, &wi, .5f, .5f, .5f, &f, &pdf, BxDFType(BSDF_REFLECTION | BSDF_SPECULAR), NULL, NULL, true)) { Ray rd(p, wi); rd.time = time; vector<SWCSpectrum> Ll(L.size(), SWCSpectrum(0.f)); LiInternal(scene, sample, bsdf->GetVolume(wi), bsdf->dgShading.scattered, rd, Ll, alpha, zdepth, rayDepth + 1, true, nrContribs); for (u_int j = 0; j < L.size(); ++j) L[j] += f * Ll[j]; } } if (rayDepth < specularRefractDepth) { float pdf; Vector wi; SWCSpectrum f; if (bsdf->SampleF(sw, wo, &wi, .5f, .5f, .5f, &f, &pdf, BxDFType(BSDF_TRANSMISSION | BSDF_SPECULAR), NULL, NULL, true)) { Ray rd(p, wi); rd.time = time; vector<SWCSpectrum> Ll(L.size(), SWCSpectrum(0.f)); LiInternal(scene, sample, bsdf->GetVolume(wi), bsdf->dgShading.scattered, rd, Ll, alpha, zdepth, rayDepth + 1, true, nrContribs); for (u_int j = 0; j < L.size(); ++j) L[j] += f * Ll[j]; } } } else { // Handle ray with no intersection BSDF *ibsdf; for (u_int i = 0; i < scene.lights.size(); ++i) { SWCSpectrum Le(1.f); if (scene.lights[i]->Le(scene, sample, ray, &ibsdf, NULL, NULL, &Le)) { L[scene.lights[i]->group] += Le; ++nrContribs; } } if (rayDepth == 0) *alpha = 0.f; } Lt /= spdf; for (u_int i = 0; i < L.size(); ++i) L[i] *= Lt; SWCSpectrum Lv(0.f); u_int g = scene.volumeIntegrator->Li(scene, ray, sample, &Lv, alpha); L[g] += Lv; }