ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/ambient.c
Revision: 2.25
Committed: Thu Jun 2 11:45:27 1994 UTC (29 years, 11 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.24: +6 -4 lines
Log Message:
changed setting of minarad for -ar 0

File Contents

# Content
1 /* Copyright (c) 1993 Regents of the University of California */
2
3 #ifndef lint
4 static char SCCSid[] = "$SunId$ LBL";
5 #endif
6
7 /*
8 * ambient.c - routines dealing with ambient (inter-reflected) component.
9 */
10
11 #include "ray.h"
12
13 #include "octree.h"
14
15 #include "otypes.h"
16
17 #include "ambient.h"
18
19 #include "random.h"
20
21 #define OCTSCALE 0.5 /* ceil((valid rad.)/(cube size)) */
22
23 typedef struct ambtree {
24 AMBVAL *alist; /* ambient value list */
25 struct ambtree *kid; /* 8 child nodes */
26 } AMBTREE; /* ambient octree */
27
28 extern CUBE thescene; /* contains space boundaries */
29
30 #define MAXASET 511 /* maximum number of elements in ambient set */
31 OBJECT ambset[MAXASET+1]={0}; /* ambient include/exclude set */
32
33 double maxarad; /* maximum ambient radius */
34 double minarad; /* minimum ambient radius */
35
36 static AMBTREE atrunk; /* our ambient trunk node */
37
38 static FILE *ambfp = NULL; /* ambient file pointer */
39 static int nunflshed = 0; /* number of unflushed ambient values */
40
41 #define AMBFLUSH (BUFSIZ/AMBVALSIZ)
42
43 #define newambval() (AMBVAL *)bmalloc(sizeof(AMBVAL))
44
45 #define newambtree() (AMBTREE *)calloc(8, sizeof(AMBTREE))
46 #define freeambtree(t) free((char *)(t))
47
48 extern long ftell(), lseek();
49 static int initambfile(), avsave(), avinsert(), loadatree();
50 static AMBVAL *avstore();
51 #ifdef F_SETLKW
52 static aflock();
53 #endif
54
55
56 setambres(ar) /* set ambient resolution */
57 int ar;
58 {
59 ambres = ar < 0 ? 0 : ar; /* may be done already */
60 /* set min & max radii */
61 if (ar <= 0) {
62 minarad = 0;
63 maxarad = thescene.cusize / 2.0;
64 } else {
65 minarad = thescene.cusize / ar;
66 maxarad = 16 * minarad; /* heuristic */
67 if (maxarad > thescene.cusize / 2.0)
68 maxarad = thescene.cusize / 2.0;
69 }
70 if (minarad <= FTINY)
71 minarad = 10*FTINY;
72 if (maxarad <= minarad)
73 maxarad = 64 * minarad;
74 }
75
76
77 setambacc(newa) /* set ambient accuracy */
78 double newa;
79 {
80 static double oldambacc = -1.0;
81 AMBTREE oldatrunk;
82
83 ambacc = newa < 0.0 ? 0.0 : newa; /* may be done already */
84 if (oldambacc < -FTINY)
85 oldambacc = ambacc; /* do nothing first call */
86 if (fabs(newa - oldambacc) < 0.01)
87 return; /* insignificant -- don't bother */
88 if (ambacc <= FTINY)
89 return; /* cannot build new tree */
90 /* else need to rebuild tree */
91 copystruct(&oldatrunk, &atrunk);
92 atrunk.alist = NULL;
93 atrunk.kid = NULL;
94 loadatree(&oldatrunk);
95 oldambacc = ambacc; /* remeber setting for next call */
96 }
97
98
99 setambient(afile) /* initialize calculation */
100 char *afile;
101 {
102 long headlen;
103 AMBVAL amb;
104 /* init ambient limits */
105 setambres(ambres);
106 setambacc(ambacc);
107 if (afile == NULL)
108 return;
109 if (ambacc <= FTINY) {
110 sprintf(errmsg, "zero ambient accuracy so \"%s\" not opened",
111 afile);
112 error(WARNING, errmsg);
113 return;
114 }
115 /* open ambient file */
116 if ((ambfp = fopen(afile, "r+")) != NULL) {
117 initambfile(0);
118 headlen = ftell(ambfp);
119 while (readambval(&amb, ambfp))
120 avinsert(avstore(&amb));
121 /* align */
122 fseek(ambfp, -((ftell(ambfp)-headlen)%AMBVALSIZ), 1);
123 } else if ((ambfp = fopen(afile, "w+")) != NULL)
124 initambfile(1);
125 else {
126 sprintf(errmsg, "cannot open ambient file \"%s\"", afile);
127 error(SYSTEM, errmsg);
128 }
129 nunflshed++; /* lie */
130 ambsync();
131 }
132
133
134 ambnotify(obj) /* record new modifier */
135 OBJECT obj;
136 {
137 static int hitlimit = 0;
138 register OBJREC *o = objptr(obj);
139 register char **amblp;
140
141 if (hitlimit || !ismodifier(o->otype))
142 return;
143 for (amblp = amblist; *amblp != NULL; amblp++)
144 if (!strcmp(o->oname, *amblp)) {
145 if (ambset[0] >= MAXASET) {
146 error(WARNING, "too many modifiers in ambient list");
147 hitlimit++;
148 return; /* should this be fatal? */
149 }
150 insertelem(ambset, obj);
151 return;
152 }
153 }
154
155
156 ambient(acol, r) /* compute ambient component for ray */
157 COLOR acol;
158 register RAY *r;
159 {
160 static int rdepth = 0; /* ambient recursion */
161 double d;
162
163 if (ambdiv <= 0) /* no ambient calculation */
164 goto dumbamb;
165 /* check number of bounces */
166 if (rdepth >= ambounce)
167 goto dumbamb;
168 /* check ambient list */
169 if (ambincl != -1 && r->ro != NULL &&
170 ambincl != inset(ambset, r->ro->omod))
171 goto dumbamb;
172
173 if (ambacc <= FTINY) { /* no ambient storage */
174 rdepth++;
175 d = doambient(acol, r, r->rweight, NULL, NULL);
176 rdepth--;
177 if (d == 0.0)
178 goto dumbamb;
179 return;
180 }
181 /* get ambient value */
182 setcolor(acol, 0.0, 0.0, 0.0);
183 d = sumambient(acol, r, rdepth,
184 &atrunk, thescene.cuorg, thescene.cusize);
185 if (d > FTINY)
186 scalecolor(acol, 1.0/d);
187 else {
188 d = makeambient(acol, r, rdepth++);
189 rdepth--;
190 }
191 if (d > FTINY)
192 return;
193 dumbamb: /* return global value */
194 copycolor(acol, ambval);
195 }
196
197
198 double
199 sumambient(acol, r, al, at, c0, s) /* get interpolated ambient value */
200 COLOR acol;
201 register RAY *r;
202 int al;
203 AMBTREE *at;
204 FVECT c0;
205 double s;
206 {
207 double d, e1, e2, wt, wsum;
208 COLOR ct;
209 FVECT ck0;
210 int i;
211 register int j;
212 register AMBVAL *av;
213 /* do this node */
214 wsum = 0.0;
215 for (av = at->alist; av != NULL; av = av->next) {
216 /*
217 * Ambient level test.
218 */
219 if (av->lvl > al) /* list sorted, so this works */
220 break;
221 if (av->weight < r->rweight-FTINY)
222 continue;
223 /*
224 * Ambient radius test.
225 */
226 e1 = 0.0;
227 for (j = 0; j < 3; j++) {
228 d = av->pos[j] - r->rop[j];
229 e1 += d * d;
230 }
231 e1 /= av->rad * av->rad;
232 if (e1 > ambacc*ambacc*1.21)
233 continue;
234 /*
235 * Normal direction test.
236 */
237 e2 = (1.0 - DOT(av->dir, r->ron)) * r->rweight;
238 if (e2 < 0.0) e2 = 0.0;
239 if (e1 + e2 > ambacc*ambacc*1.21)
240 continue;
241 /*
242 * Ray behind test.
243 */
244 d = 0.0;
245 for (j = 0; j < 3; j++)
246 d += (r->rop[j] - av->pos[j]) *
247 (av->dir[j] + r->ron[j]);
248 if (d*0.5 < -minarad*ambacc-.001)
249 continue;
250 /*
251 * Jittering final test reduces image artifacts.
252 */
253 wt = sqrt(e1) + sqrt(e2);
254 wt *= .9 + .2*urand(9015+samplendx);
255 if (wt > ambacc)
256 continue;
257 if (wt <= 1e-3)
258 wt = 1e3;
259 else
260 wt = 1.0 / wt;
261 wsum += wt;
262 extambient(ct, av, r->rop, r->ron);
263 scalecolor(ct, wt);
264 addcolor(acol, ct);
265 }
266 if (at->kid == NULL)
267 return(wsum);
268 /* do children */
269 s *= 0.5;
270 for (i = 0; i < 8; i++) {
271 for (j = 0; j < 3; j++) {
272 ck0[j] = c0[j];
273 if (1<<j & i)
274 ck0[j] += s;
275 if (r->rop[j] < ck0[j] - OCTSCALE*s)
276 break;
277 if (r->rop[j] > ck0[j] + (1.0+OCTSCALE)*s)
278 break;
279 }
280 if (j == 3)
281 wsum += sumambient(acol, r, al, at->kid+i, ck0, s);
282 }
283 return(wsum);
284 }
285
286
287 double
288 makeambient(acol, r, al) /* make a new ambient value */
289 COLOR acol;
290 register RAY *r;
291 int al;
292 {
293 AMBVAL amb;
294 FVECT gp, gd;
295 /* compute weight */
296 amb.weight = pow(AVGREFL, (double)al);
297 if (r->rweight < 0.2*amb.weight) /* heuristic */
298 amb.weight = r->rweight;
299 /* compute ambient */
300 amb.rad = doambient(acol, r, amb.weight, gp, gd);
301 if (amb.rad == 0.0)
302 return(0.0);
303 /* store it */
304 VCOPY(amb.pos, r->rop);
305 VCOPY(amb.dir, r->ron);
306 amb.lvl = al;
307 copycolor(amb.val, acol);
308 VCOPY(amb.gpos, gp);
309 VCOPY(amb.gdir, gd);
310 /* insert into tree */
311 avsave(&amb); /* and save to file */
312 return(amb.rad);
313 }
314
315
316 extambient(cr, ap, pv, nv) /* extrapolate value at pv, nv */
317 COLOR cr;
318 register AMBVAL *ap;
319 FVECT pv, nv;
320 {
321 FVECT v1, v2;
322 register int i;
323 double d;
324
325 d = 1.0; /* zeroeth order */
326 /* gradient due to translation */
327 for (i = 0; i < 3; i++)
328 d += ap->gpos[i]*(pv[i]-ap->pos[i]);
329 /* gradient due to rotation */
330 VCOPY(v1, ap->dir);
331 fcross(v2, v1, nv);
332 d += DOT(ap->gdir, v2);
333 if (d <= 0.0) {
334 setcolor(cr, 0.0, 0.0, 0.0);
335 return;
336 }
337 copycolor(cr, ap->val);
338 scalecolor(cr, d);
339 }
340
341
342 static
343 initambfile(creat) /* initialize ambient file */
344 int creat;
345 {
346 extern char *progname, *octname, VersionID[];
347
348 #ifdef F_SETLKW
349 aflock(creat ? F_WRLCK : F_RDLCK);
350 #endif
351 #ifdef MSDOS
352 setmode(fileno(ambfp), O_BINARY);
353 #endif
354 setbuf(ambfp, bmalloc(BUFSIZ+8));
355 if (creat) { /* new file */
356 newheader("RADIANCE", ambfp);
357 fprintf(ambfp, "%s -av %g %g %g -ab %d -aa %g ",
358 progname, colval(ambval,RED),
359 colval(ambval,GRN), colval(ambval,BLU),
360 ambounce, ambacc);
361 fprintf(ambfp, "-ad %d -as %d -ar %d %s\n",
362 ambdiv, ambssamp, ambres,
363 octname==NULL ? "" : octname);
364 fprintf(ambfp, "SOFTWARE= %s\n", VersionID);
365 fputformat(AMBFMT, ambfp);
366 putc('\n', ambfp);
367 putambmagic(ambfp);
368 } else if (checkheader(ambfp, AMBFMT, NULL) < 0 || !hasambmagic(ambfp))
369 error(USER, "bad ambient file");
370 }
371
372
373 static
374 avsave(av) /* insert and save an ambient value */
375 AMBVAL *av;
376 {
377 avinsert(avstore(av));
378 if (ambfp == NULL)
379 return;
380 if (writambval(av, ambfp) < 0)
381 goto writerr;
382 if (++nunflshed >= AMBFLUSH)
383 if (ambsync() == EOF)
384 goto writerr;
385 return;
386 writerr:
387 error(SYSTEM, "error writing ambient file");
388 }
389
390
391 static AMBVAL *
392 avstore(aval) /* allocate memory and store aval */
393 register AMBVAL *aval;
394 {
395 register AMBVAL *av;
396
397 if ((av = newambval()) == NULL)
398 error(SYSTEM, "out of memory in avstore");
399 copystruct(av, aval);
400 return(av);
401 }
402
403
404 static
405 avinsert(av) /* insert ambient value in our tree */
406 register AMBVAL *av;
407 {
408 register AMBTREE *at;
409 register AMBVAL *ap;
410 AMBVAL avh;
411 FVECT ck0;
412 double s;
413 int branch;
414 register int i;
415
416 if (av->rad <= FTINY)
417 error(CONSISTENCY, "zero ambient radius in avinsert");
418 at = &atrunk;
419 VCOPY(ck0, thescene.cuorg);
420 s = thescene.cusize;
421 while (s*(OCTSCALE/2) > av->rad*ambacc) {
422 if (at->kid == NULL)
423 if ((at->kid = newambtree()) == NULL)
424 error(SYSTEM, "out of memory in avinsert");
425 s *= 0.5;
426 branch = 0;
427 for (i = 0; i < 3; i++)
428 if (av->pos[i] > ck0[i] + s) {
429 ck0[i] += s;
430 branch |= 1 << i;
431 }
432 at = at->kid + branch;
433 }
434 avh.next = at->alist; /* order by increasing level */
435 for (ap = &avh; ap->next != NULL; ap = ap->next)
436 if (ap->next->lvl >= av->lvl)
437 break;
438 av->next = ap->next;
439 ap->next = av;
440 at->alist = avh.next;
441 }
442
443
444 static
445 loadatree(at) /* move tree to main store */
446 register AMBTREE *at;
447 {
448 register AMBVAL *av;
449 register int i;
450 /* transfer values at this node */
451 for (av = at->alist; av != NULL; av = at->alist) {
452 at->alist = av->next;
453 avinsert(av);
454 }
455 if (at->kid == NULL)
456 return;
457 for (i = 0; i < 8; i++) /* transfer and free children */
458 loadatree(at->kid+i);
459 freeambtree(at->kid);
460 }
461
462
463 #ifdef F_SETLKW
464
465 static
466 aflock(typ) /* lock/unlock ambient file */
467 int typ;
468 {
469 static struct flock fls; /* static so initialized to zeroes */
470
471 fls.l_type = typ;
472 if (fcntl(fileno(ambfp), F_SETLKW, &fls) < 0)
473 error(SYSTEM, "cannot (un)lock ambient file");
474 }
475
476
477 int
478 ambsync() /* synchronize ambient file */
479 {
480 static FILE *ambinp = NULL;
481 static long lastpos = -1;
482 long flen;
483 AMBVAL avs;
484 register int n;
485
486 if (nunflshed == 0)
487 return(0);
488 if (lastpos < 0) /* initializing (locked in initambfile) */
489 goto syncend;
490 /* gain exclusive access */
491 aflock(F_WRLCK);
492 /* see if file has grown */
493 if ((flen = lseek(fileno(ambfp), 0L, 2)) < 0)
494 goto seekerr;
495 if (n = flen - lastpos) { /* file has grown */
496 if (ambinp == NULL) { /* use duplicate filedes */
497 ambinp = fdopen(dup(fileno(ambfp)), "r");
498 if (ambinp == NULL)
499 error(SYSTEM, "fdopen failed in ambsync");
500 }
501 if (fseek(ambinp, lastpos, 0) < 0)
502 goto seekerr;
503 while (n >= AMBVALSIZ) { /* load contributed values */
504 readambval(&avs, ambinp);
505 avinsert(avstore(&avs));
506 n -= AMBVALSIZ;
507 }
508 /*** seek always as safety measure
509 if (n) ***/ /* alignment */
510 if (lseek(fileno(ambfp), flen-n, 0) < 0)
511 goto seekerr;
512 }
513 #ifdef DEBUG
514 if (ambfp->_ptr - ambfp->_base != nunflshed*AMBVALSIZ) {
515 sprintf(errmsg, "ambient file buffer at %d rather than %d",
516 ambfp->_ptr - ambfp->_base,
517 nunflshed*AMBVALSIZ);
518 error(CONSISTENCY, errmsg);
519 }
520 #endif
521 syncend:
522 n = fflush(ambfp); /* calls write() at last */
523 if ((lastpos = lseek(fileno(ambfp), 0L, 1)) < 0)
524 goto seekerr;
525 aflock(F_UNLCK); /* release file */
526 nunflshed = 0;
527 return(n);
528 seekerr:
529 error(SYSTEM, "seek failed in ambsync");
530 }
531
532 #else
533
534 int
535 ambsync() /* flush ambient file */
536 {
537 if (nunflshed == 0)
538 return(0);
539 nunflshed = 0;
540 return(fflush(ambfp));
541 }
542
543 #endif