ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/ambient.c
Revision: 2.8
Committed: Thu Jul 16 14:03:27 1992 UTC (31 years, 9 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.7: +3 -2 lines
Log Message:
minor changes

File Contents

# User Rev Content
1 greg 1.14 /* Copyright (c) 1991 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     * The macro AMBFLUSH (if defined) is the number of ambient values
11     * to wait before flushing to the ambient file.
12     *
13     * 5/9/86
14     */
15    
16     #include "ray.h"
17    
18     #include "octree.h"
19    
20 greg 1.8 #include "otypes.h"
21    
22 greg 1.14 #include "ambient.h"
23    
24 greg 1.1 #include "random.h"
25    
26     #define OCTSCALE 0.5 /* ceil((valid rad.)/(cube size)) */
27    
28 greg 1.14 typedef struct ambtree {
29     AMBVAL *alist; /* ambient value list */
30     struct ambtree *kid; /* 8 child nodes */
31     } AMBTREE; /* ambient octree */
32    
33 greg 1.1 extern CUBE thescene; /* contains space boundaries */
34    
35 greg 1.11 #define MAXASET 511 /* maximum number of elements in ambient set */
36     OBJECT ambset[MAXASET+1]={0}; /* ambient include/exclude set */
37 greg 1.1
38     double maxarad; /* maximum ambient radius */
39     double minarad; /* minimum ambient radius */
40    
41     static AMBTREE atrunk; /* our ambient trunk node */
42    
43     static FILE *ambfp = NULL; /* ambient file pointer */
44 greg 2.7 static char *afname; /* ambient file name */
45     static long ambheadlen; /* length of ambient file header */
46 greg 1.1
47 greg 2.6 #define AMBFLUSH (BUFSIZ/AMBVALSIZ)
48    
49 greg 1.1 #define newambval() (AMBVAL *)bmalloc(sizeof(AMBVAL))
50    
51     #define newambtree() (AMBTREE *)calloc(8, sizeof(AMBTREE))
52    
53 greg 2.7 extern long ftell(), lseek();
54 greg 1.1
55 greg 2.7
56 greg 2.3 setambres(ar) /* set ambient resolution */
57     int ar;
58     {
59     /* set min & max radii */
60     if (ar <= 0) {
61     minarad = 0.0;
62     maxarad = thescene.cusize / 2.0;
63     } else {
64     minarad = thescene.cusize / ar;
65     maxarad = 16.0 * minarad; /* heuristic */
66     if (maxarad > thescene.cusize / 2.0)
67     maxarad = thescene.cusize / 2.0;
68     }
69 greg 2.4 if (maxarad <= FTINY)
70     maxarad = .001;
71 greg 2.3 }
72    
73    
74 greg 1.1 setambient(afile) /* initialize calculation */
75     char *afile;
76     {
77     AMBVAL amb;
78 greg 2.3 /* init ambient limits */
79     setambres(ambres);
80     /* open ambient file */
81 greg 2.7 if ((afname = afile) != NULL)
82 greg 1.1 if ((ambfp = fopen(afile, "r+")) != NULL) {
83 greg 2.6 initambfile(0);
84 greg 2.5 while (readambval(&amb, ambfp))
85 greg 1.1 avinsert(&amb, &atrunk, thescene.cuorg,
86     thescene.cusize);
87     /* align */
88 greg 2.6 fseek(ambfp, -((ftell(ambfp)-ambheadlen)%AMBVALSIZ), 1);
89     } else if ((ambfp = fopen(afile, "w")) != NULL)
90     initambfile(1);
91     else {
92 greg 1.1 sprintf(errmsg, "cannot open ambient file \"%s\"",
93     afile);
94     error(SYSTEM, errmsg);
95 greg 1.8 }
96     }
97    
98    
99 greg 2.6 initambfile(creat) /* initialize ambient file */
100     int creat;
101     {
102 greg 2.8 extern char *progname, *octname, VersionID[];
103 greg 2.6
104     setbuf(ambfp, bmalloc(BUFSIZ));
105     if (creat) { /* new file */
106     fprintf(ambfp, "%s -av %g %g %g -ab %d -aa %g ",
107     progname, colval(ambval,RED),
108     colval(ambval,GRN), colval(ambval,BLU),
109     ambounce, ambacc);
110     fprintf(ambfp, "-ad %d -as %d -ar %d %s\n",
111     ambdiv, ambssamp, ambres,
112     octname==NULL ? "" : octname);
113 greg 2.8 fprintf(ambfp, "SOFTWARE= %s\n", VersionID);
114 greg 2.6 fputformat(AMBFMT, ambfp);
115     putc('\n', ambfp);
116     putambmagic(ambfp);
117     fflush(ambfp);
118 greg 2.7 } else if (checkheader(ambfp, AMBFMT, NULL) < 0
119     || !hasambmagic(ambfp)) {
120     sprintf(errmsg, "\"%s\" is not an ambient file", afname);
121 greg 2.8 error(USER, errmsg);
122 greg 2.7 }
123 greg 2.6 ambheadlen = ftell(ambfp);
124     }
125    
126    
127 greg 1.8 ambnotify(obj) /* record new modifier */
128     OBJECT obj;
129     {
130 greg 1.11 static int hitlimit = 0;
131 greg 1.8 register OBJREC *o = objptr(obj);
132     register char **amblp;
133    
134 greg 1.11 if (hitlimit || !ismodifier(o->otype))
135 greg 1.8 return;
136     for (amblp = amblist; *amblp != NULL; amblp++)
137     if (!strcmp(o->oname, *amblp)) {
138 greg 1.11 if (ambset[0] >= MAXASET) {
139     error(WARNING, "too many modifiers in ambient list");
140     hitlimit++;
141     return; /* should this be fatal? */
142     }
143 greg 1.8 insertelem(ambset, obj);
144     return;
145 greg 1.1 }
146     }
147    
148    
149     ambient(acol, r) /* compute ambient component for ray */
150     COLOR acol;
151     register RAY *r;
152     {
153     static int rdepth = 0; /* ambient recursion */
154 greg 1.16 double d;
155 greg 1.1
156     if (ambdiv <= 0) /* no ambient calculation */
157     goto dumbamb;
158     /* check number of bounces */
159 greg 1.16 if (rdepth >= ambounce)
160 greg 1.1 goto dumbamb;
161     /* check ambient list */
162     if (ambincl != -1 && r->ro != NULL &&
163     ambincl != inset(ambset, r->ro->omod))
164     goto dumbamb;
165    
166     if (ambacc <= FTINY) { /* no ambient storage */
167 greg 1.16 rdepth++;
168     d = doambient(acol, r, r->rweight, NULL, NULL);
169     rdepth--;
170     if (d == 0.0)
171 greg 1.1 goto dumbamb;
172 greg 1.16 return;
173 greg 1.1 }
174     /* get ambient value */
175     setcolor(acol, 0.0, 0.0, 0.0);
176 greg 1.16 d = sumambient(acol, r, rdepth,
177     &atrunk, thescene.cuorg, thescene.cusize);
178     if (d > FTINY)
179     scalecolor(acol, 1.0/d);
180     else {
181     d = makeambient(acol, r, rdepth++);
182     rdepth--;
183     }
184     if (d > FTINY)
185     return;
186 greg 1.1 dumbamb: /* return global value */
187     copycolor(acol, ambval);
188     }
189    
190    
191     double
192 greg 1.16 sumambient(acol, r, al, at, c0, s) /* get interpolated ambient value */
193 greg 1.1 COLOR acol;
194     register RAY *r;
195 greg 1.16 int al;
196 greg 1.1 AMBTREE *at;
197     FVECT c0;
198     double s;
199     {
200     extern double sqrt();
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 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     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     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 greg 1.1 }
332    
333    
334     static
335 greg 2.7 avsave(av) /* insert and save an ambient value */
336 greg 1.1 AMBVAL *av;
337     {
338     static int nunflshed = 0;
339 greg 2.6
340 greg 2.7 avinsert(av, &atrunk, thescene.cuorg, thescene.cusize);
341 greg 1.1 if (ambfp == NULL)
342     return;
343 greg 2.5 if (writambval(av, ambfp) < 0)
344 greg 1.1 goto writerr;
345     if (++nunflshed >= AMBFLUSH) {
346 greg 2.7 if (ambsync() == EOF)
347 greg 1.1 goto writerr;
348     nunflshed = 0;
349     }
350     return;
351     writerr:
352     error(SYSTEM, "error writing ambient file");
353     }
354    
355    
356     static
357     avinsert(aval, at, c0, s) /* insert ambient value in a tree */
358     AMBVAL *aval;
359     register AMBTREE *at;
360     FVECT c0;
361     double s;
362     {
363     FVECT ck0;
364     int branch;
365     register AMBVAL *av;
366     register int i;
367    
368     if ((av = newambval()) == NULL)
369     goto memerr;
370 greg 1.9 copystruct(av, aval);
371 greg 1.1 VCOPY(ck0, c0);
372     while (s*(OCTSCALE/2) > av->rad*ambacc) {
373     if (at->kid == NULL)
374     if ((at->kid = newambtree()) == NULL)
375     goto memerr;
376     s *= 0.5;
377     branch = 0;
378     for (i = 0; i < 3; i++)
379     if (av->pos[i] > ck0[i] + s) {
380     ck0[i] += s;
381     branch |= 1 << i;
382     }
383     at = at->kid + branch;
384     }
385     av->next = at->alist;
386     at->alist = av;
387     return;
388     memerr:
389     error(SYSTEM, "out of memory in avinsert");
390 greg 2.7 }
391    
392    
393     #include <fcntl.h>
394    
395    
396     static
397     ambsync() /* synchronize ambient file */
398     {
399     static FILE *ambinp = NULL;
400     struct flock fls;
401     AMBVAL avs;
402     long lastpos, flen;
403     register int n;
404     /* gain exclusive access */
405     fls.l_type = F_WRLCK;
406     fls.l_whence = 0;
407     fls.l_start = 0L;
408     fls.l_len = 0L;
409     if (fcntl(fileno(ambfp), F_SETLKW, &fls) < 0)
410     error(SYSTEM, "cannot lock ambient file");
411     /* see if file has grown */
412     lastpos = lseek(fileno(ambfp), 0L, 2); /* may move pointer */
413     flen = lseek(fileno(ambfp), 0L, 1); /* new(?) file length */
414     if (n = (flen - lastpos)%AMBVALSIZ) /* assure alignment */
415     lseek(fileno(ambfp), flen -= n, 0);
416     if (n = (flen - lastpos)/AMBVALSIZ) { /* file has grown */
417     if (ambinp == NULL && (ambinp = fopen(afname, "r")) == NULL)
418     error(SYSTEM, "cannot reopen ambient file");
419     fseek(ambinp, lastpos, 0); /* go to previous position */
420     while (n--) { /* load contributed values */
421     readambval(&avs, ambinp);
422     avinsert(&avs,&atrunk,thescene.cuorg,thescene.cusize);
423     }
424     }
425     n = fflush(ambfp); /* calls write() at last */
426     fls.l_type = F_UNLCK; /* release file */
427     fcntl(fileno(ambfp), F_SETLKW, &fls);
428     return(n);
429 greg 1.1 }