Loading...
Searching...
No Matches
merl_linearizer.h
Go to the documentation of this file.
1#ifndef _BBM_MERL_LINEARIZER_H_
2#define _BBM_MERL_LINEARIZER_H_
3
4#include "concepts/macro.h"
6
7#include "bbm/config.h"
8#include "bbm/vec3dpair.h"
9
10/************************************************************************/
11/*! \file merl_linearizer.h
12
13 \brief Linearize the sphere of in-out directions according to the
14 encoding used in the MERL BRDF database.
15
16 Follows concepts/inout_linearizer.h"
17*************************************************************************/
18
19namespace bbm {
20
21 template<typename CONF> requires concepts::config<CONF>
23 {
25
26 /********************************************************************/
27 /*! \brief Constructor
28 ********************************************************************/
29 merl_linearizer(const vec2d<Size_t>& h = vec2d<Size_t>(1,90), const vec2d<Size_t>& d=vec2d<Size_t>(180,90)) : _samplesH(h), _samplesD(d) {}
30
31 /*******************************************************************/
32 /*! \brief Size of the linearized 'array' of direction pairs
33 ********************************************************************/
34 Size_t size(void) const
35 {
36 return _samplesD[0] * _samplesD[1] * _samplesH[1];
37 }
38
39 /********************************************************************/
40 /*! \brief The in-out coordinate of the idx-th sample
41
42 \param idx = index of the sample (in [0, samples()-1]
43 \returns a Ve3dPair of the in and out direction of the
44 sample. Will return {0,0} if the index is not valid.
45
46 Note: the sample direction is placed at the center of the index's bin,
47 except for the top and bottom, where it is placed at the center of the
48 top and bottom edge respectively.
49 *********************************************************************/
50 Vec3dPair operator()(const Size_t& idx, Mask mask=true) const
51 {
52 Vec3dPair result = {0,0};
53
54 // check bounds
55 mask &= (idx < size());
56 if(bbm::none(mask)) return result;
57
58 // compute halfway/difference indices
59 vec2d<Size_t> idxH(0);
60 vec2d<Size_t> idxD(0);
61 Size_t temp_idx = idx;
62
63 spherical::phi(idxD) = temp_idx % spherical::phi(_samplesD);
64 temp_idx /= spherical::phi(_samplesD);
65
67 temp_idx /= spherical::theta(_samplesD);
68
69 spherical::theta(idxH) = temp_idx;
70
71 // compute halfway/difference vectors
72 Vec2d half_sph = bbm::pow(bbm::cast<Vec2d>(idxH) / _samplesH, 2.0) * (0.5 * Constants::Sphere());
73 Vec2d diff_sph = (bbm::cast<Vec2d>(idxD) / _samplesD) * (0.5 * Constants::Sphere());
74
75 std::tie(result.in, result.out) = convertFromHalfwayDifference( spherical::convert(half_sph), spherical::convert(diff_sph) );
76
77 // make sure round off errors don't push us below the horizon
78 vec::z(result.in) = bbm::max(vec::z(result.in), 0);
79 vec::z(result.out) = bbm::max(vec::z(result.out), 0);
80
81 // Done.
82 return bbm::select(mask, result, Vec3dPair{0,0});
83 }
84
85 /********************************************************************/
86 /*! \brief Map a coordinate to an linear index
87
88 \param in = incident direction
89 \param out = outgoing direction
90 \returns linearized index
91
92 Invalid querries are set to 'size()'.
93 *********************************************************************/
94 Size_t operator()(const Vec3d& in, const Vec3d& out, Mask mask=true) const
95 {
96 // above surface?
97 mask &= ((vec::z(in) >= 0) && (vec::z(out) >= 0));
98
99 // quick bail out (all samples are invalid)
100 if(bbm::none(mask)) return size();
101
102 // compute index in (thetaH, thetaD, phiD)
103 auto HalfDiff = convertToHalfwayDifference(in, out);
104 auto halfway = spherical::convert(HalfDiff.first);
105 auto difference = spherical::convert(HalfDiff.second);
106
107 // when in ~= out, phi(difference) is unstable
108 spherical::phi(difference) = bbm::select( bbm::dot(in,out) > 1-Constants::Epsilon(), 0, spherical::phi(difference) );
109
110 // reciprocity for phi(difference)
112
113 // add epsilon to counter round-off errors
114 auto idxD = bbm::floor((difference/Constants::Sphere(0.5) + Constants::Epsilon()) * _samplesD);
115 auto idxH = bbm::floor(bbm::safe_sqrt(halfway/Constants::Sphere(0.5) + Constants::Epsilon()) * _samplesH);
116
117 // clamp to ensure it remain inside range
118 idxD = bbm::clamp(idxD, 0, _samplesD - 1);
119 idxH = bbm::clamp(idxH, 0, _samplesH - 1);
120
121 // Merge indices
122 return cast<Size_t>(bbm::select(mask, (spherical::theta(idxH) * spherical::theta(_samplesD) + spherical::theta(idxD)) * spherical::phi(_samplesD) + spherical::phi(idxD), size()));
123 }
124
125 private:
126 /////////////////////
127 // Class Attributes
128 /////////////////////
129 vec2d<Size_t> _samplesH;
130 vec2d<Size_t> _samplesD;
131 };
132
134
135} // end bbm namespace
136
137
138#endif /* _BBM_MERL_LINEARIZER_H_ */
All BBM methods are defined to operate on a variety of value types and spectrum types....
inout_linearizer concept
Definition: inout_linearizer.h:28
inout_linearizer contract
Macros for checking if a class meets a concept.
#define BBM_CHECK_CONCEPT(CONCEPTNAME, CLASSNAME,...)
Check a class for a concept with bbm::concepts::archetypes in the namespace.
Definition: macro.h:35
T & phi(vec2d< T > &v)
Definition: spherical.h:39
vec2d< T > convert(const vec3d< T > &v)
Definition: spherical.h:53
T & theta(vec2d< T > &v)
Definition: spherical.h:23
constexpr decltype(auto) z(bbm::vec3d< T > &v)
Definition: vec.h:26
Definition: aggregatebsdf.h:29
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 > difference(const vec3d< T > &a, const vec3d< T > &b)
Difference vector.
Definition: vec_transform.h:106
std::pair< vec3d< T >, vec3d< T > > convertFromHalfwayDifference(const vec3d< T > &half, const vec3d< T > &diff)
Convert from Halfway-Difference to Canonical parameterization.
Definition: vec_transform.h:118
std::pair< vec3d< T >, vec3d< T > > convertToHalfwayDifference(const vec3d< T > &a, const vec3d< T > &b)
Convert fro Canonical to the Halfway-Difference parameterization.
Definition: vec_transform.h:91
Definition: merl_linearizer.h:23
Size_t size(void) const
Size of the linearized 'array' of direction pairs.
Definition: merl_linearizer.h:34
Size_t operator()(const Vec3d &in, const Vec3d &out, Mask mask=true) const
Map a coordinate to an linear index.
Definition: merl_linearizer.h:94
vec2d< Size_t > _samplesH
Definition: merl_linearizer.h:129
merl_linearizer(const vec2d< Size_t > &h=vec2d< Size_t >(1, 90), const vec2d< Size_t > &d=vec2d< Size_t >(180, 90))
Constructor.
Definition: merl_linearizer.h:29
Vec3dPair operator()(const Size_t &idx, Mask mask=true) const
The in-out coordinate of the idx-th sample.
Definition: merl_linearizer.h:50
vec2d< Size_t > _samplesD
Definition: merl_linearizer.h:130
Structure to hold a pair of directions.