Loading...
Searching...
No Matches
ashikhminshirley.h
Go to the documentation of this file.
1#ifndef _BBM_ASHIKHMIN_SHIRLEY_H_
2#define _BBM_ASHIKHMIN_SHIRLEY_H_
3
4#include "bbm/bsdfmodel.h"
5
6/************************************************************************/
7/*! \file ashikhminshirley.h
8
9 \brief Implements the specular component from: "An anisotropic phong BRDF
10 model" [Ashikhmin and Shirley 2000]:
11 https://doi.org/10.1080/10867651.2000.10487522
12
13************************************************************************/
14
15namespace bbm {
16
17 /**********************************************************************/
18 /*! \brief the Anisotropic Phong BSSF model by Ashikhmin and Shirley. This
19 implements the specular component of the model.
20
21 \tparam CONF = bbm configuration
22
23 \tparam Fresnel = fresnel implementation (requires concepts::Fresnel); default = fresnel::schlick<Config, ior::reflectance<Spectrum>>
24 \tparam Symmetry = pass symmetry_v (Default: symmetry_v::Anisotropic)
25 \tparam NAME = name of the BSDF model (Default: 'AshikhminShirley')
26
27 Implements: concepts::bsdfmodel
28 **********************************************************************/
29 template<typename CONF,
30 typename Fresnel = fresnel::schlick<CONF, ior::reflectance<Spectrum_t<CONF>>>,
32 string_literal NAME="AshikhminShirley"
33 > requires concepts::config<CONF> && concepts::fresnel<Fresnel> && concepts::matching_config<CONF, Fresnel>
35 {
36 public:
38 static constexpr string_literal name = NAME;
40
41 /********************************************************************/
42 /*! \brief Evaluate the BSDF for a given in and out direction
43
44 \param in = incident direction
45 \param out = outgoing direction
46 \param component = which reflectance component to eval
47 \param unit = unit of computation (ignored)
48 \param mask = masking of lanes (e.g., for Packet eval)
49 \returns Evaluation of the BSDF per spectrum.
50 *********************************************************************/
51 Spectrum eval(const Vec3d& in, const Vec3d& out, BsdfFlag component=bsdf_flag::All, unit_t /*unit*/=unit_t::Radiance, Mask mask=true) const
52 {
53 // specular?
54 mask &= is_set(component, bsdf_flag::Specular);
55
56 // above surface?
57 mask &= (vec::z(in) > 0) && (vec::z(out) > 0);
58
59 // Quick exit if mask is all negative
60 if(bbm::none(mask)) return Spectrum(0);
61
62 // evaluate bsdf
63 Vec3d h = halfway(in, out);
64 Value h_dot_in = bbm::dot(h, in);
65 Value denominator = h_dot_in * bbm::max( vec::z(in), vec::z(out) );
66 Spectrum F = Fresnel::eval( fresnelReflectance, h_dot_in, mask );
67
68 Value exponent, normalization;
69 if constexpr (is_set(Symmetry, symmetry_v::Anisotropic)) // anisotropic
70 {
71 exponent = bbm::select( vec::z(h) < 1 - Constants::Epsilon(), ((vec::u(sharpness) * bbm::pow(vec::x(h), 2)) + (vec::v(sharpness) * bbm::pow(vec::y(h), 2))) / (1 - bbm::pow(vec::z(h), 2)), 0);
72 normalization = bbm::sqrt( (vec::u(sharpness) + 1) * (vec::v(sharpness) + 1) ) / Constants::Pi(8);
73 }
74 else // isotropic
75 {
76 exponent = sharpness;
77 normalization = (sharpness + 1) / Constants::Pi(8);
78 }
79
80 // Done.
81 return bbm::select(mask, normalization * bbm::pow( vec::z(h), exponent ) * F / denominator, 0);
82 }
83
84
85 /********************************************************************/
86 /*! \brief Sample the BSDF given a direction and two random variables.
87
88 \param out = outgoing direction
89 \param xi = two random variables stored in a Vec2d
90 \param component = which reflectance component to sample
91 \param unit = unit of computation (ignored)
92 \param mask = masking of lanes.
93 \returns A bsdfSample containing the sampled direction and the corresponding pdf.
94 *********************************************************************/
95 BsdfSample sample(const Vec3d& out, const Vec2d& xi, BsdfFlag component=bsdf_flag::All, unit_t unit=unit_t::Radiance, Mask mask=true) const
96 {
97 BsdfSample sample = {0,0,bsdf_flag::None};
98
99 // specular?
100 mask &= is_set(component, bsdf_flag::Specular);
101
102 // random variable in [0...1]?
103 mask &= (xi[0] >= 0) && (xi[1] >= 0) && (xi[0] <= 1) && (xi[1] <= 1);
104
105 // Quick exit if mask all negative
106 if(bbm::none(mask)) return sample;
107
108 // Sample halfway
109 Vec2d csp;
110 Value cosTheta;
111
112 if constexpr (is_set(Symmetry, symmetry_v::Anisotropic)) // anisotrpic
113 {
114 // phi
115 Value phi = bbm::atan( bbm::sqrt( (vec::u(sharpness) + 1.0) / (vec::v(sharpness) + 1.0) ) * bbm::tan(xi[0] * Constants::Pi(2)) );
116
117 // make sure phi lies in same quadrant as 2PI xi[0]
118 phi = bbm::select( (xi[0] > 0.25) && (xi[0] < 0.75), phi + Constants::Pi(), phi );
119
120 // cosine theta
121 csp = bbm::cossin(phi);
122 cosTheta = bbm::pow(xi[1], 1.0 / ((vec::u(sharpness) * bbm::pow(vec::u(csp), 2)) + (vec::v(sharpness) * bbm::pow(vec::v(csp), 2)) + 1.0) );
123 }
124 else // isotropic
125 {
126 csp = bbm::cossin(xi[0] * Constants::Pi(2));
127 cosTheta = bbm::pow(xi[1], 1.0 / (sharpness + 1.0));
128 }
129
130 Value sinTheta = bbm::safe_sqrt(1.0 - cosTheta*cosTheta);
131 Vec3d h = vec::expand(csp * sinTheta, cosTheta);
132
133 // Convert to canonical domain
134 sample.direction = bbm::select(mask, reflect(out, h), 0);
135 sample.pdf = pdf(sample.direction, out, component, unit, mask);
136 sample.flag = bbm::select(mask, BsdfFlag(bsdf_flag::Specular), BsdfFlag(bsdf_flag::None));
137
138 // Done.
139 return sample;
140 }
141
142 /********************************************************************/
143 /*! \brief Compute the pdf given an in and out direction
144
145 \param in = the incoming (sampled) direction
146 \param out = the outgoing (given) direction
147 \param component = which reflectance component was sampled
148 \param unit = unit of computation (ignored)
149 \param mask = masking of lanes
150 \returns the PDF that the incoming direction would be sampled given the outgoing direction.
151 ***********************************************************************/
152 Value pdf(const Vec3d& in, const Vec3d& out, BsdfFlag component=bsdf_flag::All, unit_t /*unit*/=unit_t::Radiance, Mask mask=true) const
153 {
154 // specular?
155 mask &= is_set(component, bsdf_flag::Specular);
156
157 // above surface?
158 mask &= (vec::z(in) >= 0) && (vec::z(out) >= 0);
159
160 // Quick bailout
161 if(bbm::none(mask)) return 0;
162
163 // Compute PDF
164 auto h = halfway(in, out);
165 auto h_dot_in = bbm::dot(h, in);
166
167 Value exponent, normalization;
168 if constexpr (is_set(Symmetry, symmetry_v::Anisotropic)) // anisotrpic
169 {
170 exponent = bbm::select( vec::z(h) < 1.0-Constants::Epsilon(), ((vec::u(sharpness) * bbm::pow(vec::x(h), 2.0)) + (vec::v(sharpness) * bbm::pow(vec::y(h), 2.0))) / (1.0 - bbm::pow(vec::z(h), 2)), 0);
171 normalization = bbm::sqrt( (vec::u(sharpness) + 1) * (vec::v(sharpness) + 1) ) / Constants::Pi(2);
172 }
173 else // isotropic
174 {
175 exponent = sharpness;
176 normalization = (sharpness + 1.0) / Constants::Pi(2);
177 }
178
179 auto pdf = normalization * bbm::pow(vec::z(h), exponent) / (4.0 * h_dot_in);
180
181 // Done.
182 return bbm::select(mask, pdf, 0);
183 }
184
185
186 /*******************************************************************/
187 /*! \brief Return the (approximate) reflectance of the BSDF
188
189 \param out = the outgoing direction
190 \param component = which reflectance component to eval
191 \param unit = unit of computation (ignored)
192 \param mask = masking of lanes
193 \returns the approximate reflectance of the BSDF for a given direction
194 ********************************************************************/
195 Spectrum reflectance(const Vec3d& out, BsdfFlag component=bsdf_flag::All, unit_t /*unit*/=unit_t::Radiance, Mask mask=true) const
196 {
197 // specular?
198 mask &= is_set(component, bsdf_flag::Specular);
199
200 // check 'out' lies above the horizon
201 mask &= (vec::z(out) > 0);
202
203 // Quick exit if mask all negative
204 if(bbm::none(mask)) return 0;
205
206 // Approximate as perfect mirror
207 return Fresnel::eval( fresnelReflectance.value(), vec::z(out), mask );
208 }
209
210 /////////////////////////
211 //! @{ Class Attributes
212 /////////////////////////
215
217 //! @}
218
219 //! \brief Default constructor
221 };
222
224
225} // end bbm namespace
226
227
228#endif /* _BBM_ASHIKHMIN_SHIRLEY_H_ */
229
All includes and helpers needed for declaring new bsdfmodels.
#define BBM_EXPORT_BSDFMODEL(BsdfModel)
Definition: bbm_fromstring.h:49
bsdfmodel concept
Definition: bsdfmodel.h:33
#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) u(bbm::vec2d< T > &v)
Definition: vec.h:37
constexpr const vec3d< T > expand(const vec2d< T > &v, V &&a)
Definition: vec.h:55
constexpr decltype(auto) y(bbm::vec3d< T > &v)
Definition: vec.h:23
constexpr decltype(auto) z(bbm::vec3d< T > &v)
Definition: vec.h:26
constexpr decltype(auto) v(bbm::vec2d< T > &v)
Definition: vec.h:40
constexpr decltype(auto) x(bbm::vec3d< T > &v)
Definition: vec.h:20
Definition: aggregatebsdf.h:29
symmetry_v
symmetry variants.
Definition: bsdf_symmetry.h:19
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
the Anisotropic Phong BSSF model by Ashikhmin and Shirley. This implements the specular component of ...
Definition: ashikhminshirley.h:35
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 and out direction.
Definition: ashikhminshirley.h:51
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 BSDF given a direction and two random variables.
Definition: ashikhminshirley.h:95
fresnel_parameter< typename Fresnel::parameter_type > fresnelReflectance
Class Attributes.
Definition: ashikhminshirley.h:213
BBM_DEFAULT_CONSTRUCTOR(ashikhminshirley)
Default constructor.
Definition: ashikhminshirley.h:220
BBM_BSDF_FORWARD
Definition: ashikhminshirley.h:39
specular_sharpness< symmetry_t< Symmetry, Value > > sharpness
Definition: ashikhminshirley.h:214
Spectrum reflectance(const Vec3d &out, BsdfFlag component=bsdf_flag::All, unit_t=unit_t::Radiance, Mask mask=true) const
Return the (approximate) reflectance of the BSDF.
Definition: ashikhminshirley.h:195
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: ashikhminshirley.h:152
static constexpr string_literal name
Definition: ashikhminshirley.h:38
BBM_ATTRIBUTES(fresnelReflectance, sharpness)
Definition: string_literal.h:16