1#ifndef _BBM_NDF_SAMPLER_H_
2#define _BBM_NDF_SAMPLER_H_
34 template<
typename NDF,
size_t samplesTheta=90,
size_t samplesPhi=1, string_literal NAME=NDF::name + string_literal(
"_sampler")>
requires concepts::ndf<NDF>
63 Vec3d
sample(
const Vec3d& ,
const Vec2d& xi, Mask mask=
true)
const
66 mask &= (xi[0] >= 0) && (xi[0] <= 1) && (xi[1] >= 0) && (xi[1] <= 1);
69 if(bbm::none(mask))
return 0.0;
75 auto [index, residual] =
bbm::pick<
"index",
"residual">(
_cdf.
sample(xi[0], bbm::cast<index_mask_t<Value>>(mask)) );
78 auto xi_r = bbm::abs(residual - 0.5);
79 auto sample_offset = 1 - bbm::safe_sqrt(1 - 2*xi_r);
83 spherical::theta(h) = bbm::pow( (index + 0.5 + bbm::sign(residual-0.5)*sample_offset) / samplesTheta, 2.0 ) * Constants::Pi(0.5);
102 Value
pdf(
const Vec3d& ,
const Vec3d& m, Mask mask=
true)
const
108 if(bbm::none(mask))
return 0;
115 Value theta_index = bbm::sqrt(theta / Constants::Pi(0.5)) * samplesTheta - 0.5;
118 Value w = theta_index - bbm::floor(theta_index);
119 Size_t lidx = bbm::clamp( bbm::cast<Size_t>(bbm::floor(theta_index)), 0, samplesTheta-1);
120 Size_t uidx = bbm::clamp( bbm::cast<Size_t>(bbm::ceil(theta_index)), 0, samplesTheta-1);
121 Value
pdf =
_cdf.
pdf( lidx, bbm::cast<index_mask_t<Value>>(mask) ) * (1-w) +
_cdf.
pdf( uidx, bbm::cast<index_mask_t<Value>>(mask)) * w;
124 Value jac = (bbm::sqrt(theta) * Constants::Pi2(0.25) / samplesTheta) * bbm::abs(bbm::sin(theta)) * (Constants::Pi(2.0));
127 return bbm::select(mask && (jac > Constants::Epsilon()),
pdf / jac, 0);
152 std::vector<Value> samples;
155 for(
size_t thetaIdx=0; thetaIdx != samplesTheta; ++thetaIdx)
158 spherical::theta(h) = bbm::pow(Scalar(thetaIdx) / Scalar(samplesTheta), 2.0) * Constants::Pi(0.5);
160 for(
size_t phiIdx=0; phiIdx != samplesPhi; ++phiIdx)
162 spherical::phi(h) = Scalar(phiIdx) / Scalar(samplesPhi) * Constants::Pi(2);
170 Scalar theta1 = bbm::pow(Scalar(thetaIdx + 1) / Scalar(samplesTheta), 2.0) * Constants::Pi(0.5) ;
171 sample *= bbm::sin(theta1) * bbm::sqrt(theta1);
174 samples.push_back(
sample);
All includes and helpers needed for declaring new ndfs.
Discrete Cummulative Distribution Function (cdf) constructed from a set of samples and accompanying s...
Replace an NDFs sample and pdf method with a data-driven numerical approximation.
Definition: sampler.h:36
value_copy_tuple_t< anonymize_t< bbm::reflection::attributes_t< NDF > > > _monitor
Definition: sampler.h:186
Value pdf(const Vec3d &, const Vec3d &m, Mask mask=true) const
PDF of sampling the NDF.
Definition: sampler.h:102
Vec3d sample(const Vec3d &, const Vec2d &xi, Mask mask=true) const
Sample the NDF.
Definition: sampler.h:63
cdf< std::vector< Value > > _cdf
Definition: sampler.h:187
void initialize(void) const
initialize the data structures
Definition: sampler.h:143
static constexpr string_literal name
Definition: sampler.h:40
constexpr decltype(auto) attributes(T &&t)
Definition: reflection.h:200
T & phi(vec2d< T > &v)
Definition: spherical.h:39
vec2d< T > convert(const vec3d< T > &v)
Definition: spherical.h:53
T & theta(vec2d< T > &v)
Definition: spherical.h:23
constexpr decltype(auto) z(bbm::vec3d< T > &v)
Definition: vec.h:26
Definition: aggregatebsdf.h:29
constexpr auto select(MASK &&mask, const A &a, const A &b)
Definition: backbone.h:255
decltype(value_copy_tuple(std::declval< std::decay_t< T > >())) value_copy_tuple_t
value-copy type of a tuple.
Definition: tuple.h:73
constexpr auto pick(T &&t)
Pick a subset/reshuffle a named container T and return as a named tuple.
Definition: named.h:305
CDF data structure.
Definition: cdf.h:29
size_t size(void) const
number of samples
Definition: cdf.h:65
auto sample(const value_type &xi, index_mask_t< index_type > mask=true) const
sample the CDF given a random variable xi
Definition: cdf.h:85
auto pdf(const index_type &idx, index_mask_t< index_type > mask=true) const
querry the PDF that an index will be sampled.
Definition: cdf.h:113
Definition: string_literal.h:16