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

# User Rev Content
1 greg 2.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     }