Spectrum SeparableBSSRDF::Sample_Sp(const Scene &scene, Float u1, const Point2f &u2, MemoryArena &arena, SurfaceInteraction *pi, Float *pdf) const { ProfilePhase pp(Prof::BSSRDFEvaluation); // Choose projection axis for BSSRDF sampling Vector3f vx, vy, vz; if (u1 < .5f) { vx = ss; vy = ts; vz = Vector3f(ns); u1 *= 2; } else if (u1 < .75f) { // Prepare for sampling rays with respect to _ss_ vx = ts; vy = Vector3f(ns); vz = ss; u1 = (u1 - .5f) * 4; } else { // Prepare for sampling rays with respect to _ts_ vx = Vector3f(ns); vy = ss; vz = ts; u1 = (u1 - .75f) * 4; } // Choose spectral channel for BSSRDF sampling int ch = Clamp((int)(u1 * Spectrum::nSamples), 0, Spectrum::nSamples - 1); u1 = u1 * Spectrum::nSamples - ch; // Sample BSSRDF profile in polar coordinates Float r = Sample_Sr(ch, u2[0]); if (r < 0) return Spectrum(0.f); Float phi = 2 * Pi * u2[1]; // Compute BSSRDF profile bounds and intersection height Float rMax = Sample_Sr(ch, 0.999f); if (r > rMax) return Spectrum(0.f); Float l = 2 * std::sqrt(rMax * rMax - r * r); // Compute BSSRDF sampling ray segment Interaction base; base.p = po.p + r * (vx * std::cos(phi) + vy * std::sin(phi)) - l * vz * 0.5f; base.time = po.time; Point3f pTarget = base.p + l * vz; // Intersect BSSRDF sampling ray against the scene geometry // Declare _IntersectionChain_ and linked list struct IntersectionChain { SurfaceInteraction si; IntersectionChain *next = nullptr; }; IntersectionChain *chain = ARENA_ALLOC(arena, IntersectionChain)(); // Accumulate chain of intersections along ray IntersectionChain *ptr = chain; int nFound = 0; while (scene.Intersect(base.SpawnRayTo(pTarget), &ptr->si)) { base = ptr->si; // Append admissible intersection to _IntersectionChain_ if (ptr->si.primitive->GetMaterial() == this->material) { IntersectionChain *next = ARENA_ALLOC(arena, IntersectionChain)(); ptr->next = next; ptr = next; nFound++; } } // Randomly choose one of several intersections during BSSRDF sampling if (nFound == 0) return Spectrum(0.0f); int selected = Clamp((int)(u1 * nFound), 0, nFound - 1); while (selected-- > 0) chain = chain->next; *pi = chain->si; // Compute sample PDF and return the spatial BSSRDF term $\Sp$ *pdf = this->Pdf_Sp(*pi) / nFound; return this->Sp(*pi); }
Spectrum SeparableBSSRDF::Sample_Sp(const Scene &scene, Float sample1, const Point2f &sample2, MemoryArena &arena, SurfaceInteraction *pi, Float *pdf) const { ProfilePhase pp(Prof::BSSRDFEvaluation); // Choose projection axis for BSSRDF sampling Vector3f axis; if (sample1 < .25f) { axis = ss; sample1 *= 4; } else if (sample1 < .5f) { axis = ts; sample1 = (sample1 - .25f) * 4; } else { axis = Vector3f(ns); sample1 = (sample1 - .5f) * 2; } // Choose spectral channel for BSSRDF sampling int ch = Clamp((int)(sample1 * Spectrum::nSamples), 0, Spectrum::nSamples - 1); sample1 = sample1 * Spectrum::nSamples - ch; // Sample BSSRDF profile in polar coordinates Float r = Sample_Sr(ch, sample2.x); if (r < 0) return Spectrum(0.f); Float phi = 2 * Pi * sample2.y; // Compute BSSRDF profile bounds and intersection height Float rMax = Sample_Sr(ch, 0.999f); if (r > rMax) return Spectrum(0.f); Float l = 2 * std::sqrt(rMax * rMax - r * r); // Compute BSSRDF sampling ray segment Vector3f v0, v1; CoordinateSystem(axis, &v0, &v1); Interaction base; base.p = po.p + r * (v0 * std::cos(phi) + v1 * std::sin(phi)) - l * axis * 0.5f; base.time = po.time; Point3f target = base.p + l * axis; // Intersect BSSRDF sampling ray against the scene geometry struct IntersectionChain { SurfaceInteraction si; IntersectionChain *next; }; IntersectionChain *chain = ARENA_ALLOC(arena, IntersectionChain)(), *ptr = chain; int nFound = 0; while (true) { if (!scene.Intersect(base.SpawnRayTo(target), &ptr->si)) break; base = ptr->si; // Append admissible intersection to _IntersectionChain_ if (ptr->si.primitive->GetMaterial() == material) { IntersectionChain *next = ARENA_ALLOC(arena, IntersectionChain)(); ptr->next = next; ptr = next; nFound++; } } // Randomly choose one of several intersections during BSSRDF sampling if (nFound == 0) return Spectrum(0.0f); int selected = Clamp((int)(sample1 * nFound), 0, nFound - 1); while (selected-- > 0) chain = chain->next; *pi = chain->si; // Compute sample PDF and return the spatial BSSRDF term $\Sp$ *pdf = Pdf_Sp(*pi) / nFound; return Sp(*pi); }