-
Notifications
You must be signed in to change notification settings - Fork 4
/
MERL_BRDF.h
245 lines (192 loc) · 6.8 KB
/
MERL_BRDF.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
// Copyright 2005 Mitsubishi Electric Research Laboratories All Rights Reserved.
// Permission to use, copy and modify this software and its documentation without
// fee for educational, research and non-profit purposes, is hereby granted, provided
// that the above copyright notice and the following three paragraphs appear in all copies.
// To request permission to incorporate this software into commercial products contact:
// Vice President of Marketing and Business Development;
// Mitsubishi Electric Research Laboratories (MERL), 201 Broadway, Cambridge, MA 02139 or
// <license@merl.com>.
// IN NO EVENT SHALL MERL BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL,
// OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND
// ITS DOCUMENTATION, EVEN IF MERL HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
// MERL SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED
// HEREUNDER IS ON AN "AS IS" BASIS, AND MERL HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT,
// UPDATES, ENHANCEMENTS OR MODIFICATIONS.
#ifndef _MERL_BRDF_
#define _MERL_BRDF
#include <vector>
#include <cstdlib>
#include <cmath>
#define BRDF_SAMPLING_RES_THETA_H 90
#define BRDF_SAMPLING_RES_THETA_D 90
#define BRDF_SAMPLING_RES_PHI_D 360
#define RED_SCALE (1.0/1500.0)
#define GREEN_SCALE (1.15/1500.0)
#define BLUE_SCALE (1.66/1500.0)
#define M_PI 3.1415926535897932384626433832795
// cross product of two vectors
void cross_product (double* v1, double* v2, double* out)
{
out[0] = v1[1]*v2[2] - v1[2]*v2[1];
out[1] = v1[2]*v2[0] - v1[0]*v2[2];
out[2] = v1[0]*v2[1] - v1[1]*v2[0];
}
// normalize vector
void normalize(double* v)
{
// normalize
double len = sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
v[0] = v[0] / len;
v[1] = v[1] / len;
v[2] = v[2] / len;
}
// rotate vector along one axis
void rotate_vector(double* vector, double* axis, double angle, double* out)
{
double temp;
double cross[3];
double cos_ang = cos(angle);
double sin_ang = sin(angle);
out[0] = vector[0] * cos_ang;
out[1] = vector[1] * cos_ang;
out[2] = vector[2] * cos_ang;
temp = axis[0]*vector[0]+axis[1]*vector[1]+axis[2]*vector[2];
temp = temp*(1.0-cos_ang);
out[0] += axis[0] * temp;
out[1] += axis[1] * temp;
out[2] += axis[2] * temp;
cross_product (axis,vector,cross);
out[0] += cross[0] * sin_ang;
out[1] += cross[1] * sin_ang;
out[2] += cross[2] * sin_ang;
}
// convert standard coordinates to half vector/difference vector coordinates
void std_coords_to_half_diff_coords(double theta_in, double fi_in, double theta_out, double fi_out,
double& theta_half,double& fi_half,double& theta_diff,double& fi_diff )
{
// compute in vector
double in_vec_z = cos(theta_in);
double proj_in_vec = sin(theta_in);
double in_vec_x = proj_in_vec*cos(fi_in);
double in_vec_y = proj_in_vec*sin(fi_in);
double in[3]= {in_vec_x,in_vec_y,in_vec_z};
normalize(in);
// compute out vector
double out_vec_z = cos(theta_out);
double proj_out_vec = sin(theta_out);
double out_vec_x = proj_out_vec*cos(fi_out);
double out_vec_y = proj_out_vec*sin(fi_out);
double out[3]= {out_vec_x,out_vec_y,out_vec_z};
normalize(out);
// compute halfway vector
double half_x = (in_vec_x + out_vec_x)/2.0f;
double half_y = (in_vec_y + out_vec_y)/2.0f;
double half_z = (in_vec_z + out_vec_z)/2.0f;
double half[3] = {half_x,half_y,half_z};
normalize(half);
// compute theta_half, fi_half
theta_half = acos(half[2]);
fi_half = atan2(half[1], half[0]);
double bi_normal[3] = {0.0, 1.0, 0.0};
double normal[3] = { 0.0, 0.0, 1.0 };
double temp[3];
double diff[3];
// compute diff vector
rotate_vector(in, normal , -fi_half, temp);
rotate_vector(temp, bi_normal, -theta_half, diff);
// compute theta_diff, fi_diff
theta_diff = acos(diff[2]);
fi_diff = atan2(diff[1], diff[0]);
}
// Lookup theta_half index
// This is a non-linear mapping!
// In: [0 .. pi/2]
// Out: [0 .. 89]
inline int theta_half_index(double theta_half)
{
if (theta_half <= 0.0)
return 0;
double theta_half_deg = ((theta_half / (M_PI/2.0))*BRDF_SAMPLING_RES_THETA_H);
double temp = theta_half_deg*BRDF_SAMPLING_RES_THETA_H;
temp = sqrt(temp);
int ret_val = (int)temp;
if (ret_val < 0) ret_val = 0;
if (ret_val >= BRDF_SAMPLING_RES_THETA_H)
ret_val = BRDF_SAMPLING_RES_THETA_H-1;
return ret_val;
}
// Lookup theta_diff index
// In: [0 .. pi/2]
// Out: [0 .. 89]
inline int theta_diff_index(double theta_diff)
{
int tmp = int(theta_diff / (M_PI * 0.5) * BRDF_SAMPLING_RES_THETA_D);
if (tmp < 0)
return 0;
else if (tmp < BRDF_SAMPLING_RES_THETA_D - 1)
return tmp;
else
return BRDF_SAMPLING_RES_THETA_D - 1;
}
// Lookup phi_diff index
inline int phi_diff_index(double phi_diff)
{
// Because of reciprocity, the BRDF is unchanged under
// phi_diff -> phi_diff + M_PI
if (phi_diff < 0.0)
phi_diff += M_PI;
// In: phi_diff in [0 .. pi]
// Out: tmp in [0 .. 179]
int tmp = int(phi_diff / M_PI * BRDF_SAMPLING_RES_PHI_D / 2);
if (tmp < 0)
return 0;
else if (tmp < BRDF_SAMPLING_RES_PHI_D / 2 - 1)
return tmp;
else
return BRDF_SAMPLING_RES_PHI_D / 2 - 1;
}
// Given a pair of incoming/outgoing angles, look up the BRDF.
void lookup_brdf_val(const std::vector<double>& brdf, double theta_in, double fi_in,
double theta_out, double fi_out,
double& red_val,double& green_val,double& blue_val)
{
// Convert to halfangle / difference angle coordinates
double theta_half, fi_half, theta_diff, fi_diff;
std_coords_to_half_diff_coords(theta_in, fi_in, theta_out, fi_out,
theta_half, fi_half, theta_diff, fi_diff);
// Find index.
// Note that phi_half is ignored, since isotropic BRDFs are assumed
int ind = phi_diff_index(fi_diff) +
theta_diff_index(theta_diff) * BRDF_SAMPLING_RES_PHI_D / 2 +
theta_half_index(theta_half) * BRDF_SAMPLING_RES_PHI_D / 2 *
BRDF_SAMPLING_RES_THETA_D;
red_val = brdf[ind] * RED_SCALE;
green_val = brdf[ind + BRDF_SAMPLING_RES_THETA_H*BRDF_SAMPLING_RES_THETA_D*BRDF_SAMPLING_RES_PHI_D/2] * GREEN_SCALE;
blue_val = brdf[ind + BRDF_SAMPLING_RES_THETA_H*BRDF_SAMPLING_RES_THETA_D*BRDF_SAMPLING_RES_PHI_D] * BLUE_SCALE;
if (red_val < 0.0 || green_val < 0.0 || blue_val < 0.0)
fprintf(stderr, "Below horizon.\n");
}
// Read BRDF data
bool read_brdf(const char *filename, std::vector<double>& brdf)
{
FILE *f = fopen(filename, "rb");
if (!f)
return false;
int dims[3];
fread(dims, sizeof(int), 3, f);
int n = dims[0] * dims[1] * dims[2];
if (n != BRDF_SAMPLING_RES_THETA_H *
BRDF_SAMPLING_RES_THETA_D *
BRDF_SAMPLING_RES_PHI_D / 2)
{
fprintf(stderr, "Dimensions don't match\n");
fclose(f);
return false;
}
brdf.resize(3*n);
fread((double*)(&brdf[0]), sizeof(double), 3*n, f);
fclose(f);
return true;
}
#endif /* _MERL_BRDF_H_ */