ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/ambient.c
Revision: 2.20
Committed: Thu Aug 5 10:02:00 1993 UTC (30 years, 8 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.19: +68 -15 lines
Log Message:
corrected flaws in setting and resetting of ambient accuracy

File Contents

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