bool extend(BDPTPathVertex& next, const Scene& scene, uint32_t pathCount, bool sampleAdjoint, // Number of paths sampled with the strategies s/t = m_nDepth + 1, t/s = * RandomGenerator&& rng, MisFunctor&& mis) { if(!m_Intersection) { return false; // Can't sample from infinity } Sample3f woSample; float cosThetaOutDir; uint32_t sampledEvent; auto fs = m_BSDF.sample(Vec3f(getFloat(rng), getFloat2(rng)), woSample, cosThetaOutDir, &sampledEvent, sampleAdjoint); if(woSample.pdf == 0.f || fs == zero<Vec3f>()) { return false; } float reversePdf = m_BSDF.pdf(woSample.value, true); auto nextI = scene.intersect(Ray(m_Intersection, woSample.value)); if(!nextI) { next.m_Intersection = nextI; next.m_BSDF.init(-woSample.value, scene); next.m_fPdfWrtArea = woSample.pdf; next.m_fPathPdf = m_fPathPdf * woSample.pdf; next.m_Power = m_Power * abs(cosThetaOutDir) * fs / woSample.pdf; next.m_nDepth = m_nDepth + 1; auto previousPointToIncidentDirectionJacobian = abs(cosThetaOutDir); // No division by squared distance since the point is at infinity if((sampledEvent & ScatteringEvent::Specular) && m_BSDF.isDelta()) { next.m_fdVC = mis(previousPointToIncidentDirectionJacobian) * m_fdVC; next.m_fdVCM = 0.f; } else { // We set dVC first in case next == *this, so that the dVCM is unchanged until next line next.m_fdVC = mis(previousPointToIncidentDirectionJacobian / next.m_fPdfWrtArea) * (m_fdVCM + mis(reversePdf) * m_fdVC); next.m_fdVCM = mis(pathCount / next.m_fPdfWrtArea); } } else { auto incidentDirection = -woSample.value; auto sqrLength = sqr(nextI.distance); if(sqrLength == 0.f) { return false; } auto pdfWrtArea = woSample.pdf * abs(dot(nextI.Ns, incidentDirection)) / sqrLength; if(pdfWrtArea == 0.f) { return false; } next.m_Intersection = nextI; next.m_BSDF.init(incidentDirection, nextI, scene); next.m_fPdfWrtArea = pdfWrtArea; next.m_fPathPdf = m_fPathPdf * pdfWrtArea; next.m_Power = m_Power * abs(cosThetaOutDir) * fs / woSample.pdf; next.m_nDepth = m_nDepth + 1; auto previousPointToIncidentDirectionJacobian = abs(cosThetaOutDir) / sqrLength; if((sampledEvent & ScatteringEvent::Specular) && m_BSDF.isDelta()) { next.m_fdVC = mis(previousPointToIncidentDirectionJacobian) * m_fdVC; next.m_fdVCM = 0.f; } else { // We set dVC first in case next == *this, so that the dVCM is unchanged until next line next.m_fdVC = mis(previousPointToIncidentDirectionJacobian / next.m_fPdfWrtArea) * (m_fdVCM + mis(reversePdf) * m_fdVC); next.m_fdVCM = mis(pathCount / next.m_fPdfWrtArea); } } return true; }