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.5 by greg, Wed Dec 5 20:07:34 2007 UTC vs.
Revision 2.11 by greg, Fri Apr 11 20:07:12 2008 UTC

# Line 7 | Line 7 | static const char RCSid[] = "$Id$";
7  
8   #include "mkillum.h"
9   #include "paths.h"
10 #include "random.h"
10   #include "ezxml.h"
11  
12 + #define MAXLATS         46              /* maximum number of latitudes */
13  
14 + /* BSDF angle specification */
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 +        v[2] = d = cos(alt);
81 +        d = sqrt(1. - d*d);     /* sin(alt) */
82 +        v[0] = cos(azi)*d;
83 +        v[1] = sin(azi)*d;
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 +        v[2] = -v[2];
155 +
156 +        return(1);
157 + }
158 +
159 +
160 + static int
161 + ab_getndxR(             /* get index corresponding to the reverse vector */
162 +        FVECT v,
163 +        void *p
164 + )
165 + {
166 +        FVECT  v2;
167 +        
168 +        v2[0] = -v[0];
169 +        v2[1] = -v[1];
170 +        v2[2] = -v[2];
171 +
172 +        return ab_getndx(v2, p);
173 + }
174 +
175 +
176 + static void
177 + load_bsdf_data(         /* load BSDF distribution for this wavelength */
178 +        struct BSDF_data *dp,
179 +        ezxml_t wdb
180 + )
181 + {
182 +        char  *cbasis = ezxml_txt(ezxml_child(wdb,"ColumnAngleBasis"));
183 +        char  *rbasis = ezxml_txt(ezxml_child(wdb,"RowAngleBasis"));
184 +        char  *sdata;
185 +        int  i;
186 +        
187 +        if ((cbasis == NULL) | (rbasis == NULL)) {
188 +                error(WARNING, "missing column/row basis for BSDF");
189 +                return;
190 +        }
191 +        /* XXX need to add routines for loading in foreign bases */
192 +        for (i = nabases; i--; )
193 +                if (!strcmp(cbasis, abase_list[i].name)) {
194 +                        dp->ninc = abase_list[i].nangles;
195 +                        dp->ib_priv = (void *)&abase_list[i];
196 +                        dp->ib_vec = ab_getvecR;
197 +                        dp->ib_ndx = ab_getndxR;
198 +                        dp->ib_ohm = ab_getohm;
199 +                        break;
200 +                }
201 +        if (i < 0) {
202 +                sprintf(errmsg, "unsupported ColumnAngleBasis '%s'", cbasis);
203 +                error(WARNING, errmsg);
204 +                return;
205 +        }
206 +        for (i = nabases; i--; )
207 +                if (!strcmp(rbasis, abase_list[i].name)) {
208 +                        dp->nout = abase_list[i].nangles;
209 +                        dp->ob_priv = (void *)&abase_list[i];
210 +                        dp->ob_vec = ab_getvec;
211 +                        dp->ob_ndx = ab_getndx;
212 +                        dp->ob_ohm = ab_getohm;
213 +                        break;
214 +                }
215 +        if (i < 0) {
216 +                sprintf(errmsg, "unsupported RowAngleBasis '%s'", cbasis);
217 +                error(WARNING, errmsg);
218 +                return;
219 +        }
220 +                                /* read BSDF data */
221 +        sdata  = ezxml_txt(ezxml_child(wdb,"ScatteringData"));
222 +        if (sdata == NULL) {
223 +                error(WARNING, "missing BSDF ScatteringData");
224 +                return;
225 +        }
226 +        dp->bsdf = (float *)malloc(sizeof(float)*dp->ninc*dp->nout);
227 +        if (dp->bsdf == NULL)
228 +                error(SYSTEM, "out of memory in load_bsdf_data");
229 +        for (i = 0; i < dp->ninc*dp->nout; i++) {
230 +                char  *sdnext = fskip(sdata);
231 +                if (sdnext == NULL) {
232 +                        error(WARNING, "bad/missing BSDF ScatteringData");
233 +                        free(dp->bsdf); dp->bsdf = NULL;
234 +                        return;
235 +                }
236 +                while (*sdnext && isspace(*sdnext))
237 +                        sdnext++;
238 +                if (*sdnext == ',') sdnext++;
239 +                dp->bsdf[i] = atof(sdata);
240 +                sdata = sdnext;
241 +        }
242 +        while (isspace(*sdata))
243 +                sdata++;
244 +        if (*sdata) {
245 +                sprintf(errmsg, "%d extra characters after BSDF ScatteringData",
246 +                                strlen(sdata));
247 +                error(WARNING, errmsg);
248 +        }
249 + }
250 +
251 +
252   struct BSDF_data *
253   load_BSDF(              /* load BSDF data from file */
254          char *fname
255   )
256   {
257          char                    *path;
258 <        ezxml_t                 fl, wld, wdb;
258 >        ezxml_t                 fl, wtl, wld, wdb;
259          struct BSDF_data        *dp;
260          
261          path = getpath(fname, getrlibpath(), R_OK);
# Line 32 | Line 270 | load_BSDF(             /* load BSDF data from file */
270                  error(WARNING, errmsg);
271                  return(NULL);
272          }
273 +        if (ezxml_error(fl)[0]) {
274 +                sprintf(errmsg, "BSDF \"%s\" %s", path, ezxml_error(fl));
275 +                error(WARNING, errmsg);
276 +                ezxml_free(fl);
277 +                return(NULL);
278 +        }
279 +        if (strcmp(ezxml_name(fl), "WindowElement")) {
280 +                sprintf(errmsg,
281 +                        "BSDF \"%s\": top level node not 'WindowElement'",
282 +                                path);
283 +                error(WARNING, errmsg);
284 +                ezxml_free(fl);
285 +                return(NULL);
286 +        }
287 +        wtl = ezxml_child(ezxml_child(fl, "Optical"), "Layer");
288          dp = (struct BSDF_data *)calloc(1, sizeof(struct BSDF_data));
289 <        if (dp == NULL)
290 <                goto memerr;
291 <        for (wld = ezxml_child(fl, "WavelengthData");
39 <                                fl != NULL; fl = fl->next) {
40 <                if (strcmp(ezxml_child(wld, "Wavelength")->txt, "Visible"))
289 >        for (wld = ezxml_child(wtl, "WavelengthData");
290 >                                wld != NULL; wld = wld->next) {
291 >                if (strcmp(ezxml_txt(ezxml_child(wld,"Wavelength")), "Visible"))
292                          continue;
293                  wdb = ezxml_child(wld, "WavelengthDataBlock");
294                  if (wdb == NULL) continue;
295 <                if (strcmp(ezxml_child(wdb, "WavelengthDataDirection")->txt,
295 >                if (strcmp(ezxml_txt(ezxml_child(wdb,"WavelengthDataDirection")),
296                                          "Transmission Front"))
297                          continue;
298 +                load_bsdf_data(dp, wdb);        /* load front BTDF */
299 +                break;                          /* ignore the rest */
300          }
301 <        /* etc... */
302 <        ezxml_free(fl);
301 >        ezxml_free(fl);                         /* done with XML file */
302 >        if (dp->bsdf == NULL) {
303 >                sprintf(errmsg, "bad/missing BTDF data in \"%s\"", path);
304 >                error(WARNING, errmsg);
305 >                free_BSDF(dp);
306 >                dp = NULL;
307 >        }
308          return(dp);
51 memerr:
52        error(SYSTEM, "out of memory in load_BSDF");
53        return NULL;    /* pro forma return */
309   }
310  
311  
# Line 61 | Line 316 | free_BSDF(             /* free BSDF data structure */
316   {
317          if (b == NULL)
318                  return;
319 <        free(b->bsdf);
319 >        if (b->bsdf != NULL)
320 >                free(b->bsdf);
321          free(b);
322   }
323  
324  
325 < void
325 > int
326   r_BSDF_incvec(          /* compute random input vector at given location */
327          FVECT v,
328          struct BSDF_data *b,
# Line 79 | Line 335 | r_BSDF_incvec(         /* compute random input vector at give
335          double  rad;
336          int     j;
337          
338 <        getBSDF_incvec(v, b, i);
339 <        rad = getBSDF_incrad(b, i);
338 >        if (!getBSDF_incvec(v, b, i))
339 >                return(0);
340 >        rad = sqrt(getBSDF_incohm(b, i) / PI);
341          multisamp(pert, 3, rv);
342          for (j = 0; j < 3; j++)
343                  v[j] += rad*(2.*pert[j] - 1.);
344          if (xm != NULL)
345                  multv3(v, v, xm);
346 <        normalize(v);
346 >        return(normalize(v) != 0.0);
347   }
348  
349  
350 < void
350 > int
351   r_BSDF_outvec(          /* compute random output vector at given location */
352          FVECT v,
353          struct BSDF_data *b,
# Line 103 | Line 360 | r_BSDF_outvec(         /* compute random output vector at giv
360          double  rad;
361          int     j;
362          
363 <        getBSDF_outvec(v, b, o);
364 <        rad = getBSDF_outrad(b, o);
363 >        if (!getBSDF_outvec(v, b, o))
364 >                return(0);
365 >        rad = sqrt(getBSDF_outohm(b, o) / PI);
366          multisamp(pert, 3, rv);
367          for (j = 0; j < 3; j++)
368                  v[j] += rad*(2.*pert[j] - 1.);
369          if (xm != NULL)
370                  multv3(v, v, xm);
371 <        normalize(v);
371 >        return(normalize(v) != 0.0);
372   }
373  
374  
# Line 129 | Line 387 | addrot(                        /* compute rotation (x,y,z) => (xp,yp,zp) */
387          char    **xfp = xfarg;
388          double  theta;
389  
390 +        if (yp[2]*yp[2] + zp[2]*zp[2] < 2.*FTINY*FTINY) {
391 +                /* Special case for X' along Z-axis */
392 +                theta = -atan2(yp[0], yp[1]);
393 +                *xfp++ = "-ry";
394 +                *xfp++ = xp[2] < 0.0 ? "90" : "-90";
395 +                *xfp++ = "-rz";
396 +                sprintf(bufs[bn], "%f", theta*(180./PI));
397 +                *xfp++ = bufs[bn++];
398 +                return(xfp - xfarg);
399 +        }
400          theta = atan2(yp[2], zp[2]);
401          if (!FEQ(theta,0.0)) {
402                  *xfp++ = "-rx";
# Line 153 | Line 421 | addrot(                        /* compute rotation (x,y,z) => (xp,yp,zp) */
421  
422  
423   int
424 < getBSDF_xfm(            /* compute transform for the given surface */
424 > getBSDF_xfm(            /* compute BSDF orient. -> world orient. transform */
425          MAT4 xm,
426          FVECT nrm,
427          UpDir ud
# Line 184 | Line 452 | getBSDF_xfm(           /* compute transform for the given surfa
452                  updir[2] = 1.;
453                  break;
454          case UDunknown:
187                error(WARNING, "unspecified up direction");
455                  return(0);
456          }
457          fcross(xdest, updir, nrm);
# Line 208 | Line 475 | redistribute(          /* pass distarr ray sums through BSDF *
475          MAT4 xm
476   )
477   {
478 +        int     nout = 0;
479          MAT4    mymat, inmat;
480          COLORV  *idist;
481          COLORV  *cp, *csum;
482          FVECT   dv;
483          double  wt;
484 <        int     i, j, k, h;
484 >        int     i, j, k, o;
485          COLOR   col, cinc;
486                                          /* copy incoming distribution */
487          if (b->ninc != distsiz)
# Line 247 | Line 515 | redistribute(          /* pass distarr ray sums through BSDF *
515                  getBSDF_incvec(dv, b, i);       /* compute incident irrad. */
516                  multv3(dv, dv, mymat);
517                  if (dv[2] < 0.0) dv[2] = -dv[2];
518 <                wt = getBSDF_incrad(b, i);
519 <                wt *= wt*PI * dv[2];            /* solid_angle*cosine(theta) */
518 >                wt = getBSDF_incohm(b, i);
519 >                wt *= dv[2];                    /* solid_angle*cosine(theta) */
520                  cp = &idist[3*i];
521                  copycolor(cinc, cp);
522                  scalecolor(cinc, wt);
# Line 257 | Line 525 | redistribute(          /* pass distarr ray sums through BSDF *
525                          flatdir(dv, (k + .5)/nalt, (double)j/nazi);
526                          multv3(dv, dv, inmat);
527                                                  /* evaluate BSDF @ outgoing */
528 <                        wt = BSDF_visible(b, i, getBSDF_outndx(b, dv));
528 >                        o = getBSDF_outndx(b, dv);
529 >                        if (o < 0) {
530 >                                nout++;
531 >                                continue;
532 >                        }
533 >                        wt = BSDF_value(b, i, o);
534                          copycolor(col, cinc);
535                          scalecolor(col, wt);
536                          csum = &distarr[3*(k*nazi + j)];
# Line 265 | Line 538 | redistribute(          /* pass distarr ray sums through BSDF *
538                      }
539          }
540          free(idist);                    /* free temp space */
541 +        if (nout) {
542 +                sprintf(errmsg, "missing %.1f%% of BSDF directions",
543 +                                100.*nout/(b->ninc*nalt*nazi));
544 +                error(WARNING, errmsg);
545 +        }
546   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines