bool DipoleBSSRDF::sample( SamplingContext& sampling_context, const void* data, BSSRDFSample& sample) const { const DipoleBSSRDFInputValues* values = reinterpret_cast<const DipoleBSSRDFInputValues*>(data); if (values->m_weight == 0.0) return false; sampling_context.split_in_place(3, 1); const Vector3d s = sampling_context.next_vector2<3>(); // Sample a channel. const size_t channel = sample_cdf( &values->m_channel_cdf[0], &values->m_channel_cdf[0] + values->m_channel_cdf.size(), s[0]); // Sample a radius. const double sigma_tr = values->m_sigma_tr[channel]; const double radius = sample_exponential_distribution(s[1], sigma_tr); // Sample an angle. const double phi = TwoPi * s[2]; sample.m_eta = values->m_eta; sample.m_channel = channel; sample.m_point = Vector2d(radius * cos(phi), radius * sin(phi)); sample.m_rmax2 = values->m_rmax2; return true; }
double normalized_diffusion_sample( const double u, const double l, const double s, const double eps, const size_t max_iterations) { assert(u >= 0.0); assert(u < 1.0); const double d = l / s; // Handle the case where u is greater than the value we consider 1 in our CDF. if (u >= nd_cdf_rmax) return NdCdfTableRmax * d; // Use the CDF to find an initial interval for the root of cdf(r, 1) - u = 0. const size_t i = sample_cdf(nd_cdf_table, nd_cdf_table + NdCdfTableSize, u); assert(i > 0); assert(nd_cdf_table[i - 1] <= u); assert(nd_cdf_table[i] > u); // Transform the cdf(r, 1) interval to cdf(r, d) using the fact that cdf(r, d) == cdf(r/d, 1). double rmin = fit<size_t, double>(i - 1, 0, NdCdfTableSize - 1, 0.0, NdCdfTableRmax) * d; double rmax = fit<size_t, double>(i, 0, NdCdfTableSize - 1, 0.0, NdCdfTableRmax) * d; assert(normalized_diffusion_cdf(rmin, d) <= u); assert(normalized_diffusion_cdf(rmax, d) > u); double r = (rmax + rmin) * 0.5; // Refine the root. for (size_t i = 0; i < max_iterations; ++i) { // Use bisection if we go out of bounds. if (r < rmin || r > rmax) r = (rmax + rmin) * 0.5; const double f = normalized_diffusion_cdf(r, d) - u; // Convergence test. if (abs(f) <= eps) break; // Update bounds. f < 0.0 ? rmin = r : rmax = r; // Newton step. const double df = normalized_diffusion_pdf(r, d); r -= f / df; } return r; }
double normalized_diffusion_sample( const double u, const double l, const double s, const double eps, const size_t max_iterations) { assert(u >= 0.0); assert(u < 1.0); const double d = l / s; // Handle the case where u is greater than the value we consider 1 in our CDF. if (u >= nd_cdf_rmax) return NDCDFTableRmax * d; // Use the CDF to find an initial interval for the root of cdf(r, 1) - u = 0. const size_t i = sample_cdf(nd_cdf_table, nd_cdf_table + NDCDFTableSize, u); assert(i > 0); assert(nd_cdf_table[i - 1] <= u); assert(nd_cdf_table[i] > u); // Transform the cdf(r, 1) interval to cdf(r, d) using the fact that cdf(r, d) == cdf(r/d, 1). const double rmin = fit<size_t, double>(i - 1, 0, NDCDFTableSize - 1, 0.0, NDCDFTableRmax) * d; const double rmax = fit<size_t, double>(i, 0, NDCDFTableSize - 1, 0.0, NDCDFTableRmax) * d; return invert_cdf_function( NDCDFFun(d), NDPDFFun(d), u, rmin, rmax, (rmax + rmin) * 0.5, eps, max_iterations); }
size_t CompositeClosure::choose_closure(const double w) const { return sample_cdf(m_cdf, m_cdf + get_num_closures(), w); }