Loading...
Searching...
No Matches
orennayar.h
Go to the documentation of this file.
1#ifndef _BBM_ORENNAYAR_H_
2#define _BBM_ORENNAYAR_H_
3
4#include "bbm/bsdfmodel.h"
6
7/************************************************************************/
8/*! \file orennayar.h
9
10 \brief Implements: "Generalization of Lambert's Reflectance Model" [Oren and
11 Nayar 1994]: https://doi.org/10.1145/192161.192213
12
13*************************************************************************/
14
15namespace bbm {
16
17 /**********************************************************************/
18 /*! \brief The Oren-Nayar BSDF microfacet model for diffuse surfaces.
19
20 \tparam CONF = bbm configuration
21 \tpatam NAME = name of the BSDF model (Default: 'OrenNayar')
22
23 Implements: concepts::bsdfmodel
24 ***********************************************************************/
25 template<typename CONF, string_literal NAME="OrenNayar"> requires concepts::config<CONF>
27 {
28 public:
30 static constexpr string_literal name = NAME;
32
33 /********************************************************************/
34 /*! \brief Evaluate the BSDF for a given in and out direction
35
36 \param in = incident direction
37 \param out = outgoing direction
38 \param component = which reflectance component to eval
39 \param unit = unit of computation (ignored)
40 \param mask = masking of lanes (e.g., for Packet eval)
41 \returns Evaluation of the BSDF per spectrum.
42 *********************************************************************/
43 Spectrum eval(const Vec3d& in, const Vec3d& out, BsdfFlag component=bsdf_flag::All, unit_t /*unit*/=unit_t::Radiance, Mask mask=true) const
44 {
45 // diffuse?
46 mask &= is_set(component, bsdf_flag::Diffuse);
47
48 // above surface?
49 mask &= (vec::z(in) > 0) && (vec::z(out) > 0);
50
51 // Quick exit if mask is all negative
52 if(bbm::none(mask)) return Spectrum(0);
53
54 // Compute 'A' and 'B' parameters from roughness
55 Value sigma2 = roughness * roughness;
56 Value A = 1 - 0.5 * sigma2 / (sigma2 + 0.33);
57 Value B = 0.45 * sigma2 / (sigma2 + 0.09);
58
59 // eval: diffuse / PI * factor
60 // factor = A + B * cos(phi(in) - phi(out)) * sin(alpha) * tan(beta)
61 //
62 // Simplify:
63 // --------
64 // cos(phi(in) - phi(out)) = cos(phi(in))*cos(phi(out)) - sin(phi(in))*sin(phi(out))
65 // = (x(in) * x(out) - y(in)*y(out)) / (sin(theta(in)) * sin(theta(out)))
66 // = x(in) * x(out) - y(in)*y(out) / (sinAlpha * sinBeta)
67 //
68 // Substitute in 'factor':
69 // -----------------------
70 // factor = A + B cos(phi(in) - phi(out)) * sinAlpha * tanBeta =
71 // = A + B * (x(in) * x(out) - y(in)*y(out) / (sinAlpha * sinBeta)) * (sinAlpha * sinBeta / cosBeta)
72 // = A + B * (x(in) * x(out) - y(in)*y(out)) / cosBeta
73 //
74 // with cosBeta = cos(min(theta(in), theta(out)))
75 // = max( cos(theta(in)), cos(theta(out)) )
76 //
77 auto cosBeta = bbm::max( spherical::cosTheta(in), spherical::cosTheta(out) );
78 auto dot_xy = (vec::x(in) * vec::x(out)) + (vec::y(in) * vec::y(out));
79 auto factor = A + (B * bbm::max(dot_xy, 0) / cosBeta);
80
81 // compute reflectance
82 Spectrum result = albedo / Constants::Pi() * factor;
83
84 // Done.
85 return bbm::select(mask, result, Spectrum(0));
86 }
87
88
89 /********************************************************************/
90 /*! \brief Sample the BSDF given a direction and two random variables.
91
92 \param out = outgoing direction
93 \param xi = two random variables stored in a Vec2d
94 \param component = which reflectance component to sample
95 \param unit = unit of computation (ignored)
96 \param mask = masking of lanes.
97 \returns A bsdfSample containing the sampled direction and the corresponding pdf.
98
99 Approximate sampling by using the same sampling as Lambertian.
100 *********************************************************************/
101 BsdfSample sample(const Vec3d& out, const Vec2d& xi, BsdfFlag component=bsdf_flag::All, unit_t unit=unit_t::Radiance, Mask mask=true) const
102 {
103 return lambertian<Config>().sample(out, xi, component, unit, mask);
104 }
105
106
107 /********************************************************************/
108 /*! \brief Compute the pdf given an in and out direction
109
110 \param in = the incoming (sampled) direction
111 \param out = the outgoing (given) direction
112 \param component = which reflectance component was sampled
113 \param unit = unit of computation (ignored)
114 \param mask = masking of lanes
115 \returns the PDF that the incoming direction would be sampled given the outgoing direction.
116 ***********************************************************************/
117 Value pdf(const Vec3d& in, const Vec3d& out, BsdfFlag component=bsdf_flag::All, unit_t unit=unit_t::Radiance, Mask mask=true) const
118 {
119 return lambertian<Config>().pdf(in, out, component, unit, mask);
120 }
121
122
123 /*******************************************************************/
124 /*! \brief Return the (approximate) hemispherical reflectance of the BSDF
125
126 \param out = the outgoing direction
127 \param component = which reflectance component to eval
128 \param unit = unit of computation (ignored)
129 \param mask = masking of lanes
130 \returns the approximate hemispherical reflectance of the BSDF for a given direction
131 ********************************************************************/
132 Spectrum reflectance(const Vec3d& /*out*/, BsdfFlag component=bsdf_flag::All, unit_t /*unit*/=unit_t::Radiance, Mask mask=true) const
133 {
134 return bbm::select(mask & is_set(component, bsdf_flag::Diffuse), albedo, Spectrum(0));
135 }
136
137
138 /////////////////////////
139 //! @{ Class Attributes
140 /////////////////////////
143
145 //! @}
146
147 //! \brief Default constructor
149 };
150
152
153} // end bbm namespace
154
155#endif /* BBM_ORENNAYAR_H_ */
156
All includes and helpers needed for declaring new bsdfmodels.
#define BBM_EXPORT_BSDFMODEL(BsdfModel)
Definition: bbm_fromstring.h:49
The Oren-Nayar BSDF microfacet model for diffuse surfaces.
Definition: orennayar.h:27
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: orennayar.h:43
diffuse_scale< Spectrum > albedo
Class Attributes.
Definition: orennayar.h:141
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: orennayar.h:101
BBM_DEFAULT_CONSTRUCTOR(orennayar)
Default constructor.
Definition: orennayar.h:148
BBM_IMPORT_CONFIG(CONF)
BBM_BSDF_FORWARD
Definition: orennayar.h:31
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: orennayar.h:117
BBM_ATTRIBUTES(albedo, roughness)
diffuse_roughness< Value > roughness
Definition: orennayar.h:142
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: orennayar.h:132
static constexpr string_literal name
Definition: orennayar.h:30
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
T cosTheta(const vec2d< T > &v)
Definition: spherical.h:109
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
Definition: aggregatebsdf.h:29
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 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