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

# 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(), loadtree();
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; /* may be done already */
60 /* 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 if (maxarad <= FTINY)
71 maxarad = .001;
72 }
73
74
75 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 setambient(afile) /* initialize calculation */
94 char *afile;
95 {
96 long headlen;
97 AMBVAL amb;
98 /* init ambient limits */
99 setambres(ambres);
100 if (afile == NULL)
101 return;
102 if (ambacc <= FTINY) {
103 sprintf(errmsg, "zero ambient accuracy so \"%s\" not loaded",
104 afile);
105 error(WARNING, errmsg);
106 return;
107 }
108 /* open ambient file */
109 if ((ambfp = fopen(afile, "r+")) != NULL) {
110 initambfile(0);
111 headlen = ftell(ambfp);
112 while (readambval(&amb, ambfp))
113 avinsert(avstore(&amb), &atrunk,
114 thescene.cuorg, thescene.cusize);
115 /* 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 }
123 nunflshed++; /* lie */
124 ambsync();
125 }
126
127
128 ambnotify(obj) /* record new modifier */
129 OBJECT obj;
130 {
131 static int hitlimit = 0;
132 register OBJREC *o = objptr(obj);
133 register char **amblp;
134
135 if (hitlimit || !ismodifier(o->otype))
136 return;
137 for (amblp = amblist; *amblp != NULL; amblp++)
138 if (!strcmp(o->oname, *amblp)) {
139 if (ambset[0] >= MAXASET) {
140 error(WARNING, "too many modifiers in ambient list");
141 hitlimit++;
142 return; /* should this be fatal? */
143 }
144 insertelem(ambset, obj);
145 return;
146 }
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 double d;
156
157 if (ambdiv <= 0) /* no ambient calculation */
158 goto dumbamb;
159 /* check number of bounces */
160 if (rdepth >= ambounce)
161 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 rdepth++;
169 d = doambient(acol, r, r->rweight, NULL, NULL);
170 rdepth--;
171 if (d == 0.0)
172 goto dumbamb;
173 return;
174 }
175 /* get ambient value */
176 setcolor(acol, 0.0, 0.0, 0.0);
177 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 dumbamb: /* return global value */
188 copycolor(acol, ambval);
189 }
190
191
192 double
193 sumambient(acol, r, al, at, c0, s) /* get interpolated ambient value */
194 COLOR acol;
195 register RAY *r;
196 int al;
197 AMBTREE *at;
198 FVECT c0;
199 double s;
200 {
201 double d, e1, e2, wt, wsum;
202 COLOR ct;
203 FVECT ck0;
204 int i;
205 register int j;
206 register AMBVAL *av;
207 /* do this node */
208 wsum = 0.0;
209 for (av = at->alist; av != NULL; av = av->next) {
210 /*
211 * Ambient level test.
212 */
213 if (av->lvl > al || av->weight < r->rweight-FTINY)
214 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 if (d*0.5 < -minarad*ambacc-.001)
241 continue;
242 /*
243 * Jittering final test reduces image artifacts.
244 */
245 wt = sqrt(e1) + sqrt(e2);
246 wt *= .9 + .2*urand(9015+samplendx);
247 if (wt > ambacc)
248 continue;
249 if (wt <= 1e-3)
250 wt = 1e3;
251 else
252 wt = 1.0 / wt;
253 wsum += wt;
254 extambient(ct, av, r->rop, r->ron);
255 scalecolor(ct, wt);
256 addcolor(acol, ct);
257 }
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 wsum += sumambient(acol, r, al, at->kid+i, ck0, s);
274 }
275 return(wsum);
276 }
277
278
279 double
280 makeambient(acol, r, al) /* make a new ambient value */
281 COLOR acol;
282 register RAY *r;
283 int al;
284 {
285 AMBVAL amb;
286 FVECT gp, gd;
287 /* compute weight */
288 amb.weight = pow(AVGREFL, (double)al);
289 if (r->rweight < 0.2*amb.weight) /* heuristic */
290 amb.weight = r->rweight;
291 /* compute ambient */
292 amb.rad = doambient(acol, r, amb.weight, gp, gd);
293 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 amb.lvl = al;
299 copycolor(amb.val, acol);
300 VCOPY(amb.gpos, gp);
301 VCOPY(amb.gdir, gd);
302 /* insert into tree */
303 avsave(&amb); /* and save to file */
304 return(amb.rad);
305 }
306
307
308 extambient(cr, ap, pv, nv) /* extrapolate value at pv, nv */
309 COLOR cr;
310 register AMBVAL *ap;
311 FVECT pv, nv;
312 {
313 FVECT v1, v2;
314 register int i;
315 double d;
316
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 }
332
333
334 static
335 initambfile(creat) /* initialize ambient file */
336 int creat;
337 {
338 extern char *progname, *octname, VersionID[];
339
340 #ifdef F_SETLKW
341 aflock(creat ? F_WRLCK : F_RDLCK);
342 #endif
343 #ifdef MSDOS
344 setmode(fileno(ambfp), O_BINARY);
345 #endif
346 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 } else if (checkheader(ambfp, AMBFMT, NULL) < 0 || !hasambmagic(ambfp))
360 error(USER, "bad ambient file");
361 }
362
363
364 static
365 avsave(av) /* insert and save an ambient value */
366 AMBVAL *av;
367 {
368 avinsert(avstore(av), &atrunk, thescene.cuorg, thescene.cusize);
369 if (ambfp == NULL)
370 return;
371 if (writambval(av, ambfp) < 0)
372 goto writerr;
373 if (++nunflshed >= AMBFLUSH)
374 if (ambsync() == EOF)
375 goto writerr;
376 return;
377 writerr:
378 error(SYSTEM, "error writing ambient file");
379 }
380
381
382 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 static
396 avinsert(av, at, c0, s) /* insert ambient value in a tree */
397 register AMBVAL *av;
398 register AMBTREE *at;
399 FVECT c0;
400 double s;
401 {
402 FVECT ck0;
403 int branch;
404 register int i;
405
406 if (av->rad <= FTINY)
407 error(CONSISTENCY, "zero ambient radius in avinsert");
408 VCOPY(ck0, c0);
409 while (s*(OCTSCALE/2) > av->rad*ambacc) {
410 if (at->kid == NULL)
411 if ((at->kid = newambtree()) == NULL)
412 error(SYSTEM, "out of memory in avinsert");
413 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 }
425
426
427 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 #ifdef F_SETLKW
445
446 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 int
459 ambsync() /* synchronize ambient file */
460 {
461 static FILE *ambinp = NULL;
462 static long lastpos = -1;
463 long flen;
464 AMBVAL avs;
465 register int n;
466
467 if (nunflshed == 0)
468 return(0);
469 if (lastpos < 0) /* initializing (locked in initambfile) */
470 goto syncend;
471 /* gain exclusive access */
472 aflock(F_WRLCK);
473 /* see if file has grown */
474 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 if (ambinp == NULL) { /* use duplicate filedes */
478 ambinp = fdopen(dup(fileno(ambfp)), "r");
479 if (ambinp == NULL)
480 error(SYSTEM, "fdopen failed in ambsync");
481 }
482 if (fseek(ambinp, lastpos, 0) < 0)
483 error(SYSTEM, "fseek failed in ambsync");
484 while (n >= AMBVALSIZ) { /* load contributed values */
485 readambval(&avs, ambinp);
486 avinsert(avstore(&avs), &atrunk,
487 thescene.cuorg, thescene.cusize);
488 n -= AMBVALSIZ;
489 }
490 if (n) /* alignment */
491 lseek(fileno(ambfp), flen-n, 0);
492 }
493 syncend:
494 n = fflush(ambfp); /* calls write() at last */
495 lastpos = lseek(fileno(ambfp), 0L, 1);
496 aflock(F_UNLCK); /* release file */
497 nunflshed = 0;
498 return(n);
499 }
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 }
511
512 #endif