ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cv/bsdfrep.c
Revision: 2.1
Committed: Fri Oct 19 04:14:29 2012 UTC (11 years, 6 months ago) by greg
Content type: text/plain
Branch: MAIN
Log Message:
Broke pabopto2xml into pabopto2bsdf and bsdf2ttree

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id$";
3 #endif
4 /*
5 * Support BSDF representation as radial basis functions.
6 *
7 * G. Ward
8 */
9
10 #define _USE_MATH_DEFINES
11 #include <stdlib.h>
12 #include <math.h>
13 #include "rtio.h"
14 #include "resolu.h"
15 #include "bsdfrep.h"
16 /* which quadrants are represented */
17 int inp_coverage = 0;
18 /* all incident angles in-plane so far? */
19 int single_plane_incident = -1;
20
21 /* input/output orientations */
22 int input_orient = 0;
23 int output_orient = 0;
24
25 /* processed incident DSF measurements */
26 RBFNODE *dsf_list = NULL;
27
28 /* RBF-linking matrices (edges) */
29 MIGRATION *mig_list = NULL;
30
31 /* current input direction */
32 double theta_in_deg, phi_in_deg;
33
34 /* Register new input direction */
35 int
36 new_input_direction(double new_theta, double new_phi)
37 {
38 if (!input_orient) /* check input orientation */
39 input_orient = 1 - 2*(new_theta > 90.);
40 else if (input_orient > 0 ^ new_theta < 90.) {
41 fprintf(stderr,
42 "%s: Cannot handle input angles on both sides of surface\n",
43 progname);
44 return(0);
45 }
46 /* normalize angle ranges */
47 while (new_theta < -180.)
48 new_theta += 360.;
49 while (new_theta > 180.)
50 new_theta -= 360.;
51 if (new_theta < 0) {
52 new_theta = -new_theta;
53 new_phi += 180.;
54 }
55 while (new_phi < 0)
56 new_phi += 360.;
57 while (new_phi >= 360.)
58 new_phi -= 360.;
59 if (single_plane_incident > 0) /* check input coverage */
60 single_plane_incident = (round(new_phi) == round(phi_in_deg));
61 else if (single_plane_incident < 0)
62 single_plane_incident = 1;
63 theta_in_deg = new_theta; /* assume it's OK */
64 phi_in_deg = new_phi;
65 if ((1. < new_phi) & (new_phi < 89.))
66 inp_coverage |= INP_QUAD1;
67 else if ((91. < new_phi) & (new_phi < 179.))
68 inp_coverage |= INP_QUAD2;
69 else if ((181. < new_phi) & (new_phi < 269.))
70 inp_coverage |= INP_QUAD3;
71 else if ((271. < new_phi) & (new_phi < 359.))
72 inp_coverage |= INP_QUAD4;
73 return(1);
74 }
75
76 /* Apply symmetry to the given vector based on distribution */
77 int
78 use_symmetry(FVECT vec)
79 {
80 double phi = get_phi360(vec);
81
82 switch (inp_coverage) {
83 case INP_QUAD1|INP_QUAD2|INP_QUAD3|INP_QUAD4:
84 break;
85 case INP_QUAD1|INP_QUAD2:
86 if ((-FTINY > phi) | (phi > 180.+FTINY))
87 goto mir_y;
88 break;
89 case INP_QUAD2|INP_QUAD3:
90 if ((90.-FTINY > phi) | (phi > 270.+FTINY))
91 goto mir_x;
92 break;
93 case INP_QUAD3|INP_QUAD4:
94 if ((180.-FTINY > phi) | (phi > 360.+FTINY))
95 goto mir_y;
96 break;
97 case INP_QUAD4|INP_QUAD1:
98 if ((270.-FTINY > phi) & (phi > 90.+FTINY))
99 goto mir_x;
100 break;
101 case INP_QUAD1:
102 if ((-FTINY > phi) | (phi > 90.+FTINY))
103 switch ((int)(phi*(1./90.))) {
104 case 1: goto mir_x;
105 case 2: goto mir_xy;
106 case 3: goto mir_y;
107 }
108 break;
109 case INP_QUAD2:
110 if ((90.-FTINY > phi) | (phi > 180.+FTINY))
111 switch ((int)(phi*(1./90.))) {
112 case 0: goto mir_x;
113 case 2: goto mir_y;
114 case 3: goto mir_xy;
115 }
116 break;
117 case INP_QUAD3:
118 if ((180.-FTINY > phi) | (phi > 270.+FTINY))
119 switch ((int)(phi*(1./90.))) {
120 case 0: goto mir_xy;
121 case 1: goto mir_y;
122 case 3: goto mir_x;
123 }
124 break;
125 case INP_QUAD4:
126 if ((270.-FTINY > phi) | (phi > 360.+FTINY))
127 switch ((int)(phi*(1./90.))) {
128 case 0: goto mir_y;
129 case 1: goto mir_xy;
130 case 2: goto mir_x;
131 }
132 break;
133 default:
134 fprintf(stderr, "%s: Illegal input coverage (%d)\n",
135 progname, inp_coverage);
136 exit(1);
137 }
138 return(0); /* in range */
139 mir_x:
140 vec[0] = -vec[0];
141 return(MIRROR_X);
142 mir_y:
143 vec[1] = -vec[1];
144 return(MIRROR_Y);
145 mir_xy:
146 vec[0] = -vec[0];
147 vec[1] = -vec[1];
148 return(MIRROR_X|MIRROR_Y);
149 }
150
151 /* Reverse symmetry based on what was done before */
152 void
153 rev_symmetry(FVECT vec, int sym)
154 {
155 if (sym & MIRROR_X)
156 vec[0] = -vec[0];
157 if (sym & MIRROR_Y)
158 vec[1] = -vec[1];
159 }
160
161 /* Reverse symmetry for an RBF distribution */
162 void
163 rev_rbf_symmetry(RBFNODE *rbf, int sym)
164 {
165 int n;
166
167 rev_symmetry(rbf->invec, sym);
168 if (sym & MIRROR_X)
169 for (n = rbf->nrbf; n-- > 0; )
170 rbf->rbfa[n].gx = GRIDRES-1 - rbf->rbfa[n].gx;
171 if (sym & MIRROR_Y)
172 for (n = rbf->nrbf; n-- > 0; )
173 rbf->rbfa[n].gy = GRIDRES-1 - rbf->rbfa[n].gy;
174 }
175
176 /* Compute volume associated with Gaussian lobe */
177 double
178 rbf_volume(const RBFVAL *rbfp)
179 {
180 double rad = R2ANG(rbfp->crad);
181
182 return((2.*M_PI) * rbfp->peak * rad*rad);
183 }
184
185 /* Compute outgoing vector from grid position */
186 void
187 ovec_from_pos(FVECT vec, int xpos, int ypos)
188 {
189 double uv[2];
190 double r2;
191
192 SDsquare2disk(uv, (1./GRIDRES)*(xpos+.5), (1./GRIDRES)*(ypos+.5));
193 /* uniform hemispherical projection */
194 r2 = uv[0]*uv[0] + uv[1]*uv[1];
195 vec[0] = vec[1] = sqrt(2. - r2);
196 vec[0] *= uv[0];
197 vec[1] *= uv[1];
198 vec[2] = output_orient*(1. - r2);
199 }
200
201 /* Compute grid position from normalized input/output vector */
202 void
203 pos_from_vec(int pos[2], const FVECT vec)
204 {
205 double sq[2]; /* uniform hemispherical projection */
206 double norm = 1./sqrt(1. + fabs(vec[2]));
207
208 SDdisk2square(sq, vec[0]*norm, vec[1]*norm);
209
210 pos[0] = (int)(sq[0]*GRIDRES);
211 pos[1] = (int)(sq[1]*GRIDRES);
212 }
213
214 /* Evaluate RBF for DSF at the given normalized outgoing direction */
215 double
216 eval_rbfrep(const RBFNODE *rp, const FVECT outvec)
217 {
218 double res = .0;
219 const RBFVAL *rbfp;
220 FVECT odir;
221 double sig2;
222 int n;
223
224 if (rp == NULL)
225 return(.0);
226 rbfp = rp->rbfa;
227 for (n = rp->nrbf; n--; rbfp++) {
228 ovec_from_pos(odir, rbfp->gx, rbfp->gy);
229 sig2 = R2ANG(rbfp->crad);
230 sig2 = (DOT(odir,outvec) - 1.) / (sig2*sig2);
231 if (sig2 > -19.)
232 res += rbfp->peak * exp(sig2);
233 }
234 return(res);
235 }
236
237 /* Insert a new directional scattering function in our global list */
238 int
239 insert_dsf(RBFNODE *newrbf)
240 {
241 RBFNODE *rbf, *rbf_last;
242 int pos;
243 /* check for redundant meas. */
244 for (rbf = dsf_list; rbf != NULL; rbf = rbf->next)
245 if (DOT(rbf->invec, newrbf->invec) >= 1.-FTINY) {
246 fprintf(stderr,
247 "%s: Duplicate incident measurement (ignored)\n",
248 progname);
249 free(newrbf);
250 return(-1);
251 }
252 /* keep in ascending theta order */
253 for (rbf_last = NULL, rbf = dsf_list; rbf != NULL;
254 rbf_last = rbf, rbf = rbf->next)
255 if (single_plane_incident && input_orient*rbf->invec[2] <
256 input_orient*newrbf->invec[2])
257 break;
258 if (rbf_last == NULL) { /* insert new node in list */
259 newrbf->ord = 0;
260 newrbf->next = dsf_list;
261 dsf_list = newrbf;
262 } else {
263 newrbf->ord = rbf_last->ord + 1;
264 newrbf->next = rbf;
265 rbf_last->next = newrbf;
266 }
267 rbf_last = newrbf;
268 while (rbf != NULL) { /* update ordinal positions */
269 rbf->ord = rbf_last->ord + 1;
270 rbf_last = rbf;
271 rbf = rbf->next;
272 }
273 return(newrbf->ord);
274 }
275
276 /* Get the DSF indicated by its ordinal position */
277 RBFNODE *
278 get_dsf(int ord)
279 {
280 RBFNODE *rbf;
281
282 for (rbf = dsf_list; rbf != NULL; rbf = rbf->next)
283 if (rbf->ord == ord);
284 return(rbf);
285 return(NULL);
286 }
287
288 /* Get triangle surface orientation (unnormalized) */
289 void
290 tri_orient(FVECT vres, const FVECT v1, const FVECT v2, const FVECT v3)
291 {
292 FVECT v2minus1, v3minus2;
293
294 VSUB(v2minus1, v2, v1);
295 VSUB(v3minus2, v3, v2);
296 VCROSS(vres, v2minus1, v3minus2);
297 }
298
299 /* Determine if vertex order is reversed (inward normal) */
300 int
301 is_rev_tri(const FVECT v1, const FVECT v2, const FVECT v3)
302 {
303 FVECT tor;
304
305 tri_orient(tor, v1, v2, v3);
306
307 return(DOT(tor, v2) < 0.);
308 }
309
310 /* Find vertices completing triangles on either side of the given edge */
311 int
312 get_triangles(RBFNODE *rbfv[2], const MIGRATION *mig)
313 {
314 const MIGRATION *ej, *ej2;
315 RBFNODE *tv;
316
317 rbfv[0] = rbfv[1] = NULL;
318 if (mig == NULL)
319 return(0);
320 for (ej = mig->rbfv[0]->ejl; ej != NULL;
321 ej = nextedge(mig->rbfv[0],ej)) {
322 if (ej == mig)
323 continue;
324 tv = opp_rbf(mig->rbfv[0],ej);
325 for (ej2 = tv->ejl; ej2 != NULL; ej2 = nextedge(tv,ej2))
326 if (opp_rbf(tv,ej2) == mig->rbfv[1]) {
327 rbfv[is_rev_tri(mig->rbfv[0]->invec,
328 mig->rbfv[1]->invec,
329 tv->invec)] = tv;
330 break;
331 }
332 }
333 return((rbfv[0] != NULL) + (rbfv[1] != NULL));
334 }
335
336 /* Write our BSDF mesh interpolant out to the given binary stream */
337 void
338 save_bsdf_rep(FILE *ofp)
339 {
340 RBFNODE *rbf;
341 MIGRATION *mig;
342 int i, n;
343 /* finish header */
344 fputformat(BSDFREP_FMT, ofp);
345 fputc('\n', ofp);
346 /* write each DSF */
347 for (rbf = dsf_list; rbf != NULL; rbf = rbf->next) {
348 putint(rbf->ord, 4, ofp);
349 putflt(rbf->invec[0], ofp);
350 putflt(rbf->invec[1], ofp);
351 putflt(rbf->invec[2], ofp);
352 putflt(rbf->vtotal, ofp);
353 putint(rbf->nrbf, 4, ofp);
354 for (i = 0; i < rbf->nrbf; i++) {
355 putflt(rbf->rbfa[i].peak, ofp);
356 putint(rbf->rbfa[i].crad, 2, ofp);
357 putint(rbf->rbfa[i].gx, 1, ofp);
358 putint(rbf->rbfa[i].gy, 1, ofp);
359 }
360 }
361 putint(-1, 4, ofp); /* terminator */
362 /* write each migration matrix */
363 for (mig = mig_list; mig != NULL; mig = mig_list->next) {
364 putint(mig->rbfv[0]->ord, 4, ofp);
365 putint(mig->rbfv[1]->ord, 4, ofp);
366 n = mtx_nrows(mig) * mtx_ncols(mig);
367 for (i = 0; i < n; i++)
368 putflt(mig->mtx[i], ofp);
369 }
370 putint(-1, 4, ofp); /* terminator */
371 putint(-1, 4, ofp);
372 if (fflush(ofp) == EOF) {
373 fprintf(stderr, "%s: error writing BSDF interpolant\n",
374 progname);
375 exit(1);
376 }
377 }
378
379 /* Read a BSDF mesh interpolant from the given binary stream */
380 int
381 load_bsdf_rep(FILE *ifp)
382 {
383 RBFNODE rbfh;
384 int from_ord, to_ord;
385 int i;
386 #ifdef DEBUG
387 if ((dsf_list != NULL) | (mig_list != NULL)) {
388 fprintf(stderr,
389 "%s: attempt to load BSDF interpolant over existing\n",
390 progname);
391 return(0);
392 }
393 #endif
394 if (checkheader(ifp, BSDFREP_FMT, NULL) <= 0) {
395 fprintf(stderr, "%s: missing/bad format for BSDF interpolant\n",
396 progname);
397 return(0);
398 }
399 rbfh.next = NULL; /* read each DSF */
400 rbfh.ejl = NULL;
401 while ((rbfh.ord = getint(4, ifp)) >= 0) {
402 RBFNODE *newrbf;
403
404 rbfh.invec[0] = getflt(ifp);
405 rbfh.invec[1] = getflt(ifp);
406 rbfh.invec[2] = getflt(ifp);
407 rbfh.nrbf = getint(4, ifp);
408 if (!new_input_vector(rbfh.invec))
409 return(0);
410 newrbf = (RBFNODE *)malloc(sizeof(RBFNODE) +
411 sizeof(RBFVAL)*(rbfh.nrbf-1));
412 if (newrbf == NULL)
413 goto memerr;
414 memcpy(newrbf, &rbfh, sizeof(RBFNODE));
415 for (i = 0; i < rbfh.nrbf; i++) {
416 newrbf->rbfa[i].peak = getflt(ifp);
417 newrbf->rbfa[i].crad = getint(2, ifp) & 0xffff;
418 newrbf->rbfa[i].gx = getint(1, ifp) & 0xff;
419 newrbf->rbfa[i].gy = getint(1, ifp) & 0xff;
420 }
421 if (feof(ifp))
422 goto badEOF;
423 /* insert in global list */
424 if (insert_dsf(newrbf) != rbfh.ord) {
425 fprintf(stderr, "%s: error adding DSF\n", progname);
426 return(0);
427 }
428 }
429 /* read each migration matrix */
430 while ((from_ord = getint(4, ifp)) >= 0 &&
431 (to_ord = getint(4, ifp)) >= 0) {
432 RBFNODE *from_rbf = get_dsf(from_ord);
433 RBFNODE *to_rbf = get_dsf(to_ord);
434 MIGRATION *newmig;
435 int n;
436
437 if ((from_rbf == NULL) | (to_rbf == NULL)) {
438 fprintf(stderr,
439 "%s: bad DSF reference in migration edge\n",
440 progname);
441 return(0);
442 }
443 n = from_rbf->nrbf * to_rbf->nrbf;
444 newmig = (MIGRATION *)malloc(sizeof(MIGRATION) +
445 sizeof(float)*(n-1));
446 if (newmig == NULL)
447 goto memerr;
448 newmig->rbfv[0] = from_rbf;
449 newmig->rbfv[1] = to_rbf;
450 /* read matrix coefficients */
451 for (i = 0; i < n; i++)
452 newmig->mtx[i] = getflt(ifp);
453 if (feof(ifp))
454 goto badEOF;
455 /* insert in edge lists */
456 newmig->enxt[0] = from_rbf->ejl;
457 from_rbf->ejl = newmig;
458 newmig->enxt[1] = to_rbf->ejl;
459 to_rbf->ejl = newmig;
460 /* push onto global list */
461 newmig->next = mig_list;
462 mig_list = newmig;
463 }
464 return(1); /* success! */
465 memerr:
466 fprintf(stderr, "%s: Out of memory in load_bsdf_rep()\n", progname);
467 exit(1);
468 badEOF:
469 fprintf(stderr, "%s: Unexpected EOF in load_bsdf_rep()\n", progname);
470 return(0);
471 }