Float MISWeight(const Scene &scene, Vertex *lightSubpath, Vertex *cameraSubpath, Vertex &sampled, int s, int t, const Distribution1D &lightPdf) { if (s + t == 2) return 1.0f; Float sum = 0.f; // Determine connection vertices Vertex *qs = s > 0 ? &lightSubpath[s - 1] : nullptr, *pt = t > 0 ? &cameraSubpath[t - 1] : nullptr, *qsMinus = s > 1 ? &lightSubpath[s - 2] : nullptr, *ptMinus = t > 1 ? &cameraSubpath[t - 2] : nullptr; // Temporarily update vertex properties for current strategy ScopedAssign<Vertex> s0; ScopedAssign<bool> s1, s2; ScopedAssign<Float> s3, s4, s5, s6; if (s == 1 || t == 1) s0 = ScopedAssign<Vertex>((s == 1) ? qs : pt, sampled); if (qs) { s1 = ScopedAssign<bool>(&qs->delta, false), s3 = ScopedAssign<Float>(&qs->pdfRev, pt->Pdf(scene, ptMinus, *qs)); } if (qsMinus) s5 = ScopedAssign<Float>(&qsMinus->pdfRev, qs->Pdf(scene, pt, *qsMinus)); if (pt) { s2 = ScopedAssign<bool>(&pt->delta, false); s4 = ScopedAssign<Float>( &pt->pdfRev, s > 0 ? qs->Pdf(scene, qsMinus, *pt) : pt->PdfLightOrigin(scene, *ptMinus, lightPdf)); } if (ptMinus) s6 = ScopedAssign<Float>(&ptMinus->pdfRev, s > 0 ? pt->Pdf(scene, qs, *ptMinus) : pt->PdfLight(scene, *ptMinus)); // Consider hypothetical connection strategies along the camera subpath auto p = [](float f) -> float { return f != 0 ? f : 1.0f; }; Float ratio = 1.0f; for (int i = t - 1; i > 0; --i) { ratio *= p(cameraSubpath[i].pdfRev) / p(cameraSubpath[i].pdfFwd); if (!cameraSubpath[i].delta && !cameraSubpath[i - 1].delta) sum += ratio; } // Consider hypothetical connection strategies along the light subpath ratio = 1.0f; for (int i = s - 1; i >= 0; --i) { ratio *= p(lightSubpath[i].pdfRev) / p(lightSubpath[i].pdfFwd); bool delta_lightvertex = i > 0 ? lightSubpath[i - 1].delta : lightSubpath[0].IsDeltaLight(); if (!lightSubpath[i].delta && !delta_lightvertex) sum += ratio; } return 1.f / (1.f + sum); }
Float MISWeight(const Scene &scene, Vertex *lightVertices, Vertex *cameraVertices, Vertex &sampled, int s, int t, const Distribution1D &lightPdf, const std::unordered_map<const Light *, size_t> &lightToIndex) { if (s + t == 2) return 1; Float sumRi = 0; // Define helper function _remap0_ that deals with Dirac delta functions auto remap0 = [](Float f) -> Float { return f != 0 ? f : 1; }; // Temporarily update vertex properties for current strategy // Look up connection vertices and their predecessors Vertex *qs = s > 0 ? &lightVertices[s - 1] : nullptr, *pt = t > 0 ? &cameraVertices[t - 1] : nullptr, *qsMinus = s > 1 ? &lightVertices[s - 2] : nullptr, *ptMinus = t > 1 ? &cameraVertices[t - 2] : nullptr; // Update sampled vertex for $s=1$ or $t=1$ strategy ScopedAssignment<Vertex> a1; if (s == 1) a1 = {qs, sampled}; else if (t == 1) a1 = {pt, sampled}; // Mark connection vertices as non-degenerate ScopedAssignment<bool> a2, a3; if (pt) a2 = {&pt->delta, false}; if (qs) a3 = {&qs->delta, false}; // Update reverse density of vertex $\pt{}_{t-1}$ ScopedAssignment<Float> a4; if (pt) a4 = {&pt->pdfRev, s > 0 ? qs->Pdf(scene, qsMinus, *pt) : pt->PdfLightOrigin(scene, *ptMinus, lightPdf, lightToIndex)}; // Update reverse density of vertex $\pt{}_{t-2}$ ScopedAssignment<Float> a5; if (ptMinus) a5 = {&ptMinus->pdfRev, s > 0 ? pt->Pdf(scene, qs, *ptMinus) : pt->PdfLight(scene, *ptMinus)}; // Update reverse density of vertices $\pq{}_{s-1}$ and $\pq{}_{s-2}$ ScopedAssignment<Float> a6; if (qs) a6 = {&qs->pdfRev, pt->Pdf(scene, ptMinus, *qs)}; ScopedAssignment<Float> a7; if (qsMinus) a7 = {&qsMinus->pdfRev, qs->Pdf(scene, pt, *qsMinus)}; // Consider hypothetical connection strategies along the camera subpath Float ri = 1; for (int i = t - 1; i > 0; --i) { ri *= remap0(cameraVertices[i].pdfRev) / remap0(cameraVertices[i].pdfFwd); if (!cameraVertices[i].delta && !cameraVertices[i - 1].delta) sumRi += ri; } // Consider hypothetical connection strategies along the light subpath ri = 1; for (int i = s - 1; i >= 0; --i) { ri *= remap0(lightVertices[i].pdfRev) / remap0(lightVertices[i].pdfFwd); bool deltaLightvertex = i > 0 ? lightVertices[i - 1].delta : lightVertices[0].IsDeltaLight(); if (!lightVertices[i].delta && !deltaLightvertex) sumRi += ri; } return 1 / (1 + sumRi); }