void VolumePatIntegrator::EyeRandomWalk(const Scene *scene, const Ray &eyeRay, VolumeVertexList& vertexList, RNG &rng) const { // Do a random walk for the eye ray in the volume Spectrum cummulative(1.f); // Find the intersection between the eye ray and the volume VolumeRegion *vr = scene->volumeRegion; float t0, t1; if (!vr || !vr->IntersectP(eyeRay, &t0, &t1) || (t1-t0) == 0.f || t0 < 0.f) { return; } // Find the intersection point between the sampled light ray and the volume RayDifferential ray(eyeRay); Point p = ray(t0), pPrev; uint64_t bounces = 0; while(vr->WorldBound().Inside(p)) { Vector wi = -ray.d; const Spectrum sigma_a = vr->Sigma_a(p, wi, eyeRay.time); const Spectrum sigma_s = vr->Sigma_s(p, wi, eyeRay.time); const Spectrum STER = vr->STER(p, wi, eyeRay.time); // Construct and add the _eyeVertex_ to the _vertexList_ VolumeVertex eyeVertex(p, wi, sigma_a, sigma_s, cummulative, 1.0); vertexList.push_back(eyeVertex); // Sample the direction of the next event float directionPdf = 1.f; Vector wo; if(STER.y() > rng.RandomFloat()) { // Change the ray direction due to a scattering event at _p_ if(!vr->SampleDirection(p, wi, wo, &directionPdf, rng)) { break; // Direction error } // Account for the losses due to the scattering event at _p_ cummulative *= sigma_s * vr->p(p, wi, wo, ray.time); } else { // Account only for the trnsmittance between the previous and the // next events becuse there is no direction change. wo = ray.d; } // Sample the distance of the next event ray = RayDifferential(p, wo, 0, INFINITY); float tDist; float distancePdf = 1.f; Point Psample; if(!vr->SampleDistance(ray, &tDist, Psample, &distancePdf, rng)) { break; // The sampled point is outside the volume } // Account for the sampling Pdfs from sampling a direction and/or distance const float pdf = distancePdf * directionPdf; cummulative *= 1 / pdf; // Update the events and account for the transmittance between the events pPrev = p; p = Psample; const Ray tauRay(pPrev, p - pPrev, 0.f, 1.f, ray.time, ray.depth); const Spectrum stepTau = vr->tau(tauRay, .5f * stepSize, rng.RandomFloat()); const Spectrum TrPP = Exp(-stepTau); cummulative *= TrPP; // Possibly terminate ray marching if _cummulative_ is small if (cummulative.y() < 1e-3) { const float continueProb = .5f; if (rng.RandomFloat() > continueProb) { cummulative = 0.f; break; } cummulative /= continueProb; } // Terminate if bounces are more than requested bounces++; if (bounces > maxDepth) { break; } } }
void UniformResamplingRecursiveMISBPTRenderer::processSample(uint32_t threadID, uint32_t tileID, uint32_t pixelID, uint32_t sampleID, uint32_t x, uint32_t y) const { auto mis = [&](float v) { return Mis(v); }; ThreadRNG rng(*this, threadID); PixelSensor pixelSensor(getSensor(), Vec2u(x, y), getFramebufferSize()); auto pixelSample = getPixelSample(threadID, sampleID); auto sensorSample = getFloat2(threadID); auto fImportanceScale = 1.f / getSppCount(); BDPTPathVertex eyeVertex(getScene(), pixelSensor, sensorSample, pixelSample, m_nLightPathCount, mis); if(eyeVertex.m_Power == zero<Vec3f>() || !eyeVertex.m_fPathPdf) { return; } // Sample the light path to connect with the eye path auto lightPathIdx = clamp(std::size_t(getFloat(threadID) * m_nLightPathCount), std::size_t(0), m_nLightPathCount - 1); auto pLightPath = m_LightPathBuffer.getSlicePtr(lightPathIdx); auto maxEyePathDepth = getMaxEyePathDepth(); auto maxLightPathDepth = getMaxLightPathDepth(); auto extendEyePath = [&]() -> bool { return eyeVertex.m_nDepth < maxEyePathDepth && eyeVertex.extend(eyeVertex, getScene(), getSppCount(), false, rng, mis); }; // Iterate over an eye path do { // Intersection with light source auto totalLength = eyeVertex.m_nDepth; if(acceptPathDepth(totalLength) && totalLength <= m_nMaxDepth) { auto contrib = fImportanceScale * computeEmittedRadiance(eyeVertex, getScene(), m_LightSampler, getSppCount(), mis); if(isInvalidMeasurementEstimate(contrib)) { reportInvalidContrib(threadID, tileID, pixelID, [&]() { debugLog() << "s = " << 0 << ", t = " << (eyeVertex.m_nDepth + 1) << std::endl; }); } accumulate(FINAL_RENDER, pixelID, Vec4f(contrib, 0)); accumulate(FINAL_RENDER_DEPTH1 + totalLength - 1u, pixelID, Vec4f(contrib, 0)); auto strategyOffset = computeBPTStrategyOffset(totalLength + 1, 0u); accumulate(BPT_STRATEGY_s0_t2 + strategyOffset, pixelID, Vec4f(contrib, 0)); } // Connections if(eyeVertex.m_Intersection) { // Direct illumination auto totalLength = eyeVertex.m_nDepth + 1; if(acceptPathDepth(totalLength) && totalLength <= m_nMaxDepth) { float lightPdf; auto pLight = m_LightSampler.sample(getScene(), getFloat(threadID), lightPdf); auto s2D = getFloat2(threadID); auto contrib = fImportanceScale * connectVertices(eyeVertex, EmissionVertex(pLight, lightPdf, s2D), getScene(), getSppCount(), mis); if(isInvalidMeasurementEstimate(contrib)) { reportInvalidContrib(threadID, tileID, pixelID, [&]() { debugLog() << "s = " << 1 << ", t = " << (eyeVertex.m_nDepth + 1) << std::endl; }); } accumulate(FINAL_RENDER, pixelID, Vec4f(contrib, 0)); accumulate(FINAL_RENDER_DEPTH1 + totalLength - 1u, pixelID, Vec4f(contrib, 0)); auto strategyOffset = computeBPTStrategyOffset(totalLength + 1, 1); accumulate(BPT_STRATEGY_s0_t2 + strategyOffset, pixelID, Vec4f(contrib, 0)); } // Connection with each light vertex for(auto j = 0u; j < maxLightPathDepth; ++j) { auto pLightVertex = pLightPath + j; auto totalLength = eyeVertex.m_nDepth + pLightVertex->m_nDepth + 1; if(pLightVertex->m_fPathPdf > 0.f && acceptPathDepth(totalLength) && totalLength <= m_nMaxDepth) { auto contrib = fImportanceScale * connectVertices(eyeVertex, *pLightVertex, getScene(), getSppCount(), mis); if(isInvalidMeasurementEstimate(contrib)) { reportInvalidContrib(threadID, tileID, pixelID, [&]() { debugLog() << "s = " << (pLightVertex->m_nDepth + 1) << ", t = " << (eyeVertex.m_nDepth + 1) << std::endl; }); } accumulate(FINAL_RENDER, pixelID, Vec4f(contrib, 0)); accumulate(FINAL_RENDER_DEPTH1 + totalLength - 1u, pixelID, Vec4f(contrib, 0)); auto strategyOffset = computeBPTStrategyOffset(totalLength + 1, pLightVertex->m_nDepth + 1); accumulate(BPT_STRATEGY_s0_t2 + strategyOffset, pixelID, Vec4f(contrib, 0)); } } } } while(extendEyePath()); }