Loading...
Searching...
No Matches
aggregatebsdf.h
Go to the documentation of this file.
1#ifndef _BBM_AGGREGATEBSDF_H_
2#define _BBM_AGGREGATEBSDF_H_
3
4#include <vector>
5#include <numeric>
6#include <utility>
7#include <algorithm>
8
9#include "concepts/config.h"
11
12#include "util/multirange_for.h"
13
14#include "bbm/bsdf.h"
15#include "bbm/bsdf_ptr.h"
17
18
19
20/************************************************************************/
21/*! \file aggregatebsdf.h
22 \brief A run-time aggregation of BSDFs.
23
24 In contrast to aggregatemodel which aggregates BSDF models at compile
25 time, aggregatebsdf aggregates BSDFs at run time by using virtual
26 functions.
27*************************************************************************/
28
29namespace bbm {
30
31 /**********************************************************************/
32 /*! \brief A BSDF that is the aggregate of different BSDFs.
33
34 Note: the aggregatebsdf does not own the BSDFs, instead it takes
35 bsdf_ptrs as input.
36 ***********************************************************************/
37 template<typename CONF, string_literal NAME="Aggregate"> requires concepts::config<CONF>
38 class aggregatebsdf : public bsdf_base<CONF>
39 {
40 public:
42 static constexpr string_literal name = NAME;
44
45 //! \brief Construct an aggregate bsdf from a list of bsdf_ptrs.
46 template<typename... BSDFS> requires concepts::matching_config<Config, BSDFS...> && (concepts::bsdf_ptr<BSDFS> && ...)
47 aggregatebsdf(const BSDFS&... src) : _bsdfs({src...}) {}
48
49 //! \brief Construct an aggregate bsdf from iterators to list of 'bsdf_ptrs'
50 template<typename ITR> requires std::input_or_output_iterator<ITR> && concepts::bsdf< std::iter_reference_t<ITR> > && concepts::matching_config< std::iter_reference_t<ITR> > && concepts::bsdf_ptr< std::iter_value_t<ITR> >
51 aggregatebsdf(const ITR& begin, const ITR& end)
52 {
53 // copy
54 for(ITR itr = begin; itr != end; ++itr)
55 _bsdfs.push_back(*itr);
56 }
57
58 //! \brief Copy Constructor
60
61 //! \brief Assignment Operator
63
64 /********************************************************************/
65 /*! \brief Sum the BSDF evaluations for a given in out direction
66
67 \param in = incident direction
68 \param out = outgoing direction
69 \param component = which reflectance component to eval
70 \param unit = unit of computation
71 \param mask = masking of lanes (e.g., for Packet eval)
72 \returns Evaluation of the BSDF per spectrum.
73
74 Evaluation is performed by evaluating each BSDF in _bsdfs, and adding
75 the results.
76 *********************************************************************/
77 virtual Spectrum eval(const Vec3d& in, const Vec3d& out, BsdfFlag component=bsdf_flag::All, unit_t unit=unit_t::Radiance, Mask mask=true) const override final
78 {
79 // accumulate eval of each bsdf.
80 return std::accumulate(_bsdfs.begin(), _bsdfs.end(), Spectrum(0), [&](const Spectrum& result, auto& bsdf)
81 {
82 return result + bsdf->eval(in, out, component, unit, mask);
83 });
84 }
85
86
87 /********************************************************************/
88 /*! \brief Sample the aggregate BSDF given a direction and two random variables.
89
90 \param out = outgoing direction
91 \param xi = two random variables stored in a Vec2d
92 \param component = which reflectance component to sample
93 \param unit = unit of computation
94 \param mask = masking of lanes.
95 \returns A bsdfSample containing the sampled in direction and the corresponding pdf.
96
97 Selects one BSDF in _bsdf to sample based with a probability
98 propertional to the hemispherical reflectances of each BSDF. The selected BSDF is then
99 sampled, and its sampled direction is returned. The PDF is computed as
100 the weighted sum of each BSDF's PDF and the reflectance weights.
101 *********************************************************************/
102 virtual BsdfSample sample(const Vec3d& out, const Vec2d& xi, BsdfFlag component=bsdf_flag::All, unit_t unit=unit_t::Radiance, Mask mask=true) const override final
103 {
104 BsdfSample result;
105
106 // get weights & sum
107 std::vector<Value> weights;
108 Value sum = 0;
109 for(auto& bsdf : _bsdfs)
110 {
111 weights.push_back( bbm::hsum(bsdf->reflectance(out, component, unit, mask)) );
112 sum += weights.back();
113 }
114
115 // quick bail out
116 mask &= (sum > Constants::Epsilon());
117 if(bbm::none(mask)) return result;
118
119 // Iterate through all _bsdfs and select a bsdf based on xi[0]
120 // 1) there are likely few bsdfs in _bsdfs, so a binary search is overkill
121 // 2) when using packet types, we likely need to sample all models anyway
122 auto residual = xi[0] * sum;
123
124 multirange_for([&](auto& bsdf, auto& weight)
125 {
126 // within range?
127 Mask temp_mask = mask && ((residual >= 0) && (residual <= weight));
128
129 // Normalize residual
130 Value normalized_residual = bbm::select(temp_mask && (weight > Constants::Epsilon()), residual / weight, 0);
131
132 // sample if temp_mask is true
133 result = bbm::select(temp_mask, bsdf->sample(out, Vec2d( normalized_residual, xi[1] ), component, unit, temp_mask), result);
134
135 // next sample
136 residual -= weight;
137 }, _bsdfs, weights);
138
139 // update pdf with weighted sum
140 result.pdf = 0;
141 multirange_for([&](auto& bsdf, auto& weight)
142 {
143 result.pdf += weight * bsdf->pdf(result.direction, out, component, unit, mask) / sum;
144 }, _bsdfs, weights);
145
146 // Done.
147 return result;
148 }
149
150
151 /********************************************************************/
152 /*! \brief Compute the pdf given an in and out direction
153
154 \param in = the incoming sampled direction
155 \param out = the outgoing (given) direction
156 \param component = which reflectance component was sampled
157 \param unit = unit of computation
158 \param mask = masking of lanes
159 \returns the PDF that the incoming direction would be sampled given the outgoing direction.
160
161 The PDF is computed as the hemispherical reflectance weighted sum of all PDFs.
162 *******************************************************************/
163 virtual Value pdf(const Vec3d& in, const Vec3d& out, BsdfFlag component=bsdf_flag::All, unit_t unit=unit_t::Radiance, Mask mask=true) const override final
164 {
165
166 // get weights & sum
167 std::vector<Value> weights;
168 Value sum = 0;
169 for(auto& bsdf : _bsdfs)
170 {
171 weights.push_back( bbm::hsum(bsdf->reflectance(out, component, unit, mask)) );
172 sum += weights.back();
173 }
174
175 // quick bail out
176 mask &= (sum > Constants::Epsilon());
177 if(bbm::none(mask)) return Value(0);
178
179 // compute and return pdf as weighted sum
180 Value pdf = 0;
181 multirange_for([&](auto& bsdf, auto& weight)
182 {
183 pdf += weight * bsdf->pdf(in, out, component, unit, mask) / sum;
184 }, _bsdfs, weights);
185
186 // Done.
187 return pdf;
188 }
189
190
191 /*****************************************************************/
192 /*! \brief Return the (approximate) hemispherical reflectance of the BSDF
193
194 \param out = the outgoing direction
195 \param component = which reflectance component to eval
196 \param unit = unit of computation
197 \param mask = masking of lanes
198 \returns the approximate hemispherical reflectance of the BSDF for a given outgoing direction
199
200 The reflectance is computed as the sum of the underlying BSDF's hemispherical reflectance.
201 ******************************************************************/
202 virtual Spectrum reflectance(const Vec3d& out, BsdfFlag component=bsdf_flag::All, unit_t unit=unit_t::Radiance, Mask mask=true) const override final
203 {
204 // accumulate reflectance over all bsdfs.
205 Spectrum sum(0);
206 for(auto& bsdf : _bsdfs)
207 sum += bsdf->reflectance(out, component, unit, mask);
208
209 // Done.
210 return sum;
211 }
212
213
214 /******************************************************************/
215 /*! \brief Convert the aggregatebsdf to string
216 ******************************************************************/
217 virtual std::string toString(void) const override final
218 {
220 }
221
222 /*******************************************************************/
223 /*! \brief Construct the aggregate bsdf from a string
224 *******************************************************************/
225 static inline aggregatebsdf fromString(const std::string& str)
226 {
227 auto [key, value] = string::get_keyword(str);
228
229 // check name
230 if(key != std::string(aggregatebsdf::name)) throw std::invalid_argument(std::string("BBM: mismatched object name ") + key + ", expected " + std::string(aggregatebsdf::name));
231
232 // read vector of bsdf_ptrs
233 auto bsdfs = bbm::fromString<bbm::vector<bsdf_ptr<Config>>>(value);
234
235 // Done: create from vector.
236 return aggregatebsdf(std::begin(bsdfs), std::end(bsdfs));
237 }
238
239 /*******************************************************************/
240 /*! \name Parameter Enumeration
241 *******************************************************************/
243 {
244 bbm::vector<Value&> result;
245 for(auto& bsdf : _bsdfs)
246 {
247 auto param = bbm::parameter_values(bsdf, flags);
248 result.insert(result.end(), param.begin(), param.end());
249 }
250 return result;
251 }
252
254 {
256 for(auto& bsdf : _bsdfs)
257 {
258 auto param = bbm::parameter_values(std::as_const(bsdf), flags);
259 result.insert(result.end(), param.begin(), param.end());
260 }
261 return result;
262 }
263
265 {
266 bbm::vector<Value> result;
267 for(auto& bsdf : _bsdfs)
268 {
269 auto param = bbm::parameter_default_values(bsdf, flags);
270 result.insert(result.end(), param.begin(), param.end());
271 }
272 return result;
273 }
274
276 {
277 bbm::vector<Value> result;
278 for(auto& bsdf : _bsdfs)
279 {
280 auto param = bbm::parameter_lower_bound(bsdf, flags);
281 result.insert(result.end(), param.begin(), param.end());
282 }
283 return result;
284 }
285
287 {
288 bbm::vector<Value> result;
289 for(auto& bsdf : _bsdfs)
290 {
291 auto param = bbm::parameter_upper_bound(bsdf, flags);
292 result.insert(result.end(), param.begin(), param.end());
293 }
294 return result;
295 }
296 //! @}
297
298 private:
299 //////////////////
300 // Data Members //
301 //////////////////
302 std::vector<bsdf_ptr<Config>> _bsdfs;
303 };
304
305
306 /*********************************************************************/
307 /*! @{ \brief Helper methods for simplifying the creation of a aggregate bsdf
308
309 This is a companion method to aggregate in aggregatemodel.h. Based on
310 the available information at compile time, aggrgate chooses the most
311 optimal aggregate bsdf defintion:
312
313 + If all arguments are BSDF models, then the result is an aggregatemodel
314 + If all arguments are bsdf<BSDFMODEL>, then the result is an bsdf<aggregatemodel>
315 + If all arguments are bsdf_ptr, then the result is an aggregatebsdf
316 + If all arguments are pased via an iterator, then the result is an aggregatebsdf.
317
318 In the latter two cases, the underlying BSDFMODEL information is only
319 known at run-time, and hence, the run-time aggregatebsdf is required. In
320 the first case, because the user specifies models directly, the result is
321 expected to be a model too. Finally, a bsdf<aggregatemodel> is less overhead
322 than an aggregatebsdf, and hence, it is preferred when at compile time
323 the BSDF models are known.
324
325 Note: ownership of the data depenends on the underlying model. In the
326 case of aggregate bsdfs, ownership still lies with the original BSDF.
327 ***********************************************************************/
328 template<typename... BSDFMODELs> requires (concepts::bsdfmodel<BSDFMODELs> && ...)
329 auto aggregate(const bsdf<BSDFMODELs>&... src)
330 {
331 return bsdf<aggregatemodel<BSDFMODELs...>>( (dynamic_cast<const BSDFMODELs&>(src))... );
332 }
333
334 template<typename... CONFs> requires (concepts::config<CONFs> && ...)
335 auto aggregate(const bsdf_ptr<CONFs>&... src)
336 {
337 using cfg = get_config< std::tuple_element_t<0, std::tuple<CONFs...>> >;
338 return aggregatebsdf<cfg>(src...);
339 }
340
341
342 template<typename ITR> requires (std::input_or_output_iterator<ITR> && concepts::bsdf_ptr<std::iter_reference_t<ITR>>)
343 auto aggregate(const ITR& begin, const ITR& end)
344 {
347 }
348 //! @}
349
350} // end bbm namespace
351
352#endif /* _BBM_AGGREGATEBSDF_H_ */
The sum of different BSDF models.
Connects a BSDF model and a BSDF.
A shared_ptr wrapper for bsdfs.
A BSDF that is the aggregate of different BSDFs.
Definition: aggregatebsdf.h:39
virtual bbm::vector< Value > parameter_upper_bound(bsdf_attr flags=bsdf_attr::All) const override final
Definition: aggregatebsdf.h:286
virtual bbm::vector< Value > parameter_lower_bound(bsdf_attr flags=bsdf_attr::All) const override final
Definition: aggregatebsdf.h:275
std::vector< bsdf_ptr< Config > > _bsdfs
Definition: aggregatebsdf.h:302
virtual bbm::vector< Value > parameter_default_values(bsdf_attr flags=bsdf_attr::All) const override final
Definition: aggregatebsdf.h:264
virtual Value pdf(const Vec3d &in, const Vec3d &out, BsdfFlag component=bsdf_flag::All, unit_t unit=unit_t::Radiance, Mask mask=true) const override final
Compute the pdf given an in and out direction.
Definition: aggregatebsdf.h:163
static aggregatebsdf fromString(const std::string &str)
Construct the aggregate bsdf from a string.
Definition: aggregatebsdf.h:225
aggregatebsdf(const ITR &begin, const ITR &end)
Construct an aggregate bsdf from iterators to list of 'bsdf_ptrs'.
Definition: aggregatebsdf.h:51
virtual Spectrum eval(const Vec3d &in, const Vec3d &out, BsdfFlag component=bsdf_flag::All, unit_t unit=unit_t::Radiance, Mask mask=true) const override final
Sum the BSDF evaluations for a given in out direction.
Definition: aggregatebsdf.h:77
virtual BsdfSample sample(const Vec3d &out, const Vec2d &xi, BsdfFlag component=bsdf_flag::All, unit_t unit=unit_t::Radiance, Mask mask=true) const override final
Sample the aggregate BSDF given a direction and two random variables.
Definition: aggregatebsdf.h:102
BBM_BSDF_FORWARD
Definition: aggregatebsdf.h:43
aggregatebsdf(const BSDFS &... src)
Construct an aggregate bsdf from a list of bsdf_ptrs.
Definition: aggregatebsdf.h:47
virtual bbm::vector< Value & > parameter_values(bsdf_attr flags=bsdf_attr::All) override final
Definition: aggregatebsdf.h:242
aggregatebsdf(const aggregatebsdf< Config > &src)
Copy Constructor.
Definition: aggregatebsdf.h:59
aggregatebsdf< Config > & operator=(const aggregatebsdf< Config > &src)
Assignment Operator.
Definition: aggregatebsdf.h:62
virtual bbm::vector< const Value & > parameter_values(bsdf_attr flags=bsdf_attr::All) const override final
Definition: aggregatebsdf.h:253
virtual Spectrum reflectance(const Vec3d &out, BsdfFlag component=bsdf_flag::All, unit_t unit=unit_t::Radiance, Mask mask=true) const override final
Return the (approximate) hemispherical reflectance of the BSDF.
Definition: aggregatebsdf.h:202
static constexpr string_literal name
Definition: aggregatebsdf.h:42
virtual std::string toString(void) const override final
Convert the aggregatebsdf to string.
Definition: aggregatebsdf.h:217
BSDF implementation of a BSDF model.
Definition: bsdf.h:30
virtual Value pdf(const Vec3d &in, const Vec3d &out, BsdfFlag component=bsdf_flag::All, unit_t unit=unit_t::Radiance, Mask mask=true) const override final
Virtual passthrough of the pdf function.
Definition: bsdf.h:89
virtual Spectrum eval(const Vec3d &in, const Vec3d &out, BsdfFlag component=bsdf_flag::All, unit_t unit=unit_t::Radiance, Mask mask=true) const override final
Virtual passthrough of eval function.
Definition: bsdf.h:56
virtual BsdfSample sample(const Vec3d &out, const Vec2d &xi, BsdfFlag component=bsdf_flag::All, unit_t unit=unit_t::Radiance, Mask mask=true) const override final
Virtual passthrough of sample function.
Definition: bsdf.h:73
virtual Spectrum reflectance(const Vec3d &out, BsdfFlag component=bsdf_flag::All, unit_t unit=unit_t::Radiance, Mask mask=true) const override final
Virtual passthrough of the hemispherical reflectance function.
Definition: bsdf.h:104
Definition: vector_util.h:27
bsdf_ptr concpt
Definition: bsdf_ptr.h:24
bsdfmodel concept
Definition: bsdfmodel.h:33
config concept
Definition: config.h:31
matching_config concept
Definition: config.h:63
config contract
concept to check if a type has a valid string_converter.
ranged for loop over multiple containers at once
std::pair< std::string, std::string > get_keyword(const std::string &str)
Return the keyword substring appearing an open bracket, and the arguments appearing in the brackets: ...
Definition: string_util.h:65
Definition: aggregatebsdf.h:29
auto parameter_default_values(MODEL &&model, bsdf_attr flag=bsdf_attr::All)
Enumerate the default parameters of a BSDF model in a vector.
Definition: bsdf_enumerate.h:142
constexpr auto select(MASK &&mask, const A &a, const A &b)
Definition: backbone.h:255
void multirange_for(FUNC &&func, Ts &&... containers)
ranged for loop over multiple containers at once
Definition: multirange_for.h:43
typename std::decay_t< T >::Config get_config
get_config type trait
Definition: config.h:49
auto parameter_upper_bound(MODEL &&model, bsdf_attr flag=bsdf_attr::All)
Enumerate the upper bound of the parameters of a BSDF model in a vector.
Definition: bsdf_enumerate.h:213
auto end(T &&t)
Definition: iterator_util.h:43
std::string toString(const T &)
toString alias
Definition: stringconvert.h:594
auto aggregate(const bsdf< BSDFMODELs > &... src)
Helper methods for simplifying the creation of a aggregate bsdf.
Definition: aggregatebsdf.h:329
auto parameter_lower_bound(MODEL &&model, bsdf_attr flag=bsdf_attr::All)
Enumerate the lower bound of the parameters of a BSDF model in a vector.
Definition: bsdf_enumerate.h:178
auto begin(T &&t)
Definition: iterator_util.h:29
decltype(auto) value(T &&t)
return the value of an attribute, or if not an attribute the object
Definition: attribute_value.h:20
auto parameter_values(MODEL &&model, bsdf_attr flag=bsdf_attr::All)
Enumerate the parameters of a BSDF model in a vector.
Definition: bsdf_enumerate.h:103
bsdf_attr
Attribute Property Flags.
Definition: bsdf_attr_flag.h:17
unit_t
Light Unit.
Definition: unit.h:21
The sum of different BSDF models.
Definition: aggregatemodel.h:24
Forward declaration.
Definition: bsdf_base.h:55
Definition: bsdf_ptr.h:22
Definition: string_literal.h:16