Loading...
Searching...
No Matches
ward.h
Go to the documentation of this file.
1#ifndef _BBM_WARD_H_
2#define _BBM_WARD_H_
3
4#include "bbm/bsdfmodel.h"
5
6/************************************************************************/
7/*! \file ward.h
8
9 \brief Implements: "Measuring and modeling anisotropic reflection" [Ward
10 1992]: https://doi.org/10.1145/142920.134078 following the notes from
11 Bruce Walter: https://www.graphics.cornell.edu/~bjw/wardnotes.pdf
12
13*************************************************************************/
14
15namespace bbm {
16
17 /**********************************************************************/
18 /*! \brief The anisotropic Ward BSDF model.
19
20 \tparam CONF = bbm configuration
21 \tparam Symmetry = isotropic or anisotropic (default: symmetry_v::anisotropic)
22 \tparam NAME = name of the BSDF model (Default: 'Ward')
23
24 Implements: concepts::bsdfmodel
25 **********************************************************************/
26 template<typename CONF, symmetry_v Symmetry = symmetry_v::Anisotropic, string_literal NAME="Ward"> requires concepts::config<CONF>
27 class ward
28 {
29 public:
31 static constexpr string_literal name = NAME;
33
34 /********************************************************************/
35 /*! \brief Evaluate the BSDF for a given in and out direction
36
37 \param in = incident direction
38 \param out = outgoing direction
39 \param component = which reflectance component to eval
40 \param unit = unit of computation (ignored)
41 \param mask = masking of lanes (e.g., for Packet eval)
42 \returns Evaluation of the BSDF per spectrum.
43 *********************************************************************/
44 Spectrum eval(const Vec3d& in, const Vec3d& out, BsdfFlag component=bsdf_flag::All, unit_t /*unit*/=unit_t::Radiance, Mask mask=true) const
45 {
46 // specular?
47 mask &= is_set(component, bsdf_flag::Specular);
48
49 // above surface?
50 mask &= (vec::z(in) >= 0) && (vec::z(out) >= 0);
51
52 // Quick exit if mask is all negative
53 if(bbm::none(mask)) return Spectrum(0);
54
55 // Evaluate BRDF
56 Vec2d r(roughness); // copy anisotropic | map isotropic to Vec2d.
57 Vec3d H = in + out;
58
59 Value normalizationFactor = Constants::Pi(4) * bbm::sqrt( vec::z(in) * vec::z(out) ) * vec::x(r) * vec::y(r);
60 Value exponent = bbm::squared_norm(vec::xy(H) / r) / bbm::pow(vec::z(H), 2);
61
62 Spectrum result = albedo;
63 result *= bbm::exp(-exponent) / normalizationFactor;
64
65 // Done.
66 return bbm::select(mask, result, 0);
67 }
68
69 /********************************************************************/
70 /*! \brief Sample the BSDF given a direction and two random variables.
71
72 \param out = outgoing direction
73 \param xi = two random variables stored in a Vec2d
74 \param component = which reflectance component to sample
75 \param unit = unit of computation (ignored)
76 \param mask = masking of lanes.
77 \returns A bsdfSample containing the sampled direction and the corresponding pdf.
78 *********************************************************************/
79 BsdfSample sample(const Vec3d& out, const Vec2d& xi, BsdfFlag component=bsdf_flag::All, unit_t unit=unit_t::Radiance, Mask mask=true) const
80 {
81 BsdfSample sample = {0,0,bsdf_flag::None};
82
83 // specular?
84 mask &= is_set(component, bsdf_flag::Specular);
85
86 // random variable in [0...1]?
87 mask &= (xi[0] >= 0) && (xi[1] >= 0) && (xi[0] <= 1) && (xi[1] <= 1);
88
89 // Quick exit if mask is all negative
90 if(bbm::none(mask)) return sample;
91
92 // Compute sin and cos of halfway::phi
93 Vec2d r(roughness);
94 Vec2d csp = bbm::normalize(bbm::cossin(Constants::Pi(2) * xi[0]) * r);
95
96 // Compute sin and cos of halfway::theta
97 Value cosTheta = bbm::rsqrt( 1.0 - (bbm::log(xi[1]) / bbm::squared_norm(csp / r)) );
98 Value sinTheta = bbm::safe_sqrt(1.0 - cosTheta*cosTheta);
99
100 // Convert from halfway to the canonical domain
101 Vec3d halfway = vec::expand(csp*sinTheta, cosTheta);
102 sample.direction = bbm::select(mask, reflect(out, halfway), 0);
103 sample.pdf = pdf(sample.direction, out, component, unit, mask);
104 sample.flag = bbm::select(mask, BsdfFlag(bsdf_flag::Specular), BsdfFlag(bsdf_flag::None));
105
106 // Done.
107 return sample;
108 }
109
110 /********************************************************************/
111 /*! \brief Compute the pdf given an in and out direction
112
113 \param in = the incoming (sampled) direction
114 \param out = the outgoing (given) direction
115 \param component = which reflectance component was sampled
116 \param unit = unit of computation (ignored)
117 \param mask = masking of lanes
118 \returns the PDF that the incoming direction would be sampled given the outgoing direction.
119 ***********************************************************************/
120 Value pdf(const Vec3d& in, const Vec3d& out, BsdfFlag component=bsdf_flag::All, unit_t /*unit*/=unit_t::Radiance, Mask mask=true) const
121 {
122 // specular?
123 mask &= is_set(component, bsdf_flag::Specular);
124
125 // above surface?
126 mask &= (vec::z(in) >= 0) && (vec::z(out) >= 0);
127
128 // Quick bailout
129 if(bbm::none(mask)) return 0;
130
131 // compute PDF:
132 Vec2d r(roughness);
133 Vec3d h = halfway(in, out);
134
135 Value normalizationFactor = Constants::Pi(4) * vec::x(r) * vec::y(r) * bbm::dot(in, h) * bbm::pow( spherical::cosTheta(h), 3);
136 Value exponent = bbm::squared_norm(vec::xy(h) / r) / bbm::pow(vec::z(h), 2);
137 Value pdf = bbm::exp(-exponent) / normalizationFactor;
138
139 // Done.
140 return bbm::select(mask, pdf, 0);
141 }
142
143 /*******************************************************************/
144 /*! \brief Return the (approximate) hemispherical reflectance of the BSDF
145
146 \param out = the outgoing direction
147 \param component = which reflectance component to eval
148 \param unit = unit of computation (ignored)
149 \param mask = masking of lanes
150 \returns the approximate hemispherical reflectance of the BSDF for a given direction
151 ********************************************************************/
152 Spectrum reflectance(const Vec3d& /*out*/, BsdfFlag component=bsdf_flag::All, unit_t /*unit*/=unit_t::Radiance, Mask mask=true) const
153 {
154 return bbm::select(mask & is_set(component, bsdf_flag::Specular), albedo, Spectrum(0));
155 }
156
157 ///////////////////////////////
158 //! @{ \name Class Attributes
159 ///////////////////////////////
162
164 //! @}
165
166 //! \brief Default constructor
168 };
169
171
172} // end bbm namespace
173
174#endif /* _BBM_WARD_H_ */
175
All includes and helpers needed for declaring new bsdfmodels.
#define BBM_EXPORT_BSDFMODEL(BsdfModel)
Definition: bbm_fromstring.h:49
The anisotropic Ward BSDF model.
Definition: ward.h:28
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: ward.h:44
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: ward.h:79
BBM_IMPORT_CONFIG(CONF)
specular_roughness< symmetry_t< Symmetry, Value > > roughness
Definition: ward.h:161
BBM_DEFAULT_CONSTRUCTOR(ward)
Default constructor.
Definition: ward.h:167
BBM_BSDF_FORWARD
Definition: ward.h:32
BBM_ATTRIBUTES(albedo, roughness)
specular_scale< Spectrum > albedo
Definition: ward.h:160
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: ward.h:120
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: ward.h:152
static constexpr string_literal name
Definition: ward.h:31
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
T cosTheta(const vec2d< T > &v)
Definition: spherical.h:109
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) x(bbm::vec3d< T > &v)
Definition: vec.h:20
constexpr const vec2d< T > xy(const vec3d< T > &v)
Definition: vec.h:47
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
Definition: string_literal.h:16