Loading...
Searching...
No Matches
ashikhminshirleyfull.h
Go to the documentation of this file.
1#ifndef _BBM_ASHIKHMIN_SHIRLEY_FULL_H_
2#define _BBM_ASHIKHMIN_SHIRLEY_FULL_H_
3
6
7/************************************************************************/
8/*! \file ashikhminshirley.h
9
10 \brief Implements the full BSDF (diffuse+specular component) from: "An
11 anisotropic phong BRDF model" [Ashikhmin and Shirley 2000]:
12 https://doi.org/10.1080/10867651.2000.10487522
13
14************************************************************************/
15
16namespace bbm {
17
18 /**********************************************************************/
19 /*! \brief the Anisotropic Phong BSSF model by Ashikhmin and Shirley. This
20 implements the combined diffuse+specular component of the model. The
21 combined model is implemented as a single model due to the dependence of
22 the diffuse term on the specular fresnel reflectance.
23
24 \tparam CONF = bbm configuration
25 \tparam Fresnel = fresnel implementation (requires concepts::Fresnel); default = fresnel::schlick<Config, ior::reflectance<Spectrum>>
26 \tparam Symmetry = pass symmetry_v (Default: symmetry_v::Anisotropic)
27 \tparam NAME = name of the BSDF model (Default: 'AshikhminShirleyFull')
28
29 Implements: concepts::bsdfmodel
30 **********************************************************************/
31 template<typename CONF,
32 typename Fresnel = fresnel::schlick<CONF, ior::reflectance<Spectrum_t<CONF>>>,
34 string_literal NAME="AshikhminShirleyFull"
35 > requires concepts::config<CONF> && concepts::fresnel<Fresnel> && concepts::matching_config<CONF, Fresnel>
36 struct ashikhminshirleyfull : public ashikhminshirley<CONF, Fresnel, Symmetry>
37 {
40 public:
42 static constexpr string_literal name = NAME;
44
45 /********************************************************************/
46 /*! \brief Evaluate the BSDF for a given in and out direction
47
48 \param in = incident direction
49 \param out = outgoing direction
50 \param component = which reflectance component to eval
51 \param unit = unit of computation (ignored)
52 \param mask = masking of lanes (e.g., for Packet eval)
53 \returns Evaluation of the BSDF per spectrum.
54 *********************************************************************/
55 Spectrum eval(const Vec3d& in, const Vec3d& out, BsdfFlag component=bsdf_flag::All, unit_t unit=unit_t::Radiance, Mask mask=true) const
56 {
57 // above surface?
58 mask &= (vec::z(in) > 0) && (vec::z(out) > 0);
59
60 // Quick exit if mask is all negative
61 if(bbm::none(mask)) return Spectrum(0);
62
63 // evaluate the specular component
64 Spectrum spec = base::eval(in, out, component, unit, mask);
65
66 // Quick exit if no diffuse requested
67 mask &= is_set(component, bsdf_flag::Diffuse);
68 if(bbm::none(mask)) return spec;
69
70 // evaluate the diffuse component
71 Value scale = bbm::hprod( Scalar(1.0) - bbm::pow(Scalar(1.0) - 0.5*Vec2d(vec::z(in), vec::z(out)), 5.0) );
72 Value normalization = 28.0 / (23.0 * Constants::Pi());
73
74 // Done.
75 return bbm::select(mask, (normalization * scale * diffuseReflectance * (Scalar(1.0) - base::fresnelReflectance)) + spec, spec);
76 }
77
78
79 /********************************************************************/
80 /*! \brief Sample the BSDF given a direction and two random variables.
81
82 \param out = outgoing direction
83 \param xi = two random variables stored in a Vec2d
84 \param component = which reflectance component to sample
85 \param unit = unit of computation (ignored)
86 \param mask = masking of lanes.
87 \returns A bsdfSample containing the sampled direction and the corresponding pdf.
88 *********************************************************************/
89 BsdfSample sample(const Vec3d& out, const Vec2d& xi, BsdfFlag component=bsdf_flag::All, unit_t unit=unit_t::Radiance, Mask mask=true) const
90 {
91 BsdfSample sample = {0,0,bsdf_flag::None};
92
93 // Quick exit if only one component is selected
94 if( bbm::none(mask && is_set(component, bsdf_flag::Diffuse)) ) return base::sample(out, xi, component, unit, mask);
95 if( bbm::none(mask && is_set(component, bsdf_flag::Specular)) ) return lambertian<Config>().sample(out, xi, component, unit, mask);
96
97 // determine weighting
98 Value spec_albedo = bbm::hsum( base::fresnelReflectance );
99 Value diff_albedo = bbm::hsum( diffuseReflectance ) * (Scalar(1.0) - spec_albedo);
100 Value diff_weight = diff_albedo / (diff_albedo + spec_albedo);
101 Value spec_weight = Scalar(1.0) - diff_weight;
102
103 // sample specular
104 Value xi0_spec = bbm::select( spec_weight > Constants::Epsilon(), xi[0] / spec_weight, 0.0);
105 BsdfSample spec_sample = base::sample(out, Vec2d(xi0_spec, xi[1]), component, unit, mask);
106
107 // sample diffuse (cf. lambertian)
108 Value xi0_diff = bbm::select(diff_weight > Constants::Epsilon(), (xi[0] - spec_weight) / diff_weight, 0.0);
109 BsdfSample diff_sample = lambertian<Config>().sample(out, Vec2d(xi0_diff, xi[1]), component, unit, mask);
110
111 // combine
112 sample = bbm::select( xi[0] <= spec_weight, spec_sample, diff_sample );
113 sample.pdf = spec_weight * spec_sample.pdf + diff_weight * diff_sample.pdf;
114
115 // Done.
116 return sample;
117 }
118
119 /********************************************************************/
120 /*! \brief Compute the pdf given an in and out direction
121
122 \param in = the incoming (sampled) direction
123 \param out = the outgoing (given) direction
124 \param component = which reflectance component was sampled
125 \param unit = unit of computation (ignored)
126 \param mask = masking of lanes
127 \returns the PDF that the incoming direction would be sampled given the outgoing direction.
128 ***********************************************************************/
129 Value pdf(const Vec3d& in, const Vec3d& out, BsdfFlag component=bsdf_flag::All, unit_t unit=unit_t::Radiance, Mask mask=true) const
130 {
131 // Quick bailout
132 if( bbm::none(mask && is_set(component, bsdf_flag::Diffuse)) ) return base::pdf(in, out, component, unit, mask);
133 if( bbm::none(mask && is_set(component, bsdf_flag::Specular)) ) return lambertian<Config>().pdf(in, out, component, unit, mask);
134
135 // determine weighting
136 Value spec_albedo = bbm::hsum( base::fresnelReflectance );
137 Value diff_albedo = bbm::hsum( diffuseReflectance ) * (1.0 - spec_albedo);
138 Value diff_weight = bbm::select( diff_albedo > Constants::Epsilon(), diff_albedo / (diff_albedo + spec_albedo), 0);
139 Value spec_weight = 1.0 - diff_weight;
140
141 // get pdfs
142 Value spec_pdf = base::pdf(in, out, component, unit, mask);
143 Value diff_pdf = lambertian<Config>().pdf(in, out, component, unit, mask);
144
145 // Done.
146 return (spec_weight*spec_pdf + diff_weight*diff_pdf);
147 }
148
149
150 /*******************************************************************/
151 /*! \brief Return the (approximate) reflectance of the BSDF
152
153 \param out = the outgoing direction
154 \param component = which reflectance component to eval
155 \param unit = unit of computation (ignored)
156 \param mask = masking of lanes
157 \returns the approximate reflectance of the BSDF for a given direction
158 ********************************************************************/
159 Spectrum reflectance(const Vec3d& out, BsdfFlag component=bsdf_flag::All, unit_t unit=unit_t::Radiance, Mask mask=true) const
160 {
161 // check 'out' lies above the horizon
162 mask &= (vec::z(out) > 0);
163
164 // Quick exit if mask all negative
165 if(bbm::none(mask)) return 0;
166
167 // eval specular reflectance
168 Spectrum spec = base::reflectance(out, component, unit, mask);
169
170 // Quick exit if no diffuse is requested
171 mask &= is_set(component, bsdf_flag::Diffuse);
172 if(bbm::none(mask)) return spec;
173
174 // Compute diffuse reflectance
175 Spectrum diff = diffuseReflectance * (Scalar(1.0) - base::fresnelReflectance);
176
177 // Done
178 return bbm::select(mask, diff+spec, spec);
179 }
180
181 /////////////////////////
182 //! @{ Class Attributes
183 /////////////////////////
185
187 //! @}
188
189 //! \brief Default constructor
191 };
192
194
195} // end bbm namespace
196
197
198#endif /* _BBM_ASHIKHMIN_SHIRLEY_FULL_H_ */
199
Implements the specular component from: "An anisotropic phong BRDF model" [Ashikhmin and Shirley 2000...
#define BBM_EXPORT_BSDFMODEL(BsdfModel)
Definition: bbm_fromstring.h:49
bsdfmodel concept
Definition: bsdfmodel.h:33
The classic diffuse Lambertian BSDF model.
#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) z(bbm::vec3d< T > &v)
Definition: vec.h:26
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
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
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
the Anisotropic Phong BSSF model by Ashikhmin and Shirley. This implements the combined diffuse+specu...
Definition: ashikhminshirleyfull.h:37
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: ashikhminshirleyfull.h:89
BBM_BSDF_FORWARD
Definition: ashikhminshirleyfull.h:43
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: ashikhminshirleyfull.h:129
BBM_ATTRIBUTES(diffuseReflectance)
Spectrum eval(const Vec3d &in, const Vec3d &out, BsdfFlag component=bsdf_flag::All, unit_t unit=unit_t::Radiance, Mask mask=true) const
Evaluate the BSDF for a given in and out direction.
Definition: ashikhminshirleyfull.h:55
Spectrum reflectance(const Vec3d &out, BsdfFlag component=bsdf_flag::All, unit_t unit=unit_t::Radiance, Mask mask=true) const
Return the (approximate) reflectance of the BSDF.
Definition: ashikhminshirleyfull.h:159
static constexpr string_literal name
Definition: ashikhminshirleyfull.h:42
BBM_DEFAULT_CONSTRUCTOR(ashikhminshirleyfull)
Default constructor.
Definition: ashikhminshirleyfull.h:190
diffuse_scale< Spectrum > diffuseReflectance
Class Attributes.
Definition: ashikhminshirleyfull.h:184
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: string_literal.h:16