Loading...
Searching...
No Matches
epd.h
Go to the documentation of this file.
1#ifndef _BBM_NDF_EPD_H_
2#define _BBM_NDF_EPD_H_
3
4#include "bbm/ndf.h"
5#include "util/gamma.h"
6#include "util/invgamma.h"
7
10
11/************************************************************************/
12/*! \file epd.h
13
14 \brief The Exponential Power Distribution from "A two-scale microfacet
15 reflectance model combining reflection and diffraction", Holzschuch and
16 Pacanowski [2017]: https://doi.org/10.1145/3072959.3073621
17
18 Implements the EPD Eq. 34-38 & 49-50
19
20*************************************************************************/
21
22namespace bbm {
23 namespace ndf {
24
25 /********************************************************************/
26 /*! \brief EPD variants: compute the noralization on the fly or use precomputed values.
27 ********************************************************************/
29 {
30 Compute,
32 };
33
34 /********************************************************************/
35 /*! \brief Exponential Power Distribution
36
37 \tparam CONF = bbm configuration
38 \tparam NORMALIZATION = use precomputed normalization of compute on the fly (default=epd_normalization::Compute)
39 \tparam NAME = model name (default = "EPD")
40
41 Implements: concepts::ndf
42 *********************************************************************/
43 template<typename CONF,
45 string_literal NAME="EPD"
46 > requires concepts::config<CONF>
47 class epd
48 {
49 public:
51 static constexpr string_literal name = NAME;
52
53 /******************************************************************/
54 /*! \brief Evaluate the NDF
55
56 \param halfway = vector to eval the NDF for
57 \param mask = enable/disbale lanes [default = true]
58 \returns the resulting evaluation of the NDF
59 *******************************************************************/
60 Value eval(const Vec3d& halfway, Mask mask=true) const
61 {
62 // above surface?
63 mask &= (vec::z(halfway) > 0);
64
65 // Quick exit
66 if(bbm::none(mask)) return 0;
67
68 // eval NDF (eq. 34-35)
69 Value cosTheta2 = spherical::cosTheta2(halfway);
70 Value tanTheta2 = (1 - cosTheta2) / cosTheta2;
71 Value beta2 = beta*beta;
72 Value normalization = compute_normalization();
73 Value D = normalization * bbm::exp( -bbm::pow( tanTheta2 / beta2, p ) ) / (cosTheta2*cosTheta2);
74
75 return bbm::select(mask, D, 0);
76 }
77
78
79 /******************************************************************/
80 /*! \brief Sample the NDF
81
82 \param view = view direction (ignored)
83 \param xi = 2D uniform random variables in [0..1] range
84 \param Mask = enable/disbale lanes
85 \returns A sampled microfacet normal.
86 *******************************************************************/
87 Vec3d sample(const Vec3d& /*view*/, const Vec2d& xi, Mask mask=true) const
88 {
89 // check valid xi
90 mask &= (xi[0] >= 0) && (xi[1] >= 0) && (xi[0] <= 1) && (xi[1] <= 1);
91
92 // quick exit
93 if(bbm::none(mask)) return 0;
94
95 // Sample (Eq. 49-50)
96 Vec2d csp = bbm::cossin( Constants::Pi(2) * xi[0] );
97 Value inv_p = bbm::rcp(p);
98 Value tanTheta2 = beta * beta * bbm::pow( bbm::gamma_q_inv(inv_p, xi[1]), inv_p );
99 Value cosTheta = bbm::rsqrt(1.0 + tanTheta2);
100 Value sinTheta = bbm::safe_sqrt(1.0 - cosTheta*cosTheta);
101
102 // Done.
103 return bbm::select(mask, vec::expand(csp*sinTheta, cosTheta), 0.0);
104 };
105
106
107 /******************************************************************/
108 /*! \brief PDF of sampling the NDF
109
110 \param view = view direction (ignored)
111 \param m = sampled microfacet normal
112 \param mask = enable/disable lanes [default = true]
113 \returns the PDF of sampling 'm' using the sample method.
114 *******************************************************************/
115 Value pdf(const Vec3d& /*view*/, const Vec3d& m, Mask mask=true) const
116 {
117 // m above surface?
118 mask &= (vec::z(m) > 0);
119
120 // quick bail out
121 if(bbm::none(mask)) return 0;
122
123 // eval PDF
124 Value pdf = eval(m, mask) * spherical::cosTheta(m);
125
126 // ignore negative values (round off errors)
127 mask &= (pdf > 0);
128
129 // Done.
130 return bbm::select(mask, pdf, 0);
131 }
132
133
134 /******************************************************************/
135 /*! \brief Monodirectional shadowing and masking term
136
137 \param v = incident/outgoing vector
138 \param m = microfacet normal
139 \param mask = enable/disable lanes
140 \returns the monodirectional shadowing and masking attentuation factor
141 ****************************************************************/
142 Value G1(const Vec3d& v, const Vec3d& m, Mask mask=true) const
143 {
144 // check (dot(v,m) / dot(v,n)) > 0.
145 mask &= (vec::z(v) > 0) && (bbm::dot(v, m) > 0);
146
147 // Quick exit
148 if(bbm::none(mask)) return 0;
149
150 // Lookup precomputed value (rely on clamping of the interpolate method if outside range)
151 return bbm::get<"value">(precomputed::holzschuchpacanowski::G1.interpolate<Value>(p, spherical::tanTheta(v)*beta));
152 }
153
154 /******************************************************************/
155 /*! \brief EPD normalization
156 ******************************************************************/
157 inline Value compute_normalization(void) const
158 {
159 Value result(0);
160
161 // Quick bailout
162 Mask mask = p > Constants::Epsilon();
163 if(bbm::none(mask)) return result;
164
165 // compute on the fly
166 if constexpr (NORMALIZATION == epd_normalization::Compute) result = bbm::select(mask, p * Constants::InvPi() * bbm::rcp( bbm::tgamma(bbm::rcp(p)) ), 0.0);
167
168 // use precomputed
169 else result = bbm::get<"value">(precomputed::holzschuchpacanowski::distributionNormalization.interpolate<Value>(p));
170
171 // include roughness
172 result /= beta*beta;
173
174 // Done.
175 return result;
176 }
177
178 ///////////////////////////////
179 //! @{ \name Class Attributes
180 ///////////////////////////////
181 bsdf_parameter<Value, bsdf_attr::SpecularParameter, 0.003, 0.5, 0.0> beta; // roughness
182 bsdf_parameter<Value, bsdf_attr::SpecularParameter, 0.2, 5.0, 0.0> p; // kurtosis
183
185 //! @}
186
187 //! \brief Default constructor
189 };
190
192
193 } // end ndf namespace
194} // end bbm namespace
195
196#endif /* _BBM_NDF_EPD_H_ */
All includes and helpers needed for declaring new ndfs.
Exponential Power Distribution.
Definition: epd.h:48
Value G1(const Vec3d &v, const Vec3d &m, Mask mask=true) const
Monodirectional shadowing and masking term.
Definition: epd.h:142
BBM_ATTRIBUTES(beta, p)
BBM_DEFAULT_CONSTRUCTOR(epd)
Default constructor.
Definition: epd.h:188
bsdf_parameter< Value, bsdf_attr::SpecularParameter, 0.003, 0.5, 0.0 > beta
Definition: epd.h:181
BBM_IMPORT_CONFIG(CONF)
Value pdf(const Vec3d &, const Vec3d &m, Mask mask=true) const
PDF of sampling the NDF.
Definition: epd.h:115
bsdf_parameter< Value, bsdf_attr::SpecularParameter, 0.2, 5.0, 0.0 > p
Definition: epd.h:182
Value eval(const Vec3d &halfway, Mask mask=true) const
Evaluate the NDF.
Definition: epd.h:60
Vec3d sample(const Vec3d &, const Vec2d &xi, Mask mask=true) const
Sample the NDF.
Definition: epd.h:87
Value compute_normalization(void) const
EPD normalization.
Definition: epd.h:157
static constexpr string_literal name
Definition: epd.h:51
config concept
Definition: config.h:31
ndf concept
Definition: ndf.h:29
Packet-type friendly implementation of:
Packet friendly computation of the the inverse of the incomplete gamma functions:
#define BBM_CHECK_CONCEPT(CONCEPTNAME, CLASSNAME,...)
Check a class for a concept with bbm::concepts::archetypes in the namespace.
Definition: macro.h:35
epd_normalization
EPD variants: compute the noralization on the fly or use precomputed values.
Definition: epd.h:29
static const tab< float, std::array{256}, decltype([](const auto &p) { return p *256.0/5.0;}) > distributionNormalization
Definition: distributionNormalization.h:16
static const tab< float, std::array{100, 1000}, decltype([](const auto &p) { return 5.0/p - 1.0;}), decltype([](const auto &t) { return bbm::exp(-bbm::exp(bbm::log(bbm::rcp(t)) *0.05)) *1000.0 - 1.0;}) > G1
Definition: G1.h:17
T cosTheta(const vec2d< T > &v)
Definition: spherical.h:109
T tanTheta(const vec2d< T > &v)
Definition: spherical.h:177
bbm::value_t< V > cosTheta2(const V &v)
Definition: spherical.h:115
constexpr const vec3d< T > expand(const vec2d< T > &v, V &&a)
Definition: vec.h:55
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
auto gamma_q_inv(const TA &a, const TQ &q)
the inverse of the normalized lower incomplete gamma function
Definition: invgamma.h:447
constexpr decltype(auto) get(T &&src)
Definition: named.h:317
auto tgamma(const TA &a, const TX &x)
Unnormalized incomplete upper gamma function.
Definition: gamma.h:532
Base declaration of attribute; further specialized below.
Definition: attribute.h:26
Definition: string_literal.h:16