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

# Content
1 /* Copyright (c) 1991 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 * 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 #include "otypes.h"
21
22 #include "ambient.h"
23
24 #include "random.h"
25
26 #define OCTSCALE 0.5 /* ceil((valid rad.)/(cube size)) */
27
28 typedef struct ambtree {
29 AMBVAL *alist; /* ambient value list */
30 struct ambtree *kid; /* 8 child nodes */
31 } AMBTREE; /* ambient octree */
32
33 extern CUBE thescene; /* contains space boundaries */
34
35 #define MAXASET 511 /* maximum number of elements in ambient set */
36 OBJECT ambset[MAXASET+1]={0}; /* ambient include/exclude set */
37
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 static char *afname; /* ambient file name */
45 static long ambheadlen; /* length of ambient file header */
46
47 #define AMBFLUSH (BUFSIZ/AMBVALSIZ)
48
49 #define newambval() (AMBVAL *)bmalloc(sizeof(AMBVAL))
50
51 #define newambtree() (AMBTREE *)calloc(8, sizeof(AMBTREE))
52
53 extern long ftell(), lseek();
54
55
56 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 if (maxarad <= FTINY)
70 maxarad = .001;
71 }
72
73
74 setambient(afile) /* initialize calculation */
75 char *afile;
76 {
77 AMBVAL amb;
78 /* init ambient limits */
79 setambres(ambres);
80 /* open ambient file */
81 if ((afname = afile) != NULL)
82 if ((ambfp = fopen(afile, "r+")) != NULL) {
83 initambfile(0);
84 while (readambval(&amb, ambfp))
85 avinsert(&amb, &atrunk, thescene.cuorg,
86 thescene.cusize);
87 /* align */
88 fseek(ambfp, -((ftell(ambfp)-ambheadlen)%AMBVALSIZ), 1);
89 } else if ((ambfp = fopen(afile, "w")) != NULL)
90 initambfile(1);
91 else {
92 sprintf(errmsg, "cannot open ambient file \"%s\"",
93 afile);
94 error(SYSTEM, errmsg);
95 }
96 }
97
98
99 initambfile(creat) /* initialize ambient file */
100 int creat;
101 {
102 extern char *progname, *octname, VersionID[];
103
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 fprintf(ambfp, "SOFTWARE= %s\n", VersionID);
114 fputformat(AMBFMT, ambfp);
115 putc('\n', ambfp);
116 putambmagic(ambfp);
117 fflush(ambfp);
118 } else if (checkheader(ambfp, AMBFMT, NULL) < 0
119 || !hasambmagic(ambfp)) {
120 sprintf(errmsg, "\"%s\" is not an ambient file", afname);
121 error(USER, errmsg);
122 }
123 ambheadlen = ftell(ambfp);
124 }
125
126
127 ambnotify(obj) /* record new modifier */
128 OBJECT obj;
129 {
130 static int hitlimit = 0;
131 register OBJREC *o = objptr(obj);
132 register char **amblp;
133
134 if (hitlimit || !ismodifier(o->otype))
135 return;
136 for (amblp = amblist; *amblp != NULL; amblp++)
137 if (!strcmp(o->oname, *amblp)) {
138 if (ambset[0] >= MAXASET) {
139 error(WARNING, "too many modifiers in ambient list");
140 hitlimit++;
141 return; /* should this be fatal? */
142 }
143 insertelem(ambset, obj);
144 return;
145 }
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 double d;
155
156 if (ambdiv <= 0) /* no ambient calculation */
157 goto dumbamb;
158 /* check number of bounces */
159 if (rdepth >= ambounce)
160 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 rdepth++;
168 d = doambient(acol, r, r->rweight, NULL, NULL);
169 rdepth--;
170 if (d == 0.0)
171 goto dumbamb;
172 return;
173 }
174 /* get ambient value */
175 setcolor(acol, 0.0, 0.0, 0.0);
176 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 dumbamb: /* return global value */
187 copycolor(acol, ambval);
188 }
189
190
191 double
192 sumambient(acol, r, al, at, c0, s) /* get interpolated ambient value */
193 COLOR acol;
194 register RAY *r;
195 int al;
196 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 /* 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 avsave(av) /* insert and save an ambient value */
336 AMBVAL *av;
337 {
338 static int nunflshed = 0;
339
340 avinsert(av, &atrunk, thescene.cuorg, thescene.cusize);
341 if (ambfp == NULL)
342 return;
343 if (writambval(av, ambfp) < 0)
344 goto writerr;
345 if (++nunflshed >= AMBFLUSH) {
346 if (ambsync() == EOF)
347 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 copystruct(av, aval);
371 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 }
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 }