Spectrum TabulatedBSSRDF::Sr(Float r) const { Spectrum Sr(0.f); for (int ch = 0; ch < Spectrum::nSamples; ++ch) { // Convert $r$ into unitless optical radius $r_{\roman{optical}}$ Float rOptical = r * sigma_t[ch]; // Compute spline weights to interpolate BSSRDF on channel _ch_ int rhoOffset, radiusOffset; Float rhoWeights[4], radiusWeights[4]; if (!CatmullRomWeights(table.nRhoSamples, table.rhoSamples.get(), rho[ch], &rhoOffset, rhoWeights) || !CatmullRomWeights(table.nRadiusSamples, table.radiusSamples.get(), rOptical, &radiusOffset, radiusWeights)) continue; // Set BSSRDF value _Sr[ch]_ using tensor spline interpolation Float sr = 0; for (int i = 0; i < 4; ++i) { for (int j = 0; j < 4; ++j) { Float weight = rhoWeights[i] * radiusWeights[j]; if (weight != 0) sr += weight * table.EvalProfile(rhoOffset + i, radiusOffset + j); } } // Cancel marginal PDF factor from tabulated BSSRDF profile if (rOptical != 0) sr /= 2 * Pi * rOptical; Sr[ch] = sr; } // Transform BSSRDF value into world space units Sr *= sigma_t * sigma_t; return Sr.Clamp(); }
Float TabulatedBSSRDF::Pdf_Sr(int ch, Float r) const { // Convert $r$ into unitless optical radius $r_{\roman{optical}}$ Float rOptical = r * sigma_t[ch]; // Compute spline weights to interpolate BSSRDF density on channel _ch_ int rhoOffset, radiusOffset; Float rhoWeights[4], radiusWeights[4]; if (!CatmullRomWeights(table.nRhoSamples, table.rhoSamples.get(), rho[ch], &rhoOffset, rhoWeights) || !CatmullRomWeights(table.nRadiusSamples, table.radiusSamples.get(), rOptical, &radiusOffset, radiusWeights)) return 0.f; // Return BSSRDF profile density for channel _ch_ Float sr = 0, rhoEff = 0; for (int i = 0; i < 4; ++i) { if (rhoWeights[i] == 0) continue; rhoEff += table.rhoEff[rhoOffset + i] * rhoWeights[i]; for (int j = 0; j < 4; ++j) { if (radiusWeights[j] == 0) continue; sr += table.EvalProfile(rhoOffset + i, radiusOffset + j) * rhoWeights[i] * radiusWeights[j]; } } // Cancel marginal PDF factor from tabulated BSSRDF profile if (rOptical != 0) sr /= 2 * Pi * rOptical; return std::max((Float)0, sr * sigma_t[ch] * sigma_t[ch] / rhoEff); }
bool FourierBSDFTable::GetWeightsAndOffset(Float cosTheta, int *offset, Float weights[4]) const { return CatmullRomWeights(nMu, mu, cosTheta, offset, weights); }