Loading...
Searching...
No Matches
lafortune.h
Go to the documentation of this file.
1#ifndef _BBM_LAFORTUNE_H_
2#define _BBM_LAFORTUNE_H_
3
4#include "bbm/bsdfmodel.h"
5
6/************************************************************************/
7/*! \file lafortune.h
8
9 \brief Implements: "Non-Linear Approximation of Reflectance Functions"
10 [Lafortune 1997]: https://doi.org/10.1145/258734.258801
11
12*************************************************************************/
13
14namespace bbm {
15
16 /**********************************************************************/
17 /*! \brief The Lafortune BRDF model. This implements the model in Eq. 4 in
18 the original paper linked above:
19
20 \f$ f_r(u, v) = \rho_s [ C_x u_x v_x + C_y u_y v_y + C_z u_z v_z ]^n \f$
21
22 \tparam CONF = bbm configuration
23 \tpatam Symmetry = isotropic or anisotropic (Default: symmetry_v::Anisotropic)
24 \tparam NAME = name of the BSDF model (Default: 'Lafortune')
25
26 Implements: concepts::bsdfmodel
27 ***********************************************************************/
28 template<typename CONF, symmetry_v Symmetry = symmetry_v::Anisotropic, string_literal NAME="Lafortune"> requires concepts::config<CONF>
30 {
31 public:
33 static constexpr string_literal name = NAME;
35
36 /********************************************************************/
37 /*! \brief Evaluate the BSDF for a given in and out direction
38
39 \param in = incident direction
40 \param out = outgoing direction
41 \param component = which reflectance component to eval
42 \param unit = unit of computation (ignored)
43 \param mask = masking of lanes (e.g., for Packet eval)
44 \returns Evaluation of the BSDF per spectrum.
45 *********************************************************************/
46 Spectrum eval(const Vec3d& in, const Vec3d& out, BsdfFlag component=bsdf_flag::All, unit_t /*unit*/=unit_t::Radiance, Mask mask=true) const
47 {
48 // specular?
49 mask &= is_set(component, bsdf_flag::Specular);
50
51 // above surface?
52 mask &= (vec::z(in) > 0) && (vec::z(out) > 0);
53
54 // Quick exit if mask is all negative
55 if(bbm::none(mask)) return Spectrum(0);
56
57 // Eval
58 Vec2d cxy(Cxy); // handle isotropic vs anisotropic
59 Vec3d C = vec::expand(cxy, Cz);
60 Value fr = bbm::pow( bbm::max(bbm::dot(C, in*out), 0), sharpness );
61
62 // Done.
63 return bbm::select(mask, albedo * fr, 0);
64 }
65
66
67 /********************************************************************/
68 /*! \brief Sample the BSDF given a direction and two random variables.
69
70 \param out = outgoing direction
71 \param xi = two random variables stored in a Vec2d
72 \param component = which reflectance component to sample
73 \param unit = unit of computation (ignored)
74 \param mask = masking of lanes.
75 \returns A bsdfSample containing the sampled direction and the corresponding pdf.
76 *********************************************************************/
77 BsdfSample sample(const Vec3d& out, const Vec2d& xi, BsdfFlag component=bsdf_flag::All, unit_t unit=unit_t::Radiance, Mask mask=true) const
78 {
79 BsdfSample sample = {0,0,bsdf_flag::None};
80
81 // specular?
82 mask &= is_set(component, bsdf_flag::Specular);
83
84 // check for valid xi
85 mask &= (xi[0] >= 0) && (xi[1] >= 0) && (xi[0] <= 1) && (xi[1] <= 1);
86
87 // Quick exit if mask all negative
88 if(bbm::none(mask)) return sample;
89
90 // sample proportional to pow(cos(alpha), sharpness)
91 Vec2d csp = bbm::cossin(xi[0] * Constants::Pi(2));
92 Value cosTheta = bbm::pow(xi[1], 1.0 / (sharpness + 1));
93 Value sinTheta = bbm::safe_sqrt( 1.0 - cosTheta*cosTheta );
94
95 Vec3d in = vec::expand(csp*sinTheta, cosTheta);
96
97 // transform sampled direction to global frame
98 Vec3d C = vec::expand(Vec2d(Cxy), Cz);
99 sample.direction = toGlobalShadingFrame(bbm::normalize(C*out)) * in;
100
101 // compute pdf
102 sample.pdf = pdf(sample.direction, out, component, unit, mask);
103
104 // set component
105 sample.flag = bbm::select(mask, BsdfFlag(bsdf_flag::Specular), BsdfFlag(bsdf_flag::None));
106
107 // Done.
108 return sample;
109 }
110
111
112 /********************************************************************/
113 /*! \brief Compute the pdf given an in and out direction
114
115 \param in = the incoming (sampled) direction
116 \param out = the outgoing (given) direction
117 \param component = which reflectance component was sampled
118 \param unit = unit of computation (ignored)
119 \param mask = masking of lanes
120 \returns the PDF that the incoming direction would be sampled given the outgoing direction.
121 ***********************************************************************/
122 Value pdf(const Vec3d& in, const Vec3d& out, BsdfFlag component=bsdf_flag::All, unit_t /*unit*/=unit_t::Radiance, Mask mask=true) const
123 {
124 // specular?
125 mask &= is_set(component, bsdf_flag::Specular);
126
127 // above surface?
128 mask &= (vec::z(in) >= 0) && (vec::z(out) >= 0);
129
130 // Quick bailout
131 if(bbm::none(mask)) return 0;
132
133 // compute PDF: (sharpness+1)/2PI * pow(cos(alpha), sharpness)
134 Vec3d C = vec::expand(Vec2d(Cxy), Cz);
135 Value cosAlpha = bbm::max(bbm::dot(bbm::normalize(C*out), in), 0);
136 Value pdf = (sharpness + 1) / Constants::Pi(2) * bbm::pow(cosAlpha, sharpness);
137
138 // Done.
139 return bbm::select(mask, pdf, 0);
140 }
141
142 /*******************************************************************/
143 /*! \brief Return the (approximate) hemispherical reflectance of the BSDF
144
145 \param out = the outgoing direction
146 \param component = which reflectance component to eval
147 \param unit = unit of computation (ignored)
148 \param mask = masking of lanes
149 \returns the approximate hemispherical reflectance of the BSDF for a given direction
150 ********************************************************************/
151 Spectrum reflectance(const Vec3d& out, BsdfFlag component=bsdf_flag::All, unit_t /*unit*/=unit_t::Radiance, Mask mask=true) const
152 {
153 Vec3d C = vec::expand(Vec2d(Cxy), Cz);
154 Value normalization = bbm::pow( bbm::norm(C * out), sharpness ) * Constants::Pi(2) / (sharpness + 2);
155 return bbm::select(mask & is_set(component, bsdf_flag::Specular), albedo * normalization, Spectrum(0));
156 }
157
158
159 //////////////////////////
160 //! @{ Class Attributes
161 //////////////////////////
163 bsdf_parameter<symmetry_t<Symmetry,Value>, bsdf_attr::SpecularParameter, -0.57735026919, std::numeric_limits<Scalar>::max(), std::numeric_limits<Scalar>::min()> Cxy;
166
168 //! @}
169
170 //! \brief Default constructor
172 };
173
175
176} // end bbm namespace
177
178#endif /* _BBM_LAFORTUNE_H_ */
179
All includes and helpers needed for declaring new bsdfmodels.
#define BBM_EXPORT_BSDFMODEL(BsdfModel)
Definition: bbm_fromstring.h:49
The Lafortune BRDF model. This implements the model in Eq. 4 in the original paper linked above:
Definition: lafortune.h:30
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: lafortune.h:46
BBM_ATTRIBUTES(albedo, Cxy, Cz, sharpness)
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: lafortune.h:77
BBM_IMPORT_CONFIG(CONF)
specular_sharpness< Value > sharpness
Definition: lafortune.h:165
bsdf_parameter< Value, bsdf_attr::SpecularParameter, 0.57735026919, std::numeric_limits< Scalar >::max(), std::numeric_limits< Scalar >::min()> Cz
Definition: lafortune.h:164
bsdf_parameter< symmetry_t< Symmetry, Value >, bsdf_attr::SpecularParameter, -0.57735026919, std::numeric_limits< Scalar >::max(), std::numeric_limits< Scalar >::min()> Cxy
Definition: lafortune.h:163
BBM_BSDF_FORWARD
Definition: lafortune.h:34
BBM_DEFAULT_CONSTRUCTOR(lafortune)
Default constructor.
Definition: lafortune.h:171
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: lafortune.h:151
specular_scale< Spectrum > albedo
Class Attributes.
Definition: lafortune.h:162
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: lafortune.h:122
static constexpr string_literal name
Definition: lafortune.h:33
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 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
symmetry_v
symmetry variants.
Definition: bsdf_symmetry.h:19
constexpr auto select(MASK &&mask, const A &a, const A &b)
Definition: backbone.h:255
mat3d< std::decay_t< T > > toGlobalShadingFrame(const vec3d< T > &normal)
Construct a local shading frame to global frame transformation given a normal direction.
Definition: shading_frame.h:26
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