6
6
//
7
7
#include " pxr/imaging/plugin/hdEmbree/pxrIES/pxrIES.h"
8
8
9
+ #include " pxr/base/gf/math.h"
10
+
9
11
#include < algorithm>
10
12
11
13
16
18
#define M_PI 3.14159265358979323846
17
19
#endif
18
20
21
+ namespace {
22
+
23
+ // -------------------------------------------------------------------------
24
+ // Constants
25
+ // -------------------------------------------------------------------------
26
+
27
+ template <typename T>
28
+ constexpr T _pi = static_cast <T>(M_PI);
29
+
30
+ constexpr float _hemisphereFudgeFactor = 0 .1f ;
31
+
32
+ // -------------------------------------------------------------------------
33
+ // Utility functions
34
+ // -------------------------------------------------------------------------
35
+
36
+
37
+ float
38
+ _linearstep (float x, float a, float b)
39
+ {
40
+ if (x <= a) {
41
+ return 0 .0f ;
42
+ }
43
+
44
+ if (x >= b) {
45
+ return 1 .0f ;
46
+ }
47
+
48
+ return (x - a) / (b - a);
49
+ }
50
+
51
+ } // anonymous namespace
52
+
19
53
20
54
PXR_NAMESPACE_OPEN_SCOPE
21
55
22
56
bool
23
- PxrIESFile::load (std::string const & ies) // non-virtual "override"
57
+ PxrIESFile::load (const std::string & ies) // non-virtual "override"
24
58
{
25
59
clear ();
26
60
if (!Base::load (ies)) {
@@ -47,7 +81,8 @@ PxrIESFile::pxr_extra_process()
47
81
48
82
// does the distribution cover the whole sphere?
49
83
bool is_sphere = false ;
50
- if ((*v_angleMax - *v_angleMin) > (M_PI / 2 + 0.1 /* fudge factor*/ )) {
84
+ if ((*v_angleMax - *v_angleMin)
85
+ > (_pi<float > / 2 .0f + _hemisphereFudgeFactor)) {
51
86
is_sphere = true ;
52
87
}
53
88
@@ -60,19 +95,74 @@ PxrIESFile::pxr_extra_process()
60
95
float dh = h_angles[h + 1 ] - h_angles[h];
61
96
float dv = v_angles[v + 1 ] - v_angles[v];
62
97
// bilinearly interpolate intensity at the patch center
63
- float i0 = (intensity[h][v] + intensity[h][v + 1 ]) / 2 ;
98
+ float i0 = (intensity[h][v] + intensity[h][v + 1 ]) / 2 . 0f ;
64
99
float i1 =
65
- (intensity[h + 1 ][v] + intensity[h + 1 ][v + 1 ]) / 2 ;
66
- float center_intensity = (i0 + i1) / 2 ;
100
+ (intensity[h + 1 ][v] + intensity[h + 1 ][v + 1 ]) / 2 . 0f ;
101
+ float center_intensity = (i0 + i1) / 2 . 0f ;
67
102
// solid angle of the patch
68
- float dS = dh * dv * sinf (v_angles[v] + dv / 2 );
103
+ float dS = dh * dv * sinf (v_angles[v] + dv / 2 . 0f );
69
104
_power += dS * center_intensity;
70
105
}
71
106
}
72
107
73
108
// ...and divide by surface area of a unit sphere (or hemisphere)
74
109
// (this result matches Karma & RIS)
75
- _power /= M_PI * (is_sphere ? 4 : 2 );
110
+ _power /= _pi<float > * (is_sphere ? 4 .0f : 2 .0f );
111
+ }
112
+
113
+ float
114
+ PxrIESFile::eval (float theta, float phi, float angleScale) const
115
+ {
116
+ int hi = -1 ;
117
+ int vi = -1 ;
118
+ float dh = 0 .0f ;
119
+ float dv = 0 .0f ;
120
+
121
+ phi = GfMod (phi, 2 .0f * _pi<float >);
122
+ for (size_t i = 0 ; i < h_angles.size () - 1 ; ++i) {
123
+ if (phi >= h_angles[i] && phi < h_angles[i + 1 ]) {
124
+ hi = i;
125
+ dh = _linearstep (phi, h_angles[i], h_angles[i + 1 ]);
126
+ break ;
127
+ }
128
+ }
129
+
130
+ // This formula matches Renderman's behavior
131
+
132
+ // Scale with origin at "top" (ie, 180 degress / pi), by a factor
133
+ // of 1 / (1 + angleScale), offset so that angleScale = 0 yields the
134
+ // identity function.
135
+ const float profileScale = 1 .0f + angleScale;
136
+ theta = (theta - _pi<float >) / profileScale + _pi<float >;
137
+ theta = GfClamp (theta, 0 .0f , _pi<float >);
138
+
139
+ if (theta < 0 ) {
140
+ // vi = 0;
141
+ // dv = 0;
142
+ return 0 .0f ;
143
+ } else if (theta >= _pi<float >) {
144
+ vi = v_angles.size () - 2 ;
145
+ dv = 1 ;
146
+ } else {
147
+ for (size_t i = 0 ; i < v_angles.size () - 1 ; ++i) {
148
+ if (theta >= v_angles[i] && theta < v_angles[i + 1 ]) {
149
+ vi = i;
150
+ dv = _linearstep (theta, v_angles[i], v_angles[i + 1 ]);
151
+ break ;
152
+ }
153
+ }
154
+ }
155
+
156
+ if (hi == -1 || vi == -1 ) {
157
+ // XXX: need to indicate error somehow here
158
+ return 0 .0f ;
159
+ }
160
+
161
+ // XXX: This should be a cubic interpolation
162
+ float i0 = GfLerp (dv, intensity[hi][vi], intensity[hi][vi + 1 ]);
163
+ float i1 = GfLerp (dv, intensity[hi + 1 ][vi], intensity[hi + 1 ][vi + 1 ]);
164
+
165
+ return GfLerp (dh, i0, i1);
76
166
}
77
167
78
168
PXR_NAMESPACE_CLOSE_SCOPE
0 commit comments