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.4 by greg, Wed Dec 5 05:02:58 2007 UTC vs.
Revision 2.6 by greg, Sat Dec 8 01:43:09 2007 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 (terminate with nphi = -1) */
15 + typedef struct {
16 +        char    name[32];               /* 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 NABASES         3               /* number of predefined bases */
25 +
26 + ANGLE_BASIS     abase_list[NABASES] = {
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 +
61 + static int
62 + ab_getvec(              /* get vector for this angle basis index */
63 +        FVECT v,
64 +        int ndx,
65 +        void *p
66 + )
67 + {
68 +        ANGLE_BASIS  *ab = (ANGLE_BASIS *)p;
69 +        int     li;
70 +        double  alt, azi, d;
71 +        
72 +        if ((ndx < 0) | (ndx >= ab->nangles))
73 +                return(0);
74 +        for (li = 0; ndx >= ab->lat[li].nphis; li++)
75 +                ndx -= ab->lat[li].nphis;
76 +        alt = PI/180.*0.5*(ab->lat[li].tmin + ab->lat[li+1].tmin);
77 +        azi = 2.*PI*ndx/ab->lat[li].nphis;
78 +        d = sin(alt);
79 +        v[0] = cos(azi)*d;
80 +        v[1] = sin(azi)*d;
81 +        v[2] = cos(alt);
82 +        return(1);
83 + }
84 +
85 +
86 + static int
87 + ab_getndx(              /* get index corresponding to the given vector */
88 +        FVECT v,
89 +        void *p
90 + )
91 + {
92 +        ANGLE_BASIS  *ab = (ANGLE_BASIS *)p;
93 +        int     li, ndx;
94 +        double  alt, azi, d;
95 +
96 +        if ((v[2] < 0.0) | (v[2] > 1.0))
97 +                return(-1);
98 +        alt = 180.0/PI*acos(v[2]);
99 +        azi = 180.0/PI*atan2(v[1], v[0]);
100 +        if (azi < 0.0) azi += 360.0;
101 +        for (li = 1; ab->lat[li].tmin <= alt; li++)
102 +                if (!ab->lat[li].nphis)
103 +                        return(-1);
104 +        --li;
105 +        ndx = (int)((1./360.)*azi*ab->lat[li].nphis + 0.5);
106 +        if (ndx >= ab->lat[li].nphis) ndx = 0;
107 +        while (li--)
108 +                ndx += ab->lat[li].nphis;
109 +        return(ndx);
110 + }
111 +
112 +
113 + static double
114 + ab_getohm(              /* get solid angle for this angle basis index */
115 +        int ndx,
116 +        void *p
117 + )
118 + {
119 +        ANGLE_BASIS  *ab = (ANGLE_BASIS *)p;
120 +        int     li;
121 +        double  tdia, pdia;
122 +        
123 +        if ((ndx < 0) | (ndx >= ab->nangles))
124 +                return(0);
125 +        for (li = 0; ndx >= ab->lat[li].nphis; li++)
126 +                ndx -= ab->lat[li].nphis;
127 +        tdia = PI/180.*(ab->lat[li+1].tmin - ab->lat[li].tmin);
128 +        pdia = 2.*PI/ab->lat[li].nphis;
129 +        return(tdia*pdia);
130 + }
131 +
132 +
133 + static int
134 + ab_getvecR(             /* get reverse vector for this angle basis index */
135 +        FVECT v,
136 +        int ndx,
137 +        void *p
138 + )
139 + {
140 +        if (!ab_getvec(v, ndx, p))
141 +                return(0);
142 +
143 +        v[0] = -v[0];
144 +        v[1] = -v[1];
145 +
146 +        return(1);
147 + }
148 +
149 +
150 + static int
151 + ab_getndxR(             /* get index corresponding to the reverse vector */
152 +        FVECT v,
153 +        void *p
154 + )
155 + {
156 +        FVECT  v2;
157 +        
158 +        v2[0] = -v[0];
159 +        v2[1] = -v[1];
160 +        v2[2] = v[2];
161 +
162 +        return ab_getndx(v2, p);
163 + }
164 +
165 + static void
166 + load_bsdf_data(         /* load BSDF distribution for this wavelength */
167 +        struct BSDF_data *dp,
168 +        ezxml_t wdb
169 + )
170 + {
171 +        const char  *cbasis = ezxml_txt(ezxml_child(wdb,"ColumnAngleBasis"));
172 +        const char  *rbasis = ezxml_txt(ezxml_child(wdb,"RowAngleBasis"));
173 +        int  i;
174 +        
175 +        for (i = NABASES; i--; )
176 +                if (!strcmp(cbasis, abase_list[i].name)) {
177 +                        dp->ninc = abase_list[i].nangles;
178 +                        dp->ib_priv = (void *)&abase_list[i];
179 +                        dp->ib_vec = ab_getvec;
180 +                        dp->ib_ndx = ab_getndx;
181 +                        dp->ib_ohm = ab_getohm;
182 +                        break;
183 +                }
184 +        if (i < 0) {
185 +                sprintf(errmsg, "unsupported incident basis '%s'", cbasis);
186 +                error(INTERNAL, errmsg);
187 +        }
188 +        for (i = NABASES; i--; )
189 +                if (!strcmp(rbasis, abase_list[i].name)) {
190 +                        dp->nout = abase_list[i].nangles;
191 +                        dp->ob_priv = (void *)&abase_list[i];
192 +                        dp->ob_vec = ab_getvecR;
193 +                        dp->ob_ndx = ab_getndxR;
194 +                        dp->ob_ohm = ab_getohm;
195 +                        break;
196 +                }
197 +        if (i < 0) {
198 +                sprintf(errmsg, "unsupported exitant basis '%s'", cbasis);
199 +                error(INTERNAL, errmsg);
200 +        }
201 + }
202 +
203 +
204   struct BSDF_data *
205   load_BSDF(              /* load BSDF data from file */
206          char *fname
# Line 32 | Line 222 | load_BSDF(             /* load BSDF data from file */
222                  error(WARNING, errmsg);
223                  return(NULL);
224          }
225 <        dp = (struct BSDF_data *)malloc(sizeof(struct BSDF_data));
226 <        if (dp == NULL)
227 <                goto memerr;
225 >        if (ezxml_error(fl)[0]) {
226 >                sprintf(errmsg, "BSDF \"%s\": %s", path, ezxml_error(fl));
227 >                error(WARNING, errmsg);
228 >                ezxml_free(fl);
229 >                return(NULL);
230 >        }
231 >        dp = (struct BSDF_data *)calloc(1, sizeof(struct BSDF_data));
232          for (wld = ezxml_child(fl, "WavelengthData");
233                                  fl != NULL; fl = fl->next) {
234 <                if (strcmp(ezxml_child(wld, "Wavelength")->txt, "Visible"))
234 >                if (strcmp(ezxml_txt(ezxml_child(wld,"Wavelength")), "Visible"))
235                          continue;
236                  wdb = ezxml_child(wld, "WavelengthDataBlock");
237                  if (wdb == NULL) continue;
238 <                if (strcmp(ezxml_child(wdb, "WavelengthDataDirection")->txt,
238 >                if (strcmp(ezxml_txt(ezxml_child(wdb,"WavelengthDataDirection")),
239                                          "Transmission Front"))
240                          continue;
241 +                load_bsdf_data(dp, wdb);        /* load front BTDF */
242 +                break;                          /* ignore the rest */
243          }
244 <        /* etc... */
245 <        ezxml_free(fl);
244 >        ezxml_free(fl);                         /* done with XML file */
245 >        if (dp->bsdf == NULL) {
246 >                sprintf(errmsg, "bad/missing BTDF data in \"%s\"", path);
247 >                error(WARNING, errmsg);
248 >                free_BSDF(dp);
249 >                dp = NULL;
250 >        }
251          return(dp);
51 memerr:
52        error(SYSTEM, "out of memory in load_BSDF");
53        return NULL;    /* pro forma return */
252   }
253  
254  
# Line 61 | Line 259 | free_BSDF(             /* free BSDF data structure */
259   {
260          if (b == NULL)
261                  return;
262 <        free(b->inc_dir);
263 <        free(b->inc_rad);
66 <        free(b->out_dir);
67 <        free(b->out_rad);
68 <        free(b->bsdf);
262 >        if (b->bsdf != NULL)
263 >                free(b->bsdf);
264          free(b);
265   }
266  
267  
268 < void
268 > int
269   r_BSDF_incvec(          /* compute random input vector at given location */
270          FVECT v,
271          struct BSDF_data *b,
# Line 83 | Line 278 | r_BSDF_incvec(         /* compute random input vector at give
278          double  rad;
279          int     j;
280          
281 <        getBSDF_incvec(v, b, i);
282 <        rad = getBSDF_incrad(b, i);
281 >        if (!getBSDF_incvec(v, b, i))
282 >                return(0);
283 >        rad = sqrt(getBSDF_incohm(b, i) / PI);
284          multisamp(pert, 3, rv);
285          for (j = 0; j < 3; j++)
286                  v[j] += rad*(2.*pert[j] - 1.);
287          if (xm != NULL)
288                  multv3(v, v, xm);
289          normalize(v);
290 +        return(1);
291   }
292  
293  
294 < void
294 > int
295   r_BSDF_outvec(          /* compute random output vector at given location */
296          FVECT v,
297          struct BSDF_data *b,
# Line 107 | Line 304 | r_BSDF_outvec(         /* compute random output vector at giv
304          double  rad;
305          int     j;
306          
307 <        getBSDF_outvec(v, b, o);
308 <        rad = getBSDF_outrad(b, o);
307 >        if (!getBSDF_outvec(v, b, o))
308 >                return(0);
309 >        rad = sqrt(getBSDF_outohm(b, o) / PI);
310          multisamp(pert, 3, rv);
311          for (j = 0; j < 3; j++)
312                  v[j] += rad*(2.*pert[j] - 1.);
313          if (xm != NULL)
314                  multv3(v, v, xm);
315          normalize(v);
316 +        return(1);
317   }
318  
319  
# Line 157 | Line 356 | addrot(                        /* compute rotation (x,y,z) => (xp,yp,zp) */
356  
357  
358   int
359 < getBSDF_xfm(            /* compute transform for the given surface */
359 > getBSDF_xfm(            /* compute BSDF orient. -> world orient. transform */
360          MAT4 xm,
361          FVECT nrm,
362          UpDir ud
# Line 212 | Line 411 | redistribute(          /* pass distarr ray sums through BSDF *
411          MAT4 xm
412   )
413   {
414 <        MAT4    mymat;
415 <        COLORV  *outarr;
414 >        int     nout = 0;
415 >        MAT4    mymat, inmat;
416 >        COLORV  *idist;
417          COLORV  *cp, *csum;
218        uint16  *distcnt;
418          FVECT   dv;
419 <        double  wt0, wt1;
420 <        int     i, j, o;
421 <        int     cnt;
422 <        COLOR   col;
423 <                                        /* allocate temporary memory */
424 <        outarr = (COLORV *)calloc(b->nout, sizeof(COLOR));
425 <        distcnt = (uint16 *)calloc(nalt*nazi, sizeof(uint16));
426 <        if ((outarr == NULL) | (distcnt == NULL))
419 >        double  wt;
420 >        int     i, j, k, o;
421 >        COLOR   col, cinc;
422 >                                        /* copy incoming distribution */
423 >        if (b->ninc != distsiz)
424 >                error(INTERNAL, "error 1 in redistribute");
425 >        idist = (COLORV *)malloc(sizeof(COLOR)*distsiz);
426 >        if (idist == NULL)
427                  error(SYSTEM, "out of memory in redistribute");
428 <                                        /* compose matrix */
428 >        memcpy(idist, distarr, sizeof(COLOR)*distsiz);
429 >                                        /* compose direction transform */
430          for (i = 3; i--; ) {
431                  mymat[i][0] = u[i];
432                  mymat[i][1] = v[i];
# Line 238 | Line 438 | redistribute(          /* pass distarr ray sums through BSDF *
438          if (xm != NULL)
439                  multmat4(mymat, xm, mymat);
440          for (i = 3; i--; ) {            /* make sure it's normalized */
441 <                wt0 = 1./sqrt(  mymat[0][i]*mymat[0][i] +
441 >                wt = 1./sqrt(   mymat[0][i]*mymat[0][i] +
442                                  mymat[1][i]*mymat[1][i] +
443                                  mymat[2][i]*mymat[2][i] );
444                  for (j = 3; j--; )
445 <                        mymat[j][i] *= wt0;
445 >                        mymat[j][i] *= wt;
446          }
447 <                                        /* pass through BSDF */
447 >        if (!invmat4(inmat, mymat))     /* need inverse as well */
448 >                error(INTERNAL, "cannot invert BSDF transform");
449 >        newdist(nalt*nazi);             /* resample distribution */
450          for (i = b->ninc; i--; ) {
451 <                getBSDF_incvec(dv, b, i);
451 >                getBSDF_incvec(dv, b, i);       /* compute incident irrad. */
452                  multv3(dv, dv, mymat);
453 <                wt0 = getBSDF_incrad(b, i);
454 <                wt0 *= PI*wt0 * dv[2];          /* solid_angle*cosine(theta) */
455 <                for (o = b->nout; o--; ) {
456 <                        cp = &distarr[3*i];
457 <                        csum = &outarr[3*o];
458 <                        wt1 = wt0 * BSDF_data(b,i,o);
459 <                        copycolor(col, cp);
460 <                        scalecolor(col, wt1);
461 <                        addcolor(csum, col);
462 <                }
463 <        }
464 <        newdist(nalt*nazi);             /* resample distribution */
465 <        for (o = b->nout; o--; ) {
466 <                getBSDF_outvec(dv, b, o);
265 <                multv3(dv, dv, mymat);
266 <                j = (.5 + atan2(dv[1],dv[0])*(.5/PI))*nazi + .5;
267 <                if (j >= nazi) j = 0;
268 <                i = (0.9999 - dv[2]*dv[2])*nalt;
269 <                csum = &distarr[3*(i*nazi + j)];
270 <                cp = &outarr[3*o];
271 <                addcolor(csum, cp);
272 <                ++distcnt[i*nazi + j];
273 <        }
274 <        free(outarr);
275 <                                        /* fill in missing bits */
276 <        for (i = nalt; i--; )
277 <            for (j = nazi; j--; ) {
278 <                int     ii, jj, alt, azi;
279 <                if (distcnt[i*nazi + j])
280 <                        continue;
281 <                csum = &distarr[3*(i*nazi + j)];
282 <                setcolor(csum, 0., 0., 0.);
283 <                cnt = 0;
284 <                for (o = 0; !cnt; o++)
285 <                    for (ii = -o; ii <= o; ii++) {
286 <                        alt = i + ii;
287 <                        if (alt < 0) continue;
288 <                        if (alt >= nalt) break;
289 <                        for (jj = -o; jj <= o; jj++) {
290 <                            if (ii*ii + jj*jj != o*o)
453 >                if (dv[2] < 0.0) dv[2] = -dv[2];
454 >                wt = getBSDF_incohm(b, i);
455 >                wt *= dv[2];                    /* solid_angle*cosine(theta) */
456 >                cp = &idist[3*i];
457 >                copycolor(cinc, cp);
458 >                scalecolor(cinc, wt);
459 >                for (k = nalt; k--; )           /* loop over distribution */
460 >                    for (j = nazi; j--; ) {
461 >                        flatdir(dv, (k + .5)/nalt, (double)j/nazi);
462 >                        multv3(dv, dv, inmat);
463 >                                                /* evaluate BSDF @ outgoing */
464 >                        o = getBSDF_outndx(b, dv);
465 >                        if (o < 0) {
466 >                                nout++;
467                                  continue;
292                            azi = j + jj;
293                            if (azi >= nazi) azi -= nazi;
294                            else if (azi < 0) azi += nazi;
295                            if (!distcnt[alt*nazi + azi])
296                                continue;
297                            cp = &distarr[3*(alt*nazi + azi)];
298                            addcolor(csum, cp);
299                            cnt += distcnt[alt*nazi + azi];
468                          }
469 +                        wt = BSDF_visible(b, i, o);
470 +                        copycolor(col, cinc);
471 +                        scalecolor(col, wt);
472 +                        csum = &distarr[3*(k*nazi + j)];
473 +                        addcolor(csum, col);    /* sum into distribution */
474                      }
475 <                wt0 = 1./cnt;
476 <                scalecolor(csum, wt0);
477 <            }
478 <                                        /* finish averages */
479 <        for (i = nalt; i--; )
480 <            for (j = nazi; j--; ) {
481 <                if ((cnt = distcnt[i*nazi + j]) <= 1)
309 <                        continue;
310 <                csum = &distarr[3*(i*nazi + j)];
311 <                wt0 = 1./cnt;
312 <                scalecolor(csum, wt0);
313 <            }
314 <        free(distcnt);
475 >        }
476 >        free(idist);                    /* free temp space */
477 >        if (nout) {
478 >                sprintf(errmsg, "missing %.1f%% of BSDF directions",
479 >                                100.*nout/(b->ninc*nalt*nazi));
480 >                error(WARNING, errmsg);
481 >        }
482   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines