Float TabulatedBSSRDF::Sample_Sr(int ch, Float u) const { if (sigma_t[ch] == 0) return -1; return SampleCatmullRom2D(table.nRhoSamples, table.nRadiusSamples, table.rhoSamples.get(), table.radiusSamples.get(), table.profile.get(), table.profileCDF.get(), rho[ch], u) / sigma_t[ch]; }
Spectrum FourierBSDF::Sample_f(const Vector3f &wo, Vector3f *wi, const Point2f &u, Float *pdf, BxDFType *sampledType) const { // Sample zenith angle component for _FourierBSDF_ Float muO = CosTheta(wo); Float pdfMu; Float muI = SampleCatmullRom2D(bsdfTable.nMu, bsdfTable.nMu, bsdfTable.mu, bsdfTable.mu, bsdfTable.avg, bsdfTable.cdf, muO, u[1], nullptr, &pdfMu); // Compute Fourier coefficients $a_k$ for $(\mui, \muo)$ // Determine offsets and weights for $\mui$ and $\muo$ int offsetI, offsetO; Float weightsI[4], weightsO[4]; if (!bsdfTable.GetWeightsAndOffset(muI, &offsetI, weightsI) || !bsdfTable.GetWeightsAndOffset(muO, &offsetO, weightsO)) return Spectrum(0.f); // Allocate storage to accumulate _ak_ coefficients Float *ak = ALLOCA(Float, bsdfTable.mMax * bsdfTable.nChannels); memset(ak, 0, bsdfTable.mMax * bsdfTable.nChannels * sizeof(Float)); // Accumulate weighted sums of nearby $a_k$ coefficients int mMax = 0; for (int b = 0; b < 4; ++b) { for (int a = 0; a < 4; ++a) { // Add contribution of _(a, b)_ to $a_k$ values Float weight = weightsI[a] * weightsO[b]; if (weight != 0) { int m; const Float *ap = bsdfTable.GetAk(offsetI + a, offsetO + b, &m); mMax = std::max(mMax, m); for (int c = 0; c < bsdfTable.nChannels; ++c) for (int k = 0; k < m; ++k) ak[c * bsdfTable.mMax + k] += weight * ap[c * m + k]; } } } // Importance sample the luminance Fourier expansion Float phi, pdfPhi; Float Y = SampleFourier(ak, bsdfTable.recip, mMax, u[0], &pdfPhi, &phi); *pdf = std::max((Float)0, pdfPhi * pdfMu); // Compute the scattered direction for _FourierBSDF_ Float sin2ThetaI = 1 - muI * muI; Float norm = std::sqrt(sin2ThetaI / Sin2Theta(wo)); Float sinPhi = std::sin(phi), cosPhi = std::cos(phi); *wi = -Vector3f(norm * (cosPhi * wo.x - sinPhi * wo.y), norm * (sinPhi * wo.x + cosPhi * wo.y), muI); // Evaluate remaining Fourier expansions for angle $\phi$ Float scale = muI != 0 ? (1 / std::abs(muI)) : (Float)0; if (mode == TransportMode::Radiance && muI * muO > 0) { float eta = muI > 0 ? 1 / bsdfTable.eta : bsdfTable.eta; scale *= eta * eta; } if (bsdfTable.nChannels == 1) return Spectrum(Y * scale); Float R = Fourier(ak + 1 * bsdfTable.mMax, mMax, cosPhi); Float B = Fourier(ak + 2 * bsdfTable.mMax, mMax, cosPhi); Float G = 1.39829f * Y - 0.100913f * B - 0.297375f * R; Float rgb[3] = {R * scale, G * scale, B * scale}; return Spectrum::FromRGB(rgb).Clamp(); }