Loading...
Searching...
No Matches
ndf_sampler.h
Go to the documentation of this file.
1#ifndef _BBM_NDF_IMPORTANCE_SAMPLER_H_
2#define _BBM_NDF_IMPORTANCE_SAMPLER_H_
3
4#include <map>
5
7#include "util/reflection.h"
8#include "util/reference.h"
9#include "ndf/sampler.h"
10
11/************************************************************************/
12/*! \file ndf_sampler.h
13
14 \brief Replaces a(n isotrpic) BSDF model's importance sampling with a
15 data-driven NDF based sampler.
16
17 Assumes the BSDF model is isotropic.
18
19************************************************************************/
20
21namespace bbm {
22
23 template<typename BSDFMODEL, size_t samplesTheta=90, size_t samplesPhi=1, string_literal NAME=BSDFMODEL::name> requires concepts::bsdfmodel<BSDFMODEL>
24 class ndf_sampler : public BSDFMODEL
25 {
26 BBM_BASETYPES( BSDFMODEL );
27
28 /********************************************************************/
29 /*! \brief Helper Class: Backscatter NDF passthrough
30
31 Wraps the BSDF model's eval function in an NDF eval; other NDF methods
32 are unevaluable. This is used to construct an ndf::sampler
33 ********************************************************************/
35 {
36 BBM_BASETYPES(void); // Avoid clash with the base_type of ndf_sampler
37 BBM_IMPORT_CONFIG( BSDFMODEL );
38 static constexpr string_literal name = "backscatter_" + NAME;
39
40 backscatter(void) {}
41 backscatter(const BSDFMODEL* src, bsdf_flag c, unit_t u) : component(c), unit(u), model(src) {}
42
43 Value eval(const Vec3d& halfway, Mask mask=true) const { return bbm::hsum(model->eval(halfway, halfway, component, unit, mask)); }
44 Vec3d sample(const Vec3d& view, const Vec2d& xi, Mask mask=true) const; // unevaluable
45 Value pdf(const Vec3d& view, const Vec3d& m, Mask mask=true) const; // unevaluable
46 Value G1(const Vec3d& v, const Vec3d& m, Mask mask=true) const; // unevaluable
47
48 bsdf_flag component; //< component to sample
49 unit_t unit; //< unit to sample
50 const BSDFMODEL* model; //< pointer to BSDF model to sample
52 };
53
55
56 public:
57 BBM_IMPORT_CONFIG( BSDFMODEL );
58 static constexpr string_literal name = NAME;
60
61 //! forward to parent constructor, with empty _sampler (due to reference to *this)
62 template<typename... Ts> requires std::constructible_from<BSDFMODEL, Ts...>
63 ndf_sampler(Ts&&... ts) : BSDFMODEL(std::forward<Ts>(ts)...), _samplers() {}
64
65 // Passthrough: constructors, eval and reflectance
66 using BSDFMODEL::eval;
67 using BSDFMODEL::reflectance;
68
69 /********************************************************************/
70 /*! \brief Sample the diffuse BSDF given a direction and two random variables.
71
72 \param out = outgoing direction
73 \param xi = two random variables stored in a Vec2d
74 \param component = which reflectance component to sample
75 \param unit = unit of computation (ignored)
76 \param mask = masking of lanes.
77 \returns A bsdfSample containing the sampled direction and the corresponding pdf.
78 *********************************************************************/
79 BsdfSample sample(const Vec3d& out, const Vec2d& xi, BsdfFlag component=bsdf_flag::All, unit_t unit=unit_t::Radiance, Mask mask=true) const
80 {
81 BsdfSample sample = {0,0,bsdf_flag::None};
82
83 // check for valid xi
84 mask &= (xi[0] >= 0) && (xi[1] >= 0) && (xi[0] <= 1) && (xi[1] <= 1);
85
86 // check out lies above the horizon
87 mask &= (vec::z(out) > 0);
88
89 // Quick exit if mask all negative
90 if(bbm::none(mask)) return sample;
91
92 // Sample the correct ndf based on (component,unit)
93 Vec3d halfway;
94
95 for(auto u : bbm::reflection::enum_v<unit_t>)
96 for(auto c : bbm::reflection::enum_v<bsdf_flag>)
97 {
98 auto sample_mask = mask && bbm::eq(component, c) && bbm::eq(unit, u);
99 if(bbm::any(sample_mask))
100 {
101 // Create sampler if it does not exist for the given component/unit combination
102 auto [itr,init] = _samplers.try_emplace(std::pair(c,u), ndf::sampler<backscatter, samplesTheta, samplesPhi>(this, c, u));
103
104 // update sampled halfway
105 halfway = bbm::select(sample_mask, itr->second.sample(out, xi, sample_mask), halfway);
106 }
107 }
108
109 // haflway -> direction
110 sample.direction = bbm::select(mask, reflect(out, halfway), 0);
111 sample.pdf = pdf(sample.direction, out, component, unit, mask);
112 sample.flag = bbm::select(mask, component, BsdfFlag(bsdf_flag::None));
113
114 // Done.
115 return sample;
116 }
117
118 /********************************************************************/
119 /*! \brief Compute the pdf given an in and out direction
120
121 \param in = the incoming (sampled) direction
122 \param out = the outgoing (given) direction
123 \param component = which reflectance component was sampled
124 \param unit = unit of computation (ignored)
125 \param mask = masking of lanes
126 \returns the PDF that the incoming direction would be sampled given the outgoing direction.
127 ***********************************************************************/
128 Value pdf(const Vec3d& in, const Vec3d& out, BsdfFlag component=bsdf_flag::All, unit_t unit=unit_t::Radiance, Mask mask=true) const
129 {
130 // check out and in lie above the horizon
131 mask &= (vec::z(out) > 0) && (vec::z(in) > 0);
132
133 // Quick exit if mask all negative
134 if(bbm::none(mask)) return 0;
135
136 // Compute PDF for the correct ndf based on (component,unit)
137 Vec3d h = halfway(in, out);
138 Value pdf(0);
139
140 for(auto u : bbm::reflection::enum_v<unit_t>)
141 for(auto c : bbm::reflection::enum_v<bsdf_flag>)
142 {
143 auto pdf_mask = mask && bbm::eq(component, c) && bbm::eq(unit, u);
144 if(bbm::any(pdf_mask))
145 {
146 // Create sampler if it does not exist for the given component/unit combination
147 auto [itr,init] = _samplers.try_emplace(std::pair(c,u), ndf::sampler<backscatter, samplesTheta, samplesPhi>(this, c, u));
148
149 // update pdf
150 pdf = bbm::select(pdf_mask, itr->second.pdf(out, h, pdf_mask), pdf);
151 }
152 }
153
154 // Done; pdf = pdfh) / (4 out . h)
155 return bbm::select(mask, pdf / bbm::abs(4.0 * bbm::dot(out, h)), 0);
156 }
157
158 private:
159 ///////////////////////////////
160 //! @{ \name Class Attributes
161 ///////////////////////////////
162 mutable std::map< std::pair<bsdf_flag, unit_t>, ndf::sampler<backscatter, samplesTheta, samplesPhi> > _samplers;
163 };
164
165} // end bbm namespace
166
167#endif /* _BBM_NDF_IMPORTANCE_SAMPLER_H_ */
Replace an NDFs sample and pdf method with a data-driven numerical approximation.
Definition: sampler.h:36
Definition: ndf_sampler.h:25
BBM_CHECK_RAW_CONCEPT(concepts::ndf, backscatter)
BsdfSample sample(const Vec3d &out, const Vec2d &xi, BsdfFlag component=bsdf_flag::All, unit_t unit=unit_t::Radiance, Mask mask=true) const
Sample the diffuse BSDF given a direction and two random variables.
Definition: ndf_sampler.h:79
BBM_BSDF_FORWARD
Definition: ndf_sampler.h:59
Value pdf(const Vec3d &in, const Vec3d &out, BsdfFlag component=bsdf_flag::All, unit_t unit=unit_t::Radiance, Mask mask=true) const
Compute the pdf given an in and out direction.
Definition: ndf_sampler.h:128
BBM_BASETYPES(BSDFMODEL)
BBM_IMPORT_CONFIG(BSDFMODEL)
std::map< std::pair< bsdf_flag, unit_t >, ndf::sampler< backscatter, samplesTheta, samplesPhi > > _samplers
Definition: ndf_sampler.h:162
ndf_sampler(Ts &&... ts)
forward to parent constructor, with empty _sampler (due to reference to *this)
Definition: ndf_sampler.h:63
static constexpr string_literal name
Definition: ndf_sampler.h:58
ndf concept
Definition: ndf.h:29
bsdfmodel contract
constexpr decltype(auto) attributes(T &&t)
Definition: reflection.h:200
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
vec3d< T > halfway(const vec3d< T > &a, const vec3d< T > &b)
Halfway vector (3D)
Definition: vec_transform.h:77
bsdf_flag
Reflectance Component Evaluation Flags.
Definition: bsdf_flag.h:22
vec3d< T > reflect(const vec3d< T > &v, const vec3d< T > &normal)
Reflects a 3D vector.
Definition: vec_transform.h:44
unit_t
Light Unit.
Definition: unit.h:21
Definition: named.h:325
Assignable reference with wrapper support for rvalues.
Replace an NDF's sample and pdf method by a data-driven version. Monitors the NDF and update the inte...
Helper Class: Backscatter NDF passthrough.
Definition: ndf_sampler.h:35
unit_t unit
Definition: ndf_sampler.h:49
Value G1(const Vec3d &v, const Vec3d &m, Mask mask=true) const
Value pdf(const Vec3d &view, const Vec3d &m, Mask mask=true) const
Value eval(const Vec3d &halfway, Mask mask=true) const
Definition: ndf_sampler.h:43
Vec3d sample(const Vec3d &view, const Vec2d &xi, Mask mask=true) const
backscatter(void)
Definition: ndf_sampler.h:40
BBM_ATTRIBUTES(reflection::attributes(*model))
bsdf_flag component
Definition: ndf_sampler.h:48
const BSDFMODEL * model
Definition: ndf_sampler.h:50
backscatter(const BSDFMODEL *src, bsdf_flag c, unit_t u)
Definition: ndf_sampler.h:41
static constexpr string_literal name
Definition: ndf_sampler.h:38
Definition: string_literal.h:16
Compile-time reflection of: