Loading...
Searching...
No Matches
microfacet.h
Go to the documentation of this file.
1#ifndef _BBM_MICROFACET_H_
2#define _BBM_MICROFACET_H_
3
4#include "concepts/ndf.h"
6
7#include "bbm/bsdfmodel.h"
8
9/************************************************************************/
10/*! \file microfacet.h
11
12 \brief Microfacet BSDF model following "Microfacet Models for Refraction
13 through Rough Surfaces" [Walter et al. 2007]:
14 http://dx.doi.org/10.2312/EGWR/EGSR07/195-206
15
16 This does not include implementation of Shadowin and Masking functions (G)
17 or of the microfacet distributions (D).
18
19 TODO: include BTDF
20************************************************************************/
21
22namespace bbm {
23
24 /**********************************************************************/
25 /*! \brief Predefined normalization factors
26
27 + Unnormalized = 1.0
28 + Walter = 4.0
29 + Cook = 3.1415...
30 ***********************************************************************/
32 {
33 static constexpr literal Unnormalized = 1.0;
34 static constexpr literal Walter = 4.0;
35 static constexpr literal Cook = constants<double>::Pi();
36 };
37
38 /**********************************************************************/
39 /*! \brief General microfacet BRDF model.
40
41 \tparam NDF = microfacet normal distribution (concepts::ndf && std::default_initializable)
42 \tparam MaskingShadowing = masking and shadowing function (concepts::maskingshadowing)
43 \tparam Fresnel = fresnel implementation (requires concepts::fresnel)
44 \tparam NormalizationFactor = see microfacet_n
45 \tparam NAME = model name
46
47 NDF, MaskingShadowing, and Fresnel must also meet config::matching_config
48
49 Implements: concepts::bsdfmodel
50 ***********************************************************************/
51 template<typename NDF,
52 typename MaskingShadowing,
53 typename Fresnel,
54 auto NormalizationFactor=microfacet_n::Unnormalized,
55 string_literal NAME="microfacet"
58 {
60 static constexpr string_literal name = NAME;
62
63
64 /********************************************************************/
65 /*! \brief Evaluate the BSDF for a given in-out direction pair
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 (ignored)
71 \param mask = masking of lanes (e.g., for Packet eval)
72 \returns Evaluation of the BSDF per spectrum.
73 *********************************************************************/
74 Spectrum eval(const Vec3d& in, const Vec3d& out, BsdfFlag component=bsdf_flag::All, unit_t /*unit*/=unit_t::Radiance, Mask mask=true) const
75 {
76 // specular?
77 mask &= is_set(component, bsdf_flag::Specular);
78
79 // above surface?
80 mask &= ((vec::z(in) > 0.0f) && (vec::z(out) > 0.0f));
81
82 // Quick exit if mask is all negative
83 if(bbm::none(mask)) return Spectrum(0);
84
85 // Halfway vector
86 Vec3d h = halfway(in, out);
87 Value inh = bbm::dot(in, h);
88 Value outh = bbm::dot(out, h);
89
90 // eval NDF
91 auto D = ndf.eval(h, mask);
92
93 // eval shadowing and masking
94 auto G = MaskingShadowing::eval(ndf, in, out, h, mask);
95
96 // compute Fresnel (take average of inh and outh to avoid non-reciprocal differences due to round-off errors).
97 auto F = Fresnel::eval(eta, Value(0.5) * (inh + outh), mask);
98
99 // Done.
100 Spectrum result = D * G * F / NormalizationFactor / (vec::z(in) * vec::z(out));
101 return bbm::select(mask, result, 0);
102 }
103
104
105 /********************************************************************/
106 /*! \brief Sample the microfacet BSDF given a direction and two random variables.
107
108 \param out = outgoing direction
109 \param xi = two random variables stored in a Vec2d
110 \param component = which reflectance component to sample
111 \param unit = unit of computation (ignored)
112 \param mask = masking of lanes.
113 \returns A bsdfSample containing the sampled direction and the corresponding pdf.
114 *********************************************************************/
115 BsdfSample sample(const Vec3d& out, const Vec2d& xi, BsdfFlag component=bsdf_flag::All, unit_t unit=unit_t::Radiance, Mask mask=true) const
116 {
117 BsdfSample sample = {0,0,bsdf_flag::None};
118
119 // specular?
120 mask &= is_set(component, bsdf_flag::Specular);
121
122 // check for valid xi
123 mask &= (xi[0] >= 0) && (xi[1] >= 0) && (xi[0] <= 1) && (xi[1] <= 1);
124
125 // check out lies above the horizon
126 mask &= (vec::z(out) > 0);
127
128 // Quick exit if mask all negative
129 if(bbm::none(mask)) return sample;
130
131 // sample microfacet normal
132 Vec3d normal_m = ndf.sample(out, xi, mask);
133
134 // sample direction == reflection about normal_m
135 sample.direction = bbm::select(mask, reflect(out, normal_m), 0);
136 sample.pdf = pdf(sample.direction, out, component, unit, mask);
137 sample.flag = bbm::select(mask, BsdfFlag(bsdf_flag::Specular), BsdfFlag(bsdf_flag::None));
138
139 // Done.
140 return sample;
141 }
142
143
144 /********************************************************************/
145 /*! \brief Compute the pdf given an in and out direction
146
147 \param in = the incoming (sampled) direction
148 \param out = the outgoing (given) direction
149 \param component = which reflectance component was sampled
150 \param unit = unit of computation (ignored)
151 \param mask = masking of lanes
152 \returns the PDF that the incoming direction would be sampled given the outgoing direction.
153 *******************************************************************/
154 Value pdf(const Vec3d& in, const Vec3d& out, BsdfFlag component=bsdf_flag::All, unit_t /*unit*/=unit_t::Radiance, Mask mask=true) const
155 {
156 // specular?
157 mask &= is_set(component, bsdf_flag::Specular);
158
159 // check if 'out' and 'in' lie above the horizon
160 mask &= (vec::z(out) > 0) && (vec::z(in) > 0);
161
162 // Quick exit if mask is all negative
163 if(bbm::none(mask)) return 0;
164
165 // Halfway (must lie above the horizon)
166 Vec3d h = halfway(in, out);
167 h = bbm::select(vec::z(h) < 0, -h, h);
168
169 // eval PDF: pdf(h) / (4 out . h)
170 auto pdf = ndf.pdf(out, h, mask) / (4.0 * bbm::abs(bbm::dot( out, h )) );
171
172 // Compute PDF
173 return bbm::select(mask, pdf, 0);
174 }
175
176
177 /********************************************************************/
178 /*! \brief Return the (approximate) hemispherical reflectance of the BSDF
179
180 \param out = the outgoing direction
181 \param component = which reflectance component to eval
182 \param unit = unit of computation (ignored)
183 \param mask = masking of lanes
184 \returns the approximate hemispherical reflectance of the BSDF for a given direction
185 ******************************************************************/
186 Spectrum reflectance(const Vec3d& out, BsdfFlag component=bsdf_flag::All, unit_t /*unit*/=unit_t::Radiance, Mask mask=true) const
187 {
188 // specular?
189 mask &= is_set(component, bsdf_flag::Specular);
190
191 // check 'out' lies above the horizon
192 mask &= (vec::z(out) > 0);
193
194 // Quick exit if mask is all negative
195 if(bbm::none(mask)) return 0;
196
197 // Approximate as perfect mirror
198 return Fresnel::eval(eta.value(), vec::z(out), mask) / NormalizationFactor * 4.0;
199 }
200
201 ///////////////////////////////////////////////////////
202 //! @{ \name Class Attributes are copied from the NDF
203 ///////////////////////////////////////////////////////
204 NDF ndf;
206
208 //! @}
209
210 //! \brief Default constructor
212 };
213
215
216} // end bbm namespace
217
218
219#endif /* _BBM_MICROFACET_H_ */
All includes and helpers needed for declaring new bsdfmodels.
bsdfmodel concept
Definition: bsdfmodel.h:33
fresnel concept
Definition: fresnel.h:27
maskingshadowing concept
Definition: maskingshadowing.h:24
matching_config concept
Definition: config.h:63
ndf concept
Definition: ndf.h:29
Joint Masking-Shadowing Functor concept.
Microfacet Normal Distribution contract.
#define BBM_CHECK_CONCEPT(CONCEPTNAME, CLASSNAME,...)
Check a class for a concept with bbm::concepts::archetypes in the namespace.
Definition: macro.h:35
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
vec3d< T > reflect(const vec3d< T > &v, const vec3d< T > &normal)
Reflects a 3D vector.
Definition: vec_transform.h:44
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
unit_t
Light Unit.
Definition: unit.h:21
Base declaration of attribute; further specialized below.
Definition: attribute.h:26
Definition: fresnel.h:48
static constexpr T Pi(T scale=1)
Definition: constants.h:19
Definition: literal.h:16
Predefined normalization factors.
Definition: microfacet.h:32
static constexpr literal Cook
Definition: microfacet.h:35
static constexpr literal Walter
Definition: microfacet.h:34
static constexpr literal Unnormalized
Definition: microfacet.h:33
General microfacet BRDF model.
Definition: microfacet.h:58
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 for a given in-out direction pair.
Definition: microfacet.h:74
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 microfacet BSDF given a direction and two random variables.
Definition: microfacet.h:115
BBM_BSDF_FORWARD
Definition: microfacet.h:61
BBM_ATTRIBUTES(reflection::attributes(ndf), eta)
BBM_DEFAULT_CONSTRUCTOR(microfacet)
Default constructor.
Definition: microfacet.h:211
Spectrum reflectance(const Vec3d &out, BsdfFlag component=bsdf_flag::All, unit_t=unit_t::Radiance, Mask mask=true) const
Return the (approximate) hemispherical reflectance of the BSDF.
Definition: microfacet.h:186
fresnel_parameter< typename std::decay_t< Fresnel >::parameter_type > eta
Definition: microfacet.h:205
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: microfacet.h:154
NDF ndf
Definition: microfacet.h:204
static constexpr string_literal name
Definition: microfacet.h:60
Definition: string_literal.h:16