ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/gen/mkillum4.c
(Generate patch)

Comparing ray/src/gen/mkillum4.c (file contents):
Revision 2.1 by greg, Tue Sep 18 19:51:07 2007 UTC vs.
Revision 2.9 by greg, Fri Jan 25 02:11:13 2008 UTC

# Line 7 | Line 7 | static const char RCSid[] = "$Id$";
7  
8   #include "mkillum.h"
9   #include "paths.h"
10 + #include "ezxml.h"
11  
12 + #define MAXLATS         46              /* maximum number of latitudes */
13  
14 + /* BSDF angle specification (terminate with nphi = -1) */
15 + typedef struct {
16 +        char    name[64];               /* basis name */
17 +        int     nangles;                /* total number of directions */
18 +        struct {
19 +                float   tmin;                   /* starting theta */
20 +                short   nphis;                  /* number of phis (0 term) */
21 +        }       lat[MAXLATS+1];         /* latitudes */
22 + } ANGLE_BASIS;
23 +
24 + #define MAXABASES       3               /* limit on defined bases */
25 +
26 + ANGLE_BASIS     abase_list[MAXABASES] = {
27 +        {
28 +                "LBNL/Klems Full", 145,
29 +                { {-5., 1},
30 +                {5., 8},
31 +                {15., 16},
32 +                {25., 20},
33 +                {35., 24},
34 +                {45., 24},
35 +                {55., 24},
36 +                {65., 16},
37 +                {75., 12},
38 +                {90., 0} }
39 +        }, {
40 +                "LBNL/Klems Half", 73,
41 +                { {-6.5, 1},
42 +                {6.5, 8},
43 +                {19.5, 12},
44 +                {32.5, 16},
45 +                {46.5, 20},
46 +                {61.5, 12},
47 +                {76.5, 4},
48 +                {90., 0} }
49 +        }, {
50 +                "LBNL/Klems Quarter", 41,
51 +                { {-9., 1},
52 +                {9., 8},
53 +                {27., 12},
54 +                {46., 12},
55 +                {66., 8},
56 +                {90., 0} }
57 +        }
58 + };
59 +
60 + static int      nabases = 3;    /* current number of defined bases */
61 +
62 +
63 + static int
64 + ab_getvec(              /* get vector for this angle basis index */
65 +        FVECT v,
66 +        int ndx,
67 +        void *p
68 + )
69 + {
70 +        ANGLE_BASIS  *ab = (ANGLE_BASIS *)p;
71 +        int     li;
72 +        double  alt, azi, d;
73 +        
74 +        if ((ndx < 0) | (ndx >= ab->nangles))
75 +                return(0);
76 +        for (li = 0; ndx >= ab->lat[li].nphis; li++)
77 +                ndx -= ab->lat[li].nphis;
78 +        alt = PI/180.*0.5*(ab->lat[li].tmin + ab->lat[li+1].tmin);
79 +        azi = 2.*PI*ndx/ab->lat[li].nphis;
80 +        d = sin(alt);
81 +        v[0] = cos(azi)*d;
82 +        v[1] = sin(azi)*d;
83 +        v[2] = cos(alt);
84 +        return(1);
85 + }
86 +
87 +
88 + static int
89 + ab_getndx(              /* get index corresponding to the given vector */
90 +        FVECT v,
91 +        void *p
92 + )
93 + {
94 +        ANGLE_BASIS  *ab = (ANGLE_BASIS *)p;
95 +        int     li, ndx;
96 +        double  alt, azi, d;
97 +
98 +        if ((v[2] < -1.0) | (v[2] > 1.0))
99 +                return(-1);
100 +        alt = 180.0/PI*acos(v[2]);
101 +        azi = 180.0/PI*atan2(v[1], v[0]);
102 +        if (azi < 0.0) azi += 360.0;
103 +        for (li = 1; ab->lat[li].tmin <= alt; li++)
104 +                if (!ab->lat[li].nphis)
105 +                        return(-1);
106 +        --li;
107 +        ndx = (int)((1./360.)*azi*ab->lat[li].nphis + 0.5);
108 +        if (ndx >= ab->lat[li].nphis) ndx = 0;
109 +        while (li--)
110 +                ndx += ab->lat[li].nphis;
111 +        return(ndx);
112 + }
113 +
114 +
115 + static double
116 + ab_getohm(              /* get solid angle for this angle basis index */
117 +        int ndx,
118 +        void *p
119 + )
120 + {
121 +        ANGLE_BASIS  *ab = (ANGLE_BASIS *)p;
122 +        int     li;
123 +        double  tdia, pdia;
124 +        
125 +        if ((ndx < 0) | (ndx >= ab->nangles))
126 +                return(0);
127 +        for (li = 0; ndx >= ab->lat[li].nphis; li++)
128 +                ndx -= ab->lat[li].nphis;
129 +        if (ab->lat[li].nphis == 1) {           /* special case */
130 +                if (ab->lat[li].tmin > FTINY)
131 +                        error(USER, "unsupported BSDF coordinate system");
132 +                tdia = PI/180. * ab->lat[li+1].tmin;
133 +                return(PI*tdia*tdia);
134 +        }
135 +        tdia = PI/180.*(ab->lat[li+1].tmin - ab->lat[li].tmin);
136 +        tdia *= sin(PI/180.*(ab->lat[li].tmin + ab->lat[li+1].tmin));
137 +        pdia = 2.*PI/ab->lat[li].nphis;
138 +        return(tdia*pdia);
139 + }
140 +
141 +
142 + static int
143 + ab_getvecR(             /* get reverse vector for this angle basis index */
144 +        FVECT v,
145 +        int ndx,
146 +        void *p
147 + )
148 + {
149 +        if (!ab_getvec(v, ndx, p))
150 +                return(0);
151 +
152 +        v[0] = -v[0];
153 +        v[1] = -v[1];
154 +
155 +        return(1);
156 + }
157 +
158 +
159 + static int
160 + ab_getndxR(             /* get index corresponding to the reverse vector */
161 +        FVECT v,
162 +        void *p
163 + )
164 + {
165 +        FVECT  v2;
166 +        
167 +        v2[0] = -v[0];
168 +        v2[1] = -v[1];
169 +        v2[2] = v[2];
170 +
171 +        return ab_getndx(v2, p);
172 + }
173 +
174 +
175 + static void
176 + load_bsdf_data(         /* load BSDF distribution for this wavelength */
177 +        struct BSDF_data *dp,
178 +        ezxml_t wdb
179 + )
180 + {
181 +        char  *cbasis = ezxml_txt(ezxml_child(wdb,"ColumnAngleBasis"));
182 +        char  *rbasis = ezxml_txt(ezxml_child(wdb,"RowAngleBasis"));
183 +        char  *sdata;
184 +        int  i;
185 +        
186 +        if ((cbasis == NULL) | (rbasis == NULL)) {
187 +                error(WARNING, "missing column/row basis for BSDF");
188 +                return;
189 +        }
190 +        /* XXX need to add routines for loading in foreign bases */
191 +        for (i = nabases; i--; )
192 +                if (!strcmp(cbasis, abase_list[i].name)) {
193 +                        dp->ninc = abase_list[i].nangles;
194 +                        dp->ib_priv = (void *)&abase_list[i];
195 +                        dp->ib_vec = ab_getvec;
196 +                        dp->ib_ndx = ab_getndx;
197 +                        dp->ib_ohm = ab_getohm;
198 +                        break;
199 +                }
200 +        if (i < 0) {
201 +                sprintf(errmsg, "unsupported ColumnAngleBasis '%s'", cbasis);
202 +                error(WARNING, errmsg);
203 +                return;
204 +        }
205 +        for (i = nabases; i--; )
206 +                if (!strcmp(rbasis, abase_list[i].name)) {
207 +                        dp->nout = abase_list[i].nangles;
208 +                        dp->ob_priv = (void *)&abase_list[i];
209 +                        dp->ob_vec = ab_getvecR;
210 +                        dp->ob_ndx = ab_getndxR;
211 +                        dp->ob_ohm = ab_getohm;
212 +                        break;
213 +                }
214 +        if (i < 0) {
215 +                sprintf(errmsg, "unsupported RowAngleBasis '%s'", cbasis);
216 +                error(WARNING, errmsg);
217 +                return;
218 +        }
219 +                                /* read BSDF data */
220 +        sdata  = ezxml_txt(ezxml_child(wdb,"ScatteringData"));
221 +        if (sdata == NULL) {
222 +                error(WARNING, "missing BSDF ScatteringData");
223 +                return;
224 +        }
225 +        dp->bsdf = (float *)malloc(sizeof(float)*dp->ninc*dp->nout);
226 +        if (dp->bsdf == NULL)
227 +                error(SYSTEM, "out of memory in load_bsdf_data");
228 +        for (i = 0; i < dp->ninc*dp->nout; i++) {
229 +                char  *sdnext = fskip(sdata);
230 +                if (sdnext == NULL) {
231 +                        error(WARNING, "bad/missing BSDF ScatteringData");
232 +                        free(dp->bsdf); dp->bsdf = NULL;
233 +                        return;
234 +                }
235 +                while (*sdnext && isspace(*sdnext))
236 +                        sdnext++;
237 +                if (*sdnext == ',') sdnext++;
238 +                dp->bsdf[i] = atof(sdata);
239 +                sdata = sdnext;
240 +        }
241 +        while (isspace(*sdata))
242 +                sdata++;
243 +        if (*sdata) {
244 +                sprintf(errmsg, "%d extra characters after BSDF ScatteringData",
245 +                                strlen(sdata));
246 +                error(WARNING, errmsg);
247 +        }
248 + }
249 +
250 +
251   struct BSDF_data *
252   load_BSDF(              /* load BSDF data from file */
253          char *fname
254   )
255   {
256          char                    *path;
257 <        FILE                    *fp;
257 >        ezxml_t                 fl, wld, wdb;
258          struct BSDF_data        *dp;
259          
260          path = getpath(fname, getrlibpath(), R_OK);
# Line 24 | Line 263 | load_BSDF(             /* load BSDF data from file */
263                  error(WARNING, errmsg);
264                  return(NULL);
265          }
266 <        if ((fp = fopen(path, "r")) == NULL) {
266 >        fl = ezxml_parse_file(path);
267 >        if (fl == NULL) {
268                  sprintf(errmsg, "cannot open BSDF \"%s\"", path);
269                  error(WARNING, errmsg);
270                  return(NULL);
271          }
272 <        dp = (struct BSDF_data *)malloc(sizeof(struct BSDF_data));
273 <        if (dp == NULL)
274 <                goto memerr;
275 <        /* etc... */
276 <        fclose(fp);
272 >        if (ezxml_error(fl)[0]) {
273 >                sprintf(errmsg, "BSDF \"%s\": %s", path, ezxml_error(fl));
274 >                error(WARNING, errmsg);
275 >                ezxml_free(fl);
276 >                return(NULL);
277 >        }
278 >        dp = (struct BSDF_data *)calloc(1, sizeof(struct BSDF_data));
279 >        for (wld = ezxml_child(fl, "WavelengthData");
280 >                                wld != NULL; wld = wld->next) {
281 >                if (strcmp(ezxml_txt(ezxml_child(wld,"Wavelength")), "Visible"))
282 >                        continue;
283 >                wdb = ezxml_child(wld, "WavelengthDataBlock");
284 >                if (wdb == NULL) continue;
285 >                if (strcmp(ezxml_txt(ezxml_child(wdb,"WavelengthDataDirection")),
286 >                                        "Transmission Front"))
287 >                        continue;
288 >                load_bsdf_data(dp, wdb);        /* load front BTDF */
289 >                break;                          /* ignore the rest */
290 >        }
291 >        ezxml_free(fl);                         /* done with XML file */
292 >        if (dp->bsdf == NULL) {
293 >                sprintf(errmsg, "bad/missing BTDF data in \"%s\"", path);
294 >                error(WARNING, errmsg);
295 >                free_BSDF(dp);
296 >                dp = NULL;
297 >        }
298          return(dp);
38 memerr:
39        error(SYSTEM, "out of memory in load_BSDF");
40        return NULL;    /* pro forma return */
299   }
300  
301  
# Line 48 | Line 306 | free_BSDF(             /* free BSDF data structure */
306   {
307          if (b == NULL)
308                  return;
309 <        free(b->inc_dir);
310 <        free(b->inc_rad);
53 <        free(b->out_dir);
54 <        free(b->out_rad);
55 <        free(b->bsdf);
309 >        if (b->bsdf != NULL)
310 >                free(b->bsdf);
311          free(b);
312   }
313  
314  
315 < void
315 > int
316   r_BSDF_incvec(          /* compute random input vector at given location */
317          FVECT v,
318          struct BSDF_data *b,
# Line 70 | Line 325 | r_BSDF_incvec(         /* compute random input vector at give
325          double  rad;
326          int     j;
327          
328 <        getBSDF_incvec(v, b, i);
329 <        rad = getBSDF_incrad(b, i);
328 >        if (!getBSDF_incvec(v, b, i))
329 >                return(0);
330 >        rad = sqrt(getBSDF_incohm(b, i) / PI);
331          multisamp(pert, 3, rv);
332          for (j = 0; j < 3; j++)
333                  v[j] += rad*(2.*pert[j] - 1.);
334          if (xm != NULL)
335                  multv3(v, v, xm);
336 <        normalize(v);
336 >        return(normalize(v) != 0.0);
337   }
338  
339  
340 < void
340 > int
341   r_BSDF_outvec(          /* compute random output vector at given location */
342          FVECT v,
343          struct BSDF_data *b,
# Line 94 | Line 350 | r_BSDF_outvec(         /* compute random output vector at giv
350          double  rad;
351          int     j;
352          
353 <        getBSDF_outvec(v, b, o);
354 <        rad = getBSDF_outrad(b, o);
353 >        if (!getBSDF_outvec(v, b, o))
354 >                return(0);
355 >        rad = sqrt(getBSDF_outohm(b, o) / PI);
356          multisamp(pert, 3, rv);
357          for (j = 0; j < 3; j++)
358                  v[j] += rad*(2.*pert[j] - 1.);
359          if (xm != NULL)
360                  multv3(v, v, xm);
361 <        normalize(v);
361 >        return(normalize(v) != 0.0);
362 > }
363 >
364 >
365 > #define  FEQ(a,b)       ((a)-(b) <= 1e-7 && (b)-(a) <= 1e-7)
366 >
367 > static int
368 > addrot(                 /* compute rotation (x,y,z) => (xp,yp,zp) */
369 >        char *xfarg[],
370 >        FVECT xp,
371 >        FVECT yp,
372 >        FVECT zp
373 > )
374 > {
375 >        static char     bufs[3][16];
376 >        int     bn = 0;
377 >        char    **xfp = xfarg;
378 >        double  theta;
379 >
380 >        if (yp[2]*yp[2] + zp[2]*zp[2] < 2.*FTINY*FTINY) {
381 >                /* Special case for X' along Z-axis */
382 >                theta = -atan2(yp[0], yp[1]);
383 >                *xfp++ = "-ry";
384 >                *xfp++ = xp[2] < 0.0 ? "90" : "-90";
385 >                *xfp++ = "-rz";
386 >                sprintf(bufs[bn], "%f", theta*(180./PI));
387 >                *xfp++ = bufs[bn++];
388 >                return(xfp - xfarg);
389 >        }
390 >        theta = atan2(yp[2], zp[2]);
391 >        if (!FEQ(theta,0.0)) {
392 >                *xfp++ = "-rx";
393 >                sprintf(bufs[bn], "%f", theta*(180./PI));
394 >                *xfp++ = bufs[bn++];
395 >        }
396 >        theta = asin(-xp[2]);
397 >        if (!FEQ(theta,0.0)) {
398 >                *xfp++ = "-ry";
399 >                sprintf(bufs[bn], " %f", theta*(180./PI));
400 >                *xfp++ = bufs[bn++];
401 >        }
402 >        theta = atan2(xp[1], xp[0]);
403 >        if (!FEQ(theta,0.0)) {
404 >                *xfp++ = "-rz";
405 >                sprintf(bufs[bn], "%f", theta*(180./PI));
406 >                *xfp++ = bufs[bn++];
407 >        }
408 >        *xfp = NULL;
409 >        return(xfp - xfarg);
410 > }
411 >
412 >
413 > int
414 > getBSDF_xfm(            /* compute BSDF orient. -> world orient. transform */
415 >        MAT4 xm,
416 >        FVECT nrm,
417 >        UpDir ud
418 > )
419 > {
420 >        char    *xfargs[7];
421 >        XF      myxf;
422 >        FVECT   updir, xdest, ydest;
423 >
424 >        updir[0] = updir[1] = updir[2] = 0.;
425 >        switch (ud) {
426 >        case UDzneg:
427 >                updir[2] = -1.;
428 >                break;
429 >        case UDyneg:
430 >                updir[1] = -1.;
431 >                break;
432 >        case UDxneg:
433 >                updir[0] = -1.;
434 >                break;
435 >        case UDxpos:
436 >                updir[0] = 1.;
437 >                break;
438 >        case UDypos:
439 >                updir[1] = 1.;
440 >                break;
441 >        case UDzpos:
442 >                updir[2] = 1.;
443 >                break;
444 >        case UDunknown:
445 >                return(0);
446 >        }
447 >        fcross(xdest, updir, nrm);
448 >        if (normalize(xdest) == 0.0)
449 >                return(0);
450 >        fcross(ydest, nrm, xdest);
451 >        xf(&myxf, addrot(xfargs, xdest, ydest, nrm), xfargs);
452 >        copymat4(xm, myxf.xfm);
453 >        return(1);
454 > }
455 >
456 >
457 > void
458 > redistribute(           /* pass distarr ray sums through BSDF */
459 >        struct BSDF_data *b,
460 >        int nalt,
461 >        int nazi,
462 >        FVECT u,
463 >        FVECT v,
464 >        FVECT w,
465 >        MAT4 xm
466 > )
467 > {
468 >        int     nout = 0;
469 >        MAT4    mymat, inmat;
470 >        COLORV  *idist;
471 >        COLORV  *cp, *csum;
472 >        FVECT   dv;
473 >        double  wt;
474 >        int     i, j, k, o;
475 >        COLOR   col, cinc;
476 >                                        /* copy incoming distribution */
477 >        if (b->ninc != distsiz)
478 >                error(INTERNAL, "error 1 in redistribute");
479 >        idist = (COLORV *)malloc(sizeof(COLOR)*distsiz);
480 >        if (idist == NULL)
481 >                error(SYSTEM, "out of memory in redistribute");
482 >        memcpy(idist, distarr, sizeof(COLOR)*distsiz);
483 >                                        /* compose direction transform */
484 >        for (i = 3; i--; ) {
485 >                mymat[i][0] = u[i];
486 >                mymat[i][1] = v[i];
487 >                mymat[i][2] = w[i];
488 >                mymat[i][3] = 0.;
489 >        }
490 >        mymat[3][0] = mymat[3][1] = mymat[3][2] = 0.;
491 >        mymat[3][3] = 1.;
492 >        if (xm != NULL)
493 >                multmat4(mymat, xm, mymat);
494 >        for (i = 3; i--; ) {            /* make sure it's normalized */
495 >                wt = 1./sqrt(   mymat[0][i]*mymat[0][i] +
496 >                                mymat[1][i]*mymat[1][i] +
497 >                                mymat[2][i]*mymat[2][i] );
498 >                for (j = 3; j--; )
499 >                        mymat[j][i] *= wt;
500 >        }
501 >        if (!invmat4(inmat, mymat))     /* need inverse as well */
502 >                error(INTERNAL, "cannot invert BSDF transform");
503 >        newdist(nalt*nazi);             /* resample distribution */
504 >        for (i = b->ninc; i--; ) {
505 >                getBSDF_incvec(dv, b, i);       /* compute incident irrad. */
506 >                multv3(dv, dv, mymat);
507 >                if (dv[2] < 0.0) dv[2] = -dv[2];
508 >                wt = getBSDF_incohm(b, i);
509 >                wt *= dv[2];                    /* solid_angle*cosine(theta) */
510 >                cp = &idist[3*i];
511 >                copycolor(cinc, cp);
512 >                scalecolor(cinc, wt);
513 >                for (k = nalt; k--; )           /* loop over distribution */
514 >                    for (j = nazi; j--; ) {
515 >                        flatdir(dv, (k + .5)/nalt, (double)j/nazi);
516 >                        multv3(dv, dv, inmat);
517 >                                                /* evaluate BSDF @ outgoing */
518 >                        o = getBSDF_outndx(b, dv);
519 >                        if (o < 0) {
520 >                                nout++;
521 >                                continue;
522 >                        }
523 >                        wt = BSDF_value(b, i, o);
524 >                        copycolor(col, cinc);
525 >                        scalecolor(col, wt);
526 >                        csum = &distarr[3*(k*nazi + j)];
527 >                        addcolor(csum, col);    /* sum into distribution */
528 >                    }
529 >        }
530 >        free(idist);                    /* free temp space */
531 >        if (nout) {
532 >                sprintf(errmsg, "missing %.1f%% of BSDF directions",
533 >                                100.*nout/(b->ninc*nalt*nazi));
534 >                error(WARNING, errmsg);
535 >        }
536   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines