Loading...
Searching...
No Matches
merl.h
Go to the documentation of this file.
1#ifndef _BBM_MERL_H_
2#define _BBM_MERL_H_
3
4#include <fstream>
5#include <utility>
6
7#include "concepts/macro.h"
9
10#include "bbm/config.h"
11#include "bbm/ndf_sampler.h"
12
13#include "core/error.h"
14#include "core/color.h"
15#include "core/spherical.h"
16
18#include "bsdfmodel/lambertian.h"
19
20
21/************************************************************************/
22/*! \file merl.h
23 \brief Support for the MERL-MIT brdf database: https://doi.org/10.1145/882262.882343
24
25 Loading and evaluating of MERL-MIT measured BRDF as a bsdf model
26*************************************************************************/
27
28namespace bbm
29{
30
31 /*********************************************************************/
32 /*! \brief MERL-MIT sampled reflectance
33
34 Stored and provides access to the MERL-MIT measured BRDFs.
35
36 Sample, pdf, and reflectance are implemented by placeholders.
37 **********************************************************************/
38 template<typename CONF, string_literal NAME="MerlData"> requires concepts::config<CONF>
40 {
41 public:
43 static constexpr string_literal name = NAME;
44 //BBM_BSDF_FORWARD;
45
46 //! Empty Constructor
47 merl_data(void) = delete;
48
49 //! Copy constructor
50 merl_data(const merl_data& src) = default;
51
52 //! Assignment operator
53 merl_data& operator=(const merl_data& src) = default;
54
55 /********************************************************************/
56 /*! \brief Import Constructor
57
58 \param filename = name of MERL BRDF file
59 ******************************************************************/
61 {
62 import();
63 }
64
65
66 /********************************************************************/
67 /*! \brief Evaluate the BSDF given an in and out direction
68
69 \param in = incoming direction of transport
70 \param out = exitant direction of transport
71 \param component = which reflectance component to eval
72 \param unit = unit of computation
73 \param mask = mask to enable/disable lanes
74 \returns the resulting Spectrum of the evaluation.
75
76 IMPORTANT: The foreshortning (i.e., cosine) is __NOT__ included.
77 ********************************************************************/
78 Spectrum eval(const Vec3d& in, const Vec3d& out, BsdfFlag component=bsdf_flag::All, unit_t /*unit*/=unit_t::Radiance, Mask mask=true) const
79 {
80 Spectrum result(0);
81
82 // matching flag
83 mask &= is_set(component, bsdf_flag::All);
84
85 // above surface?
86 mask &= (vec::z(in) >= 0) && (vec::z(out) >= 0);
87
88 // Quick exit
89 if(bbm::none(mask)) return result;
90
91 // Get index in data
92 Size_t index = _linearizer(in, out, mask);
93
94 // Get data (TODO: conversion from color to Spectrum)
95 return bbm::lookup<Spectrum>(_data, index, bbm::cast<index_mask_t<Value>>(mask));
96 }
97
98 /*******************************************************************/
99 /*! \brief Sample the sanpled BSDF given a direction and two random variables.
100
101 \param out = outgoing direction
102 \param xi = two random variables stored in a Vec2d
103 \param component = which reflectance component to sample
104 \param unit =unit of computation
105 \param mask = mask to enable/disable lanes
106 \returns A bsdfSample containing the sampled direction and the corresponding pdf.
107 *********************************************************************/
108 BsdfSample sample(const Vec3d& out, const Vec2d& xi, BsdfFlag component=bsdf_flag::All, unit_t unit=unit_t::Radiance, Mask mask=true) const
109 {
110 // matching flag
111 mask &= is_set(component, bsdf_flag::All);
112
113 // Placeholder
114 return lambertian<Config>().sample(out, xi, bsdf_flag::Diffuse, unit, mask);
115 }
116
117 /********************************************************************/
118 /*! \brief Compute the pdf given an in and out direction
119
120 \param in = the incoming direction
121 \param out = the outgoing direction
122 \param component = which reflectance component was sampled
123 \param unit = unit of computation
124 \param mask = enable/disable lanes.
125 \returns the PDF that the outgoing direction would be sampled given the incoming direction.
126 *********************************************************************/
127 Value pdf(const Vec3d& in, const Vec3d& out, BsdfFlag component=bsdf_flag::All, unit_t unit=unit_t::Radiance, Mask mask=true) const
128 {
129 // matching flag
130 mask &= is_set(component, bsdf_flag::All);
131
132 // Placeholder
133 auto sample = lambertian<Config>().pdf(in, out, bsdf_flag::Diffuse, unit, mask);
134 sample.flag = bbm::select(sample.flag == bsdf_flag::Diffuse, BsdfFlag(bsdf_flag::All), BsdfFlag(bsdf_flag::None));
135
136 // Done.
137 return sample;
138 }
139
140 /*****************************************************************/
141 /*! \brief Return the (approximate) hemispherical reflectance of the BSDF
142
143 \param out = the outgoing direction (ignored)
144 \param component = which reflectance component to eval
145 \param unit = unit of computation
146 \param mask = enable/disable lanes
147 \returns the approximate hemispherical reflectance of the BSDF for a given incident direction
148 ******************************************************************/
149 Spectrum reflectance(const Vec3d& /*out*/, BsdfFlag component=bsdf_flag::All, unit_t /*unit*/=unit_t::Radiance, Mask mask=true) const
150 {
151 // matching flag
152 mask &= is_set(component, bsdf_flag::All);
153
154 // Placeholder
155 return bbm::select(mask, Spectrum(1), Spectrum(0));
156 }
157
158 /********************************************************************/
159 /*! \brief Custom string conversion
160 ********************************************************************/
161 inline std::string toString(void) const
162 {
163 return std::string(name) + "(" + bbm::toString(_filename) + ")";
164 }
165
166 private:
167 /********************************************************************/
168 /*! \brief Import MERL data from file
169
170 Load the MERL-MIT BRDF data from path/filename. Will throw a run-time
171 exception if not found, or if the format is not a MERL-MIT format.
172 *********************************************************************/
173 inline void import(void)
174 {
175 // Check file
176 std::ifstream ifs(_filename, std::ios_base::binary);
177 if(!ifs) throw std::runtime_error("BBM: unable to open MERL BRDF: " + bbm::toString(_filename));
178
179 uint32_t thetaH, thetaD, phiD;
180 ifs.read(reinterpret_cast<char*>(&thetaH), sizeof(uint32_t));
181 ifs.read(reinterpret_cast<char*>(&thetaD), sizeof(uint32_t));
182 ifs.read(reinterpret_cast<char*>(&phiD), sizeof(uint32_t));
183
184 if(thetaH != 90 || thetaD != 90 || phiD != 180) throw std::runtime_error("BBM: not a recognized MERL BRDF: " + bbm::toString(_filename));
185
186 // create linearizer
187 _linearizer = merl_linearizer<Config>( vec2d<Size_t>(1, 90), vec2d<Size_t>(180, 90) );
188
189 // read data
190 size_t size = thetaH * thetaD * phiD;
191 auto buffer = std::make_unique<double[]>(3 * size);
192 auto buffer_ref = buffer.get();
193 ifs.read(reinterpret_cast<char *>(buffer_ref), 3 * size * sizeof(double));
194
195 // redistribute (remove negative values and apply white balance)
196 _data.clear();
197 _data.reserve(size);
198
199 for(size_t idx=0; idx != size; ++idx)
200 _data.push_back( color<double>( bbm::max(0, buffer_ref[idx] * 1.0 / 1500.0),
201 bbm::max(0, buffer_ref[size + idx] * 1.15 / 1500.0),
202 bbm::max(0, buffer_ref[2*size + idx] * 1.66 / 1500.0)
203 ) );
204
205 // Done.
206 }
207
208 ///////////////////////
209 //! @{ Class members
210 ///////////////////////
211 std::string _filename;
213 std::vector<color<double>> _data;
214 //! @}
215 };
216
218
219
220 /**********************************************************************/
221 /*! \brief Data-driven MERL BSDF model with data-driven backscatter based
222 importance sampling
223 **********************************************************************/
224 template<typename Config> requires concepts::config<Config>
225 using merl = ndf_sampler<merl_data<Config, "Merl">, 90, 1>;
226
228
229} // end bbm namespace
230
231#endif /* _BBM_MERL_H_ */
232
234
All BBM methods are defined to operate on a variety of value types and spectrum types....
#define BBM_EXPORT_BSDFMODEL(BsdfModel)
Definition: bbm_fromstring.h:49
MERL-MIT sampled reflectance.
Definition: merl.h:40
std::vector< color< double > > _data
Definition: merl.h:213
Spectrum eval(const Vec3d &in, const Vec3d &out, BsdfFlag component=bsdf_flag::All, unit_t=unit_t::Radiance, Mask mask=true) const
Evaluate the BSDF given an in and out direction.
Definition: merl.h:78
merl_data(const merl_data &src)=default
Copy constructor.
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 sanpled BSDF given a direction and two random variables.
Definition: merl.h:108
std::string toString(void) const
Custom string conversion.
Definition: merl.h:161
BBM_IMPORT_CONFIG(CONF)
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: merl.h:127
merl_linearizer< Config > _linearizer
Definition: merl.h:212
merl_data(void)=delete
Empty Constructor.
merl_data & operator=(const merl_data &src)=default
Assignment operator.
std::string _filename
Class members.
Definition: merl.h:211
Spectrum reflectance(const Vec3d &, BsdfFlag component=bsdf_flag::All, unit_t=unit_t::Radiance, Mask mask=true) const
Return the (approximate) hemispherical reflectance of the BSDF.
Definition: merl.h:149
static constexpr string_literal name
Definition: merl.h:43
BBM_CONSTRUCTOR(merl_data, args, arg< const std::string &, "filename">)
Import Constructor.
Definition: merl.h:60
Definition: ndf_sampler.h:25
bsdfmodel concept
Definition: bsdfmodel.h:33
config concept
Definition: config.h:31
bsdfmodel contract
Predefined exceptions for common errors.
Defines additional helper methods for RGB colors.
The classic diffuse Lambertian BSDF model.
Macros for checking if a class meets a concept.
#define BBM_CHECK_CONCEPT(CONCEPTNAME, CLASSNAME,...)
Check a class for a concept with bbm::concepts::archetypes in the namespace.
Definition: macro.h:35
Linearize the sphere of in-out directions according to the encoding used in the MERL BRDF database.
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
size_t size(T &&t)
Definition: iterator_util.h:22
std::string toString(const T &)
toString alias
Definition: stringconvert.h:594
constexpr auto is_set(const FLAGNAME &a, const FLAG &flag)
Check if all in 'flag' are also set in 'a'; compatible with packet types.
Definition: flags.h:100
decltype(auto) value(T &&t)
return the value of an attribute, or if not an attribute the object
Definition: attribute_value.h:20
unit_t
Light Unit.
Definition: unit.h:21
Forward declaration of bbm::arg.
Definition: arg.h:27
Replaces a(n isotrpic) BSDF model's importance sampling with a data-driven NDF based sampler.
Methods for handling spherical coordinates.
Forward declaration.
Definition: args.h:248
The classic diffuse Lambertian BSDF model.
Definition: lambertian.h:24
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: lambertian.h:76
Value pdf(const Vec3d &in, const Vec3d &out, BsdfFlag component=bsdf_flag::All, unit_t=unit_t::Radiance, Mask mask=true) const
Compute the pdf given an in and out direction.
Definition: lambertian.h:115
Definition: merl_linearizer.h:23
Definition: string_literal.h:16