ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/gen/mkillum2.c
Revision: 2.35
Committed: Fri Sep 3 23:53:50 2010 UTC (13 years, 7 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.34: +60 -3 lines
Log Message:
Working version of genBSDF with detail geometry support in mkillum

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: mkillum2.c,v 2.34 2009/09/09 15:32:20 greg Exp $";
3 #endif
4 /*
5 * Routines to do the actual calculation for mkillum
6 */
7
8 #include <string.h>
9
10 #include "mkillum.h"
11 #include "face.h"
12 #include "cone.h"
13 #include "source.h"
14 #include "paths.h"
15
16 #ifndef NBSDFSAMPS
17 #define NBSDFSAMPS 256 /* BSDF resampling count */
18 #endif
19
20 COLORV * distarr = NULL; /* distribution array */
21 int distsiz = 0;
22 COLORV * direct_discount = NULL; /* amount to take off direct */
23
24
25 void
26 newdist( /* allocate & clear distribution array */
27 int siz
28 )
29 {
30 if (siz <= 0) {
31 if (distsiz > 0)
32 free((void *)distarr);
33 distarr = NULL;
34 distsiz = 0;
35 return;
36 }
37 if (distsiz < siz) {
38 if (distsiz > 0)
39 free((void *)distarr);
40 distarr = (COLORV *)malloc(sizeof(COLOR)*siz);
41 if (distarr == NULL)
42 error(SYSTEM, "out of memory in newdist");
43 distsiz = siz;
44 }
45 memset(distarr, '\0', sizeof(COLOR)*siz);
46 }
47
48
49 static void
50 new_discount() /* allocate space for direct contrib. record */
51 {
52 if (distsiz <= 0)
53 return;
54 direct_discount = (COLORV *)calloc(distsiz, sizeof(COLOR));
55 if (direct_discount == NULL)
56 error(SYSTEM, "out of memory in new_discount");
57 }
58
59
60 static void
61 done_discount() /* clear off direct contrib. record */
62 {
63 if (direct_discount == NULL)
64 return;
65 free((void *)direct_discount);
66 direct_discount = NULL;
67 }
68
69
70 int
71 process_ray( /* process a ray result or report error */
72 RAY *r,
73 int rv
74 )
75 {
76 COLORV *colp;
77
78 if (rv == 0) /* no result ready */
79 return(0);
80 if (rv < 0)
81 error(USER, "ray tracing process died");
82 if (r->rno >= distsiz)
83 error(INTERNAL, "bad returned index in process_ray");
84 multcolor(r->rcol, r->rcoef); /* in case it's a source ray */
85 colp = &distarr[r->rno * 3];
86 addcolor(colp, r->rcol);
87 if (r->rsrc >= 0 && /* remember source contrib. */
88 direct_discount != NULL) {
89 colp = &direct_discount[r->rno * 3];
90 addcolor(colp, r->rcol);
91 }
92 return(1);
93 }
94
95
96 void
97 raysamp( /* queue a ray sample */
98 int ndx,
99 FVECT org,
100 FVECT dir
101 )
102 {
103 RAY myRay;
104 int rv;
105
106 if ((ndx < 0) | (ndx >= distsiz))
107 error(INTERNAL, "bad index in raysamp");
108 VCOPY(myRay.rorg, org);
109 VCOPY(myRay.rdir, dir);
110 myRay.rmax = .0;
111 rayorigin(&myRay, PRIMARY, NULL, NULL);
112 myRay.rno = ndx;
113 /* queue ray, check result */
114 process_ray(&myRay, ray_pqueue(&myRay));
115 }
116
117
118 void
119 srcsamps( /* sample sources from this surface position */
120 struct illum_args *il,
121 FVECT org,
122 FVECT nrm,
123 MAT4 ixfm
124 )
125 {
126 int nalt, nazi;
127 SRCINDEX si;
128 RAY sr;
129 FVECT v;
130 double d;
131 int i, j;
132 /* get sampling density */
133 if (il->sampdens <= 0) {
134 nalt = nazi = 1;
135 } else {
136 i = PI * il->sampdens;
137 nalt = sqrt(i/PI) + .5;
138 nazi = PI*nalt + .5;
139 }
140 initsrcindex(&si); /* loop over (sub)sources */
141 for ( ; ; ) {
142 VCOPY(sr.rorg, org); /* pick side to shoot from */
143 if (il->sd != NULL) {
144 int sn = si.sn;
145 if (si.sp+1 >= si.np) ++sn;
146 if (sn >= nsources) break;
147 if (source[sn].sflags & SDISTANT)
148 d = DOT(source[sn].sloc, nrm);
149 else {
150 VSUB(v, source[sn].sloc, org);
151 d = DOT(v, nrm);
152 }
153 } else
154 d = 1.0; /* only transmission */
155 if (d < 0.0)
156 d = -1.0001*il->thick - 5.*FTINY;
157 else
158 d = 5.*FTINY;
159 for (i = 3; i--; )
160 sr.rorg[i] += d*nrm[i];
161 samplendx++; /* increment sample counter */
162 if (!srcray(&sr, NULL, &si))
163 break; /* end of sources */
164 /* index direction */
165 if (ixfm != NULL)
166 multv3(v, sr.rdir, ixfm);
167 else
168 VCOPY(v, sr.rdir);
169 if (il->sd != NULL) {
170 i = getBSDF_incndx(il->sd, v);
171 if (i < 0)
172 continue; /* must not be important */
173 sr.rno = i;
174 d = 1.0/getBSDF_incohm(il->sd, i);
175 } else {
176 if (v[2] >= -FTINY)
177 continue; /* only sample transmission */
178 v[0] = -v[0]; v[1] = -v[1]; v[2] = -v[2];
179 sr.rno = flatindex(v, nalt, nazi);
180 d = nalt*nazi*(1./PI) * v[2];
181 }
182 d *= si.dom; /* solid angle correction */
183 scalecolor(sr.rcoef, d);
184 process_ray(&sr, ray_pqueue(&sr));
185 }
186 }
187
188
189 void
190 rayclean() /* finish all pending rays */
191 {
192 RAY myRay;
193
194 while (process_ray(&myRay, ray_presult(&myRay, 0)))
195 ;
196 }
197
198
199 static void
200 mkaxes( /* compute u and v to go with n */
201 FVECT u,
202 FVECT v,
203 FVECT n
204 )
205 {
206 register int i;
207
208 v[0] = v[1] = v[2] = 0.0;
209 for (i = 0; i < 3; i++)
210 if (n[i] < 0.6 && n[i] > -0.6)
211 break;
212 v[i] = 1.0;
213 fcross(u, v, n);
214 normalize(u);
215 fcross(v, n, u);
216 }
217
218
219 static void
220 rounddir( /* compute uniform spherical direction */
221 register FVECT dv,
222 double alt,
223 double azi
224 )
225 {
226 double d1, d2;
227
228 dv[2] = 1. - 2.*alt;
229 d1 = sqrt(1. - dv[2]*dv[2]);
230 d2 = 2.*PI * azi;
231 dv[0] = d1*cos(d2);
232 dv[1] = d1*sin(d2);
233 }
234
235
236 void
237 flatdir( /* compute uniform hemispherical direction */
238 FVECT dv,
239 double alt,
240 double azi
241 )
242 {
243 double d1, d2;
244
245 d1 = sqrt(alt);
246 d2 = 2.*PI * azi;
247 dv[0] = d1*cos(d2);
248 dv[1] = d1*sin(d2);
249 dv[2] = sqrt(1. - alt);
250 }
251
252
253 int
254 flatindex( /* compute index for hemispherical direction */
255 FVECT dv,
256 int nalt,
257 int nazi
258 )
259 {
260 double d;
261 int i, j;
262
263 d = 1.0 - dv[2]*dv[2];
264 i = d*nalt;
265 d = atan2(dv[1], dv[0]) * (0.5/PI);
266 if (d < 0.0) d += 1.0;
267 j = d*nazi + 0.5;
268 if (j >= nazi) j = 0;
269 return(i*nazi + j);
270 }
271
272
273 int
274 printgeom( /* print out detailed geometry for BSDF */
275 struct BSDF_data *sd,
276 char *xfrot,
277 FVECT ctr,
278 double s1,
279 double s2
280 )
281 {
282 static char mgftemp[] = TEMPLATE;
283 char cmdbuf[64];
284 FILE *fp;
285 double sca;
286
287 if (sd == NULL || sd->mgf == NULL)
288 return(0);
289 if (sd->dim[0] <= FTINY || sd->dim[1] <= FTINY)
290 return(0);
291 if ((s1 > s2) ^ (sd->dim[0] > sd->dim[1])) {
292 sca = s1; s1 = s2; s2 = sca;
293 }
294 s1 /= sd->dim[0];
295 s2 /= sd->dim[1];
296 sca = s1 > s2 ? s1 : s2;
297 strcpy(mgftemp, TEMPLATE);
298 if ((fp = fopen(mktemp(mgftemp), "w")) == NULL)
299 error(SYSTEM, "cannot create temporary file for MGF");
300 /* prepend our transform */
301 fprintf(fp, "xf%s -s %.5f -t %.5g %.5g %.5g\n",
302 xfrot, sca, ctr[0], ctr[1], ctr[2]);
303 /* output given MGF description */
304 fputs(sd->mgf, fp);
305 fputs("\nxf\n", fp);
306 if (fclose(fp) == EOF)
307 error(SYSTEM, "error writing MGF temporary file");
308 /* execute mgf2rad to convert MGF */
309 strcpy(cmdbuf, "mgf2rad ");
310 strcpy(cmdbuf+8, mgftemp);
311 fflush(stdout);
312 system(cmdbuf);
313 unlink(mgftemp); /* clean up */
314 return(1);
315 }
316
317
318 int
319 my_default( /* default illum action */
320 OBJREC *ob,
321 struct illum_args *il,
322 char *nm
323 )
324 {
325 sprintf(errmsg, "(%s): cannot make illum for %s \"%s\"",
326 nm, ofun[ob->otype].funame, ob->oname);
327 error(WARNING, errmsg);
328 printobj(il->altmat, ob);
329 return(1);
330 }
331
332
333 int
334 my_face( /* make an illum face */
335 OBJREC *ob,
336 struct illum_args *il,
337 char *nm
338 )
339 {
340 int dim[2];
341 int n, nalt, nazi, alti;
342 double sp[2], r1, r2;
343 int h;
344 FVECT dn, org, dir;
345 FVECT u, v;
346 double ur[2], vr[2];
347 MAT4 xfm;
348 char xfrot[64];
349 int nallow;
350 FACE *fa;
351 int i, j;
352 /* get/check arguments */
353 fa = getface(ob);
354 if (fa->area == 0.0) {
355 freeface(ob);
356 return(my_default(ob, il, nm));
357 }
358 /* set up sampling */
359 if (il->sd != NULL) {
360 if (!getBSDF_xfm(xfm, fa->norm, il->udir, xfrot)) {
361 objerror(ob, WARNING, "illegal up direction");
362 freeface(ob);
363 return(my_default(ob, il, nm));
364 }
365 n = il->sd->ninc;
366 } else {
367 if (il->sampdens <= 0) {
368 nalt = nazi = 1; /* diffuse assumption */
369 } else {
370 n = PI * il->sampdens;
371 nalt = sqrt(n/PI) + .5;
372 nazi = PI*nalt + .5;
373 }
374 n = nazi*nalt;
375 }
376 newdist(n);
377 /* take first edge >= sqrt(area) */
378 for (j = fa->nv-1, i = 0; i < fa->nv; j = i++) {
379 u[0] = VERTEX(fa,i)[0] - VERTEX(fa,j)[0];
380 u[1] = VERTEX(fa,i)[1] - VERTEX(fa,j)[1];
381 u[2] = VERTEX(fa,i)[2] - VERTEX(fa,j)[2];
382 if ((r1 = DOT(u,u)) >= fa->area-FTINY)
383 break;
384 }
385 if (i < fa->nv) { /* got one! -- let's align our axes */
386 r2 = 1.0/sqrt(r1);
387 u[0] *= r2; u[1] *= r2; u[2] *= r2;
388 fcross(v, fa->norm, u);
389 } else /* oh well, we'll just have to wing it */
390 mkaxes(u, v, fa->norm);
391 /* now, find limits in (u,v) coordinates */
392 ur[0] = vr[0] = FHUGE;
393 ur[1] = vr[1] = -FHUGE;
394 for (i = 0; i < fa->nv; i++) {
395 r1 = DOT(VERTEX(fa,i),u);
396 if (r1 < ur[0]) ur[0] = r1;
397 if (r1 > ur[1]) ur[1] = r1;
398 r2 = DOT(VERTEX(fa,i),v);
399 if (r2 < vr[0]) vr[0] = r2;
400 if (r2 > vr[1]) vr[1] = r2;
401 }
402 /* output detailed geometry? */
403 if (!(il->flags & IL_LIGHT) && il->sd != NULL && il->sd->mgf != NULL &&
404 il->thick <= FTINY) {
405 for (j = 3; j--; )
406 org[j] = .5*(ur[0]+ur[1])*u[j] +
407 .5*(vr[0]+vr[1])*v[j] +
408 fa->offset*fa->norm[j];
409 printgeom(il->sd, xfrot, org, ur[1]-ur[0], vr[1]-vr[0]);
410 }
411 dim[0] = random();
412 /* sample polygon */
413 nallow = 5*n*il->nsamps;
414 for (dim[1] = 0; dim[1] < n; dim[1]++)
415 for (i = 0; i < il->nsamps; i++) {
416 /* randomize direction */
417 h = ilhash(dim, 2) + i;
418 if (il->sd != NULL) {
419 r_BSDF_incvec(dir, il->sd, dim[1], urand(h), xfm);
420 } else {
421 multisamp(sp, 2, urand(h));
422 alti = dim[1]/nazi;
423 r1 = (alti + sp[0])/nalt;
424 r2 = (dim[1] - alti*nazi + sp[1] - .5)/nazi;
425 flatdir(dn, r1, r2);
426 for (j = 0; j < 3; j++)
427 dir[j] = -dn[0]*u[j] - dn[1]*v[j] -
428 dn[2]*fa->norm[j];
429 }
430 /* randomize location */
431 do {
432 multisamp(sp, 2, urand(h+4862+nallow));
433 r1 = ur[0] + (ur[1]-ur[0]) * sp[0];
434 r2 = vr[0] + (vr[1]-vr[0]) * sp[1];
435 for (j = 0; j < 3; j++)
436 org[j] = r1*u[j] + r2*v[j]
437 + fa->offset*fa->norm[j];
438 } while (!inface(org, fa) && nallow-- > 0);
439 if (nallow < 0) {
440 objerror(ob, WARNING, "bad aspect");
441 rayclean();
442 freeface(ob);
443 return(my_default(ob, il, nm));
444 }
445 if (il->sd != NULL && DOT(dir, fa->norm) < -FTINY)
446 r1 = -1.0001*il->thick - 5.*FTINY;
447 else
448 r1 = 5.*FTINY;
449 for (j = 0; j < 3; j++)
450 org[j] += r1*fa->norm[j];
451 /* send sample */
452 raysamp(dim[1], org, dir);
453 }
454 /* add in direct component? */
455 if (!directvis && (il->flags & IL_LIGHT || il->sd != NULL)) {
456 MAT4 ixfm;
457 if (il->sd == NULL) {
458 for (i = 3; i--; ) {
459 ixfm[i][0] = u[i];
460 ixfm[i][1] = v[i];
461 ixfm[i][2] = fa->norm[i];
462 ixfm[i][3] = 0.;
463 }
464 ixfm[3][0] = ixfm[3][1] = ixfm[3][2] = 0.;
465 ixfm[3][3] = 1.;
466 } else {
467 if (!invmat4(ixfm, xfm))
468 objerror(ob, INTERNAL,
469 "cannot invert BSDF transform");
470 if (!(il->flags & IL_LIGHT))
471 new_discount();
472 }
473 dim[0] = random();
474 nallow = 10*il->nsamps;
475 for (i = 0; i < il->nsamps; i++) {
476 /* randomize location */
477 h = dim[0] + samplendx++;
478 do {
479 multisamp(sp, 2, urand(h+nallow));
480 r1 = ur[0] + (ur[1]-ur[0]) * sp[0];
481 r2 = vr[0] + (vr[1]-vr[0]) * sp[1];
482 for (j = 0; j < 3; j++)
483 org[j] = r1*u[j] + r2*v[j]
484 + fa->offset*fa->norm[j];
485 } while (!inface(org, fa) && nallow-- > 0);
486 if (nallow < 0) {
487 objerror(ob, WARNING, "bad aspect");
488 rayclean();
489 freeface(ob);
490 return(my_default(ob, il, nm));
491 }
492 /* sample source rays */
493 srcsamps(il, org, fa->norm, ixfm);
494 }
495 }
496 /* wait for all rays to finish */
497 rayclean();
498 if (il->sd != NULL) { /* run distribution through BSDF */
499 nalt = sqrt(il->sd->nout/PI) + .5;
500 nazi = PI*nalt + .5;
501 redistribute(il->sd, nalt, nazi, u, v, fa->norm, xfm);
502 done_discount();
503 if (!il->sampdens)
504 il->sampdens = nalt*nazi/PI + .999;
505 }
506 /* write out the face and its distribution */
507 if (average(il, distarr, n)) {
508 if (il->sampdens > 0)
509 flatout(il, distarr, nalt, nazi, u, v, fa->norm);
510 illumout(il, ob);
511 } else
512 printobj(il->altmat, ob);
513 /* clean up */
514 freeface(ob);
515 return(0);
516 }
517
518
519 int
520 my_sphere( /* make an illum sphere */
521 register OBJREC *ob,
522 struct illum_args *il,
523 char *nm
524 )
525 {
526 int dim[3];
527 int n, nalt, nazi;
528 double sp[4], r1, r2, r3;
529 FVECT org, dir;
530 FVECT u, v;
531 register int i, j;
532 /* check arguments */
533 if (ob->oargs.nfargs != 4)
534 objerror(ob, USER, "bad # of arguments");
535 /* set up sampling */
536 if (il->sampdens <= 0)
537 nalt = nazi = 1;
538 else {
539 n = 4.*PI * il->sampdens;
540 nalt = sqrt(2./PI*n) + .5;
541 nazi = PI/2.*nalt + .5;
542 }
543 if (il->sd != NULL)
544 objerror(ob, WARNING, "BSDF ignored");
545 n = nalt*nazi;
546 newdist(n);
547 dim[0] = random();
548 /* sample sphere */
549 for (dim[1] = 0; dim[1] < nalt; dim[1]++)
550 for (dim[2] = 0; dim[2] < nazi; dim[2]++)
551 for (i = 0; i < il->nsamps; i++) {
552 /* next sample point */
553 multisamp(sp, 4, urand(ilhash(dim,3)+i));
554 /* random direction */
555 r1 = (dim[1] + sp[0])/nalt;
556 r2 = (dim[2] + sp[1] - .5)/nazi;
557 rounddir(dir, r1, r2);
558 /* random location */
559 mkaxes(u, v, dir); /* yuck! */
560 r3 = sqrt(sp[2]);
561 r2 = 2.*PI*sp[3];
562 r1 = r3*ob->oargs.farg[3]*cos(r2);
563 r2 = r3*ob->oargs.farg[3]*sin(r2);
564 r3 = ob->oargs.farg[3]*sqrt(1.01-r3*r3);
565 for (j = 0; j < 3; j++) {
566 org[j] = ob->oargs.farg[j] + r1*u[j] + r2*v[j] +
567 r3*dir[j];
568 dir[j] = -dir[j];
569 }
570 /* send sample */
571 raysamp(dim[1]*nazi+dim[2], org, dir);
572 }
573 /* wait for all rays to finish */
574 rayclean();
575 /* write out the sphere and its distribution */
576 if (average(il, distarr, n)) {
577 if (il->sampdens > 0)
578 roundout(il, distarr, nalt, nazi);
579 else
580 objerror(ob, WARNING, "diffuse distribution");
581 illumout(il, ob);
582 } else
583 printobj(il->altmat, ob);
584 /* clean up */
585 return(1);
586 }
587
588
589 int
590 my_ring( /* make an illum ring */
591 OBJREC *ob,
592 struct illum_args *il,
593 char *nm
594 )
595 {
596 int dim[2];
597 int n, nalt, nazi, alti;
598 double sp[2], r1, r2, r3;
599 int h;
600 FVECT dn, org, dir;
601 FVECT u, v;
602 MAT4 xfm;
603 CONE *co;
604 int i, j;
605 /* get/check arguments */
606 co = getcone(ob, 0);
607 /* set up sampling */
608 if (il->sd != NULL) {
609 if (!getBSDF_xfm(xfm, co->ad, il->udir, NULL)) {
610 objerror(ob, WARNING, "illegal up direction");
611 freecone(ob);
612 return(my_default(ob, il, nm));
613 }
614 n = il->sd->ninc;
615 } else {
616 if (il->sampdens <= 0) {
617 nalt = nazi = 1; /* diffuse assumption */
618 } else {
619 n = PI * il->sampdens;
620 nalt = sqrt(n/PI) + .5;
621 nazi = PI*nalt + .5;
622 }
623 n = nazi*nalt;
624 }
625 newdist(n);
626 mkaxes(u, v, co->ad);
627 dim[0] = random();
628 /* sample disk */
629 for (dim[1] = 0; dim[1] < n; dim[1]++)
630 for (i = 0; i < il->nsamps; i++) {
631 /* next sample point */
632 h = ilhash(dim,2) + i;
633 /* randomize direction */
634 if (il->sd != NULL) {
635 r_BSDF_incvec(dir, il->sd, dim[1], urand(h), xfm);
636 } else {
637 multisamp(sp, 2, urand(h));
638 alti = dim[1]/nazi;
639 r1 = (alti + sp[0])/nalt;
640 r2 = (dim[1] - alti*nazi + sp[1] - .5)/nazi;
641 flatdir(dn, r1, r2);
642 for (j = 0; j < 3; j++)
643 dir[j] = -dn[0]*u[j] - dn[1]*v[j] - dn[2]*co->ad[j];
644 }
645 /* randomize location */
646 multisamp(sp, 2, urand(h+8371));
647 r3 = sqrt(CO_R0(co)*CO_R0(co) +
648 sp[0]*(CO_R1(co)*CO_R1(co) - CO_R0(co)*CO_R0(co)));
649 r2 = 2.*PI*sp[1];
650 r1 = r3*cos(r2);
651 r2 = r3*sin(r2);
652 if (il->sd != NULL && DOT(dir, co->ad) < -FTINY)
653 r3 = -1.0001*il->thick - 5.*FTINY;
654 else
655 r3 = 5.*FTINY;
656 for (j = 0; j < 3; j++)
657 org[j] = CO_P0(co)[j] + r1*u[j] + r2*v[j] +
658 r3*co->ad[j];
659 /* send sample */
660 raysamp(dim[1], org, dir);
661 }
662 /* add in direct component? */
663 if (!directvis && (il->flags & IL_LIGHT || il->sd != NULL)) {
664 MAT4 ixfm;
665 if (il->sd == NULL) {
666 for (i = 3; i--; ) {
667 ixfm[i][0] = u[i];
668 ixfm[i][1] = v[i];
669 ixfm[i][2] = co->ad[i];
670 ixfm[i][3] = 0.;
671 }
672 ixfm[3][0] = ixfm[3][1] = ixfm[3][2] = 0.;
673 ixfm[3][3] = 1.;
674 } else {
675 if (!invmat4(ixfm, xfm))
676 objerror(ob, INTERNAL,
677 "cannot invert BSDF transform");
678 if (!(il->flags & IL_LIGHT))
679 new_discount();
680 }
681 dim[0] = random();
682 for (i = 0; i < il->nsamps; i++) {
683 /* randomize location */
684 h = dim[0] + samplendx++;
685 multisamp(sp, 2, urand(h));
686 r3 = sqrt(CO_R0(co)*CO_R0(co) +
687 sp[0]*(CO_R1(co)*CO_R1(co) - CO_R0(co)*CO_R0(co)));
688 r2 = 2.*PI*sp[1];
689 r1 = r3*cos(r2);
690 r2 = r3*sin(r2);
691 for (j = 0; j < 3; j++)
692 org[j] = CO_P0(co)[j] + r1*u[j] + r2*v[j];
693 /* sample source rays */
694 srcsamps(il, org, co->ad, ixfm);
695 }
696 }
697 /* wait for all rays to finish */
698 rayclean();
699 if (il->sd != NULL) { /* run distribution through BSDF */
700 nalt = sqrt(il->sd->nout/PI) + .5;
701 nazi = PI*nalt + .5;
702 redistribute(il->sd, nalt, nazi, u, v, co->ad, xfm);
703 done_discount();
704 if (!il->sampdens)
705 il->sampdens = nalt*nazi/PI + .999;
706 }
707 /* write out the ring and its distribution */
708 if (average(il, distarr, n)) {
709 if (il->sampdens > 0)
710 flatout(il, distarr, nalt, nazi, u, v, co->ad);
711 illumout(il, ob);
712 } else
713 printobj(il->altmat, ob);
714 /* clean up */
715 freecone(ob);
716 return(1);
717 }
718
719
720 void
721 redistribute( /* pass distarr ray sums through BSDF */
722 struct BSDF_data *b,
723 int nalt,
724 int nazi,
725 FVECT u,
726 FVECT v,
727 FVECT w,
728 MAT4 xm
729 )
730 {
731 int nout = 0;
732 MAT4 mymat, inmat;
733 COLORV *idist;
734 COLORV *cp;
735 FVECT dv;
736 double wt;
737 int i, j, k, c, o;
738 COLOR col, cinc;
739 /* copy incoming distribution */
740 if (b->ninc > distsiz)
741 error(INTERNAL, "error 1 in redistribute");
742 idist = (COLORV *)malloc(sizeof(COLOR)*b->ninc);
743 if (idist == NULL)
744 error(SYSTEM, "out of memory in redistribute");
745 memcpy(idist, distarr, sizeof(COLOR)*b->ninc);
746 /* compose direction transform */
747 for (i = 3; i--; ) {
748 mymat[i][0] = u[i];
749 mymat[i][1] = v[i];
750 mymat[i][2] = w[i];
751 mymat[i][3] = 0.;
752 }
753 mymat[3][0] = mymat[3][1] = mymat[3][2] = 0.;
754 mymat[3][3] = 1.;
755 if (xm != NULL)
756 multmat4(mymat, xm, mymat);
757 for (i = 3; i--; ) { /* make sure it's normalized */
758 wt = 1./sqrt( mymat[0][i]*mymat[0][i] +
759 mymat[1][i]*mymat[1][i] +
760 mymat[2][i]*mymat[2][i] );
761 for (j = 3; j--; )
762 mymat[j][i] *= wt;
763 }
764 if (!invmat4(inmat, mymat)) /* need inverse as well */
765 error(INTERNAL, "cannot invert BSDF transform");
766 newdist(nalt*nazi); /* resample distribution */
767 for (i = b->ninc; i--; ) {
768 int direct_out = -1;
769 COLOR cdir;
770 getBSDF_incvec(dv, b, i); /* compute incident irrad. */
771 multv3(dv, dv, mymat);
772 if (dv[2] < 0.0) {
773 dv[0] = -dv[0]; dv[1] = -dv[1]; dv[2] = -dv[2];
774 direct_out += (direct_discount != NULL);
775 }
776 wt = getBSDF_incohm(b, i);
777 wt *= dv[2]; /* solid_angle*cosine(theta) */
778 cp = &idist[3*i];
779 copycolor(cinc, cp);
780 scalecolor(cinc, wt);
781 if (!direct_out) { /* discount direct contr. */
782 cp = &direct_discount[3*i];
783 copycolor(cdir, cp);
784 scalecolor(cdir, -wt);
785 if (b->nout != b->ninc)
786 direct_out = flatindex(dv, nalt, nazi);
787 else
788 direct_out = i; /* assumes dist. mirroring */
789 }
790 for (k = nalt; k--; ) /* loop over distribution */
791 for (j = nazi; j--; ) {
792 int rstart = random();
793 for (c = NBSDFSAMPS; c--; ) {
794 double sp[2];
795 multisamp(sp, 2, urand(rstart+c));
796 flatdir(dv, (k + sp[0])/nalt,
797 (j + .5 - sp[1])/nazi);
798 multv3(dv, dv, inmat);
799 /* evaluate BSDF @ outgoing */
800 o = getBSDF_outndx(b, dv);
801 if (o < 0) {
802 nout++;
803 continue;
804 }
805 wt = BSDF_value(b, i, o) * (1./NBSDFSAMPS);
806 copycolor(col, cinc);
807 if (b->nout != b->ninc)
808 o = k*nazi + j;
809 if (o == direct_out)
810 addcolor(col, cdir); /* minus direct */
811 scalecolor(col, wt);
812 cp = &distarr[3*(k*nazi + j)];
813 addcolor(cp, col); /* sum into distribution */
814 }
815 }
816 }
817 free(idist); /* free temp space */
818 if (nout) {
819 sprintf(errmsg, "missing %.1f%% of BSDF directions",
820 100.*nout/(b->ninc*nalt*nazi*NBSDFSAMPS));
821 error(WARNING, errmsg);
822 }
823 }