ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/ambient.c
Revision: 1.8
Committed: Fri Jan 12 11:30:59 1990 UTC (34 years, 3 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.7: +20 -14 lines
Log Message:
changed recording of ambient include/exclude set so instances work

File Contents

# Content
1 /* Copyright (c) 1986 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 "random.h"
23
24 #define OCTSCALE 0.5 /* ceil((valid rad.)/(cube size)) */
25
26 extern CUBE thescene; /* contains space boundaries */
27
28 extern COLOR ambval; /* global ambient component */
29 extern double ambacc; /* ambient accuracy */
30 extern int ambres; /* ambient resolution */
31 extern int ambdiv; /* number of divisions for calculation */
32 extern int ambssamp; /* number of super-samples */
33 extern int ambounce; /* number of ambient bounces */
34 extern char *amblist[]; /* ambient include/exclude list */
35 extern int ambincl; /* include == 1, exclude == 0 */
36
37 OBJECT ambset[256]={0}; /* ambient include/exclude set */
38
39 double maxarad; /* maximum ambient radius */
40 double minarad; /* minimum ambient radius */
41
42 typedef struct ambval {
43 FVECT pos; /* position in space */
44 FVECT dir; /* normal direction */
45 int lvl; /* recursion level of parent ray */
46 float weight; /* weight of parent ray */
47 COLOR val; /* computed ambient value */
48 float rad; /* validity radius */
49 struct ambval *next; /* next in list */
50 } AMBVAL; /* ambient value */
51
52 typedef struct ambtree {
53 AMBVAL *alist; /* ambient value list */
54 struct ambtree *kid; /* 8 child nodes */
55 } AMBTREE; /* ambient octree */
56
57 typedef struct {
58 float k; /* error contribution per sample */
59 COLOR v; /* ray sum */
60 int n; /* number of samples */
61 short t, p; /* theta, phi indices */
62 } AMBSAMP; /* ambient sample */
63
64 static AMBTREE atrunk; /* our ambient trunk node */
65
66 static FILE *ambfp = NULL; /* ambient file pointer */
67
68 #define newambval() (AMBVAL *)bmalloc(sizeof(AMBVAL))
69
70 #define newambtree() (AMBTREE *)calloc(8, sizeof(AMBTREE))
71
72 double sumambient(), doambient(), makeambient();
73
74
75 setambient(afile) /* initialize calculation */
76 char *afile;
77 {
78 long ftell();
79 OBJECT obj;
80 AMBVAL amb;
81
82 maxarad = thescene.cusize / 2.0; /* maximum radius */
83 /* minimum radius */
84 minarad = ambres > 0 ? thescene.cusize/ambres : 0.0;
85
86 /* open ambient file */
87 if (afile != NULL)
88 if ((ambfp = fopen(afile, "r+")) != NULL) {
89 while (fread(&amb, sizeof(AMBVAL), 1, ambfp) == 1)
90 avinsert(&amb, &atrunk, thescene.cuorg,
91 thescene.cusize);
92 /* align */
93 fseek(ambfp, -(ftell(ambfp)%sizeof(AMBVAL)), 1);
94 } else if ((ambfp = fopen(afile, "w")) == NULL) {
95 sprintf(errmsg, "cannot open ambient file \"%s\"",
96 afile);
97 error(SYSTEM, errmsg);
98 }
99 }
100
101
102 ambnotify(obj) /* record new modifier */
103 OBJECT obj;
104 {
105 register OBJREC *o = objptr(obj);
106 register char **amblp;
107
108 if (!ismodifier(o->otype))
109 return;
110 for (amblp = amblist; *amblp != NULL; amblp++)
111 if (!strcmp(o->oname, *amblp)) {
112 insertelem(ambset, obj);
113 return;
114 }
115 }
116
117
118 ambient(acol, r) /* compute ambient component for ray */
119 COLOR acol;
120 register RAY *r;
121 {
122 static int rdepth = 0; /* ambient recursion */
123 double wsum;
124
125 rdepth++; /* increment level */
126
127 if (ambdiv <= 0) /* no ambient calculation */
128 goto dumbamb;
129 /* check number of bounces */
130 if (rdepth > ambounce)
131 goto dumbamb;
132 /* check ambient list */
133 if (ambincl != -1 && r->ro != NULL &&
134 ambincl != inset(ambset, r->ro->omod))
135 goto dumbamb;
136
137 if (ambacc <= FTINY) { /* no ambient storage */
138 if (doambient(acol, r) == 0.0)
139 goto dumbamb;
140 goto done;
141 }
142 /* get ambient value */
143 setcolor(acol, 0.0, 0.0, 0.0);
144 wsum = sumambient(acol, r, &atrunk, thescene.cuorg, thescene.cusize);
145 if (wsum > FTINY)
146 scalecolor(acol, 1.0/wsum);
147 else if (makeambient(acol, r) == 0.0)
148 goto dumbamb;
149 goto done;
150
151 dumbamb: /* return global value */
152 copycolor(acol, ambval);
153 done: /* must finish here! */
154 rdepth--;
155 }
156
157
158 double
159 sumambient(acol, r, at, c0, s) /* get interpolated ambient value */
160 COLOR acol;
161 register RAY *r;
162 AMBTREE *at;
163 FVECT c0;
164 double s;
165 {
166 extern double sqrt();
167 double d, e1, e2, wt, wsum;
168 COLOR ct;
169 FVECT ck0;
170 int i;
171 register int j;
172 register AMBVAL *av;
173 /* do this node */
174 wsum = 0.0;
175 for (av = at->alist; av != NULL; av = av->next) {
176 /*
177 * Ray strength test.
178 */
179 if (av->lvl > r->rlvl || av->weight < r->rweight-FTINY)
180 continue;
181 /*
182 * Ambient radius test.
183 */
184 e1 = 0.0;
185 for (j = 0; j < 3; j++) {
186 d = av->pos[j] - r->rop[j];
187 e1 += d * d;
188 }
189 e1 /= av->rad * av->rad;
190 if (e1 > ambacc*ambacc*1.21)
191 continue;
192 /*
193 * Normal direction test.
194 */
195 e2 = (1.0 - DOT(av->dir, r->ron)) * r->rweight;
196 if (e2 < 0.0) e2 = 0.0;
197 if (e1 + e2 > ambacc*ambacc*1.21)
198 continue;
199 /*
200 * Ray behind test.
201 */
202 d = 0.0;
203 for (j = 0; j < 3; j++)
204 d += (r->rop[j] - av->pos[j]) *
205 (av->dir[j] + r->ron[j]);
206 if (d < -minarad)
207 continue;
208 /*
209 * Jittering final test reduces image artifacts.
210 */
211 wt = sqrt(e1) + sqrt(e2);
212 wt *= .9 + .2*frandom();
213 if (wt > ambacc)
214 continue;
215 if (wt <= 1e-3)
216 wt = 1e3;
217 else
218 wt = 1.0 / wt;
219 wsum += wt;
220 copycolor(ct, av->val);
221 scalecolor(ct, wt);
222 addcolor(acol, ct);
223 }
224 if (at->kid == NULL)
225 return(wsum);
226 /* do children */
227 s *= 0.5;
228 for (i = 0; i < 8; i++) {
229 for (j = 0; j < 3; j++) {
230 ck0[j] = c0[j];
231 if (1<<j & i)
232 ck0[j] += s;
233 if (r->rop[j] < ck0[j] - OCTSCALE*s)
234 break;
235 if (r->rop[j] > ck0[j] + (1.0+OCTSCALE)*s)
236 break;
237 }
238 if (j == 3)
239 wsum += sumambient(acol, r, at->kid+i, ck0, s);
240 }
241 return(wsum);
242 }
243
244
245 double
246 makeambient(acol, r) /* make a new ambient value */
247 COLOR acol;
248 register RAY *r;
249 {
250 AMBVAL amb;
251
252 amb.rad = doambient(acol, r); /* compute ambient */
253 if (amb.rad == 0.0)
254 return(0.0);
255 /* store it */
256 VCOPY(amb.pos, r->rop);
257 VCOPY(amb.dir, r->ron);
258 amb.lvl = r->rlvl;
259 amb.weight = r->rweight;
260 copycolor(amb.val, acol);
261 /* insert into tree */
262 avinsert(&amb, &atrunk, thescene.cuorg, thescene.cusize);
263 avsave(&amb); /* write to file */
264 return(amb.rad);
265 }
266
267
268 double
269 doambient(acol, r) /* compute ambient component */
270 COLOR acol;
271 register RAY *r;
272 {
273 extern int ambcmp();
274 extern double sin(), cos(), sqrt();
275 double phi, xd, yd, zd;
276 double b, b2;
277 register AMBSAMP *div;
278 AMBSAMP dnew;
279 RAY ar;
280 FVECT ux, uy;
281 double arad;
282 int ndivs, nt, np, ns, ne, i, j;
283 register int k;
284
285 setcolor(acol, 0.0, 0.0, 0.0);
286 /* set number of divisions */
287 nt = sqrt(ambdiv * r->rweight * 0.5) + 0.5;
288 np = 2 * nt;
289 ndivs = nt * np;
290 /* check first */
291 if (ndivs == 0 || rayorigin(&ar, r, AMBIENT, 0.5) < 0)
292 return(0.0);
293 /* set number of super-samples */
294 ns = ambssamp * r->rweight + 0.5;
295 if (ns > 0) {
296 div = (AMBSAMP *)malloc(ndivs*sizeof(AMBSAMP));
297 if (div == NULL)
298 error(SYSTEM, "out of memory in doambient");
299 }
300 /* make axes */
301 uy[0] = uy[1] = uy[2] = 0.0;
302 for (k = 0; k < 3; k++)
303 if (r->ron[k] < 0.6 && r->ron[k] > -0.6)
304 break;
305 uy[k] = 1.0;
306 fcross(ux, r->ron, uy);
307 normalize(ux);
308 fcross(uy, ux, r->ron);
309 /* sample divisions */
310 arad = 0.0;
311 ne = 0;
312 for (i = 0; i < nt; i++)
313 for (j = 0; j < np; j++) {
314 rayorigin(&ar, r, AMBIENT, 0.5); /* pretested */
315 zd = sqrt((i+frandom())/nt);
316 phi = 2.0*PI * (j+frandom())/np;
317 xd = cos(phi) * zd;
318 yd = sin(phi) * zd;
319 zd = sqrt(1.0 - zd*zd);
320 for (k = 0; k < 3; k++)
321 ar.rdir[k] = xd*ux[k]+yd*uy[k]+zd*r->ron[k];
322 rayvalue(&ar);
323 if (ar.rot < FHUGE)
324 arad += 1.0 / ar.rot;
325 if (ns > 0) { /* save division */
326 div[ne].k = 0.0;
327 copycolor(div[ne].v, ar.rcol);
328 div[ne].n = 0;
329 div[ne].t = i; div[ne].p = j;
330 /* sum errors */
331 b = bright(ar.rcol);
332 if (i > 0) { /* from above */
333 b2 = bright(div[ne-np].v) - b;
334 b2 *= b2 * 0.25;
335 div[ne].k += b2;
336 div[ne].n++;
337 div[ne-np].k += b2;
338 div[ne-np].n++;
339 }
340 if (j > 0) { /* from behind */
341 b2 = bright(div[ne-1].v) - b;
342 b2 *= b2 * 0.25;
343 div[ne].k += b2;
344 div[ne].n++;
345 div[ne-1].k += b2;
346 div[ne-1].n++;
347 }
348 if (j == np-1) { /* around */
349 b2 = bright(div[ne-(np-1)].v) - b;
350 b2 *= b2 * 0.25;
351 div[ne].k += b2;
352 div[ne].n++;
353 div[ne-(np-1)].k += b2;
354 div[ne-(np-1)].n++;
355 }
356 ne++;
357 } else
358 addcolor(acol, ar.rcol);
359 }
360 for (k = 0; k < ne; k++) { /* compute errors */
361 if (div[k].n > 1)
362 div[k].k /= div[k].n;
363 div[k].n = 1;
364 }
365 /* sort the divisions */
366 qsort(div, ne, sizeof(AMBSAMP), ambcmp);
367 /* skim excess */
368 while (ne > ns) {
369 ne--;
370 addcolor(acol, div[ne].v);
371 }
372 /* super-sample */
373 for (i = ns; i > 0; i--) {
374 rayorigin(&ar, r, AMBIENT, 0.5); /* pretested */
375 zd = sqrt((div[0].t+frandom())/nt);
376 phi = 2.0*PI * (div[0].p+frandom())/np;
377 xd = cos(phi) * zd;
378 yd = sin(phi) * zd;
379 zd = sqrt(1.0 - zd*zd);
380 for (k = 0; k < 3; k++)
381 ar.rdir[k] = xd*ux[k]+yd*uy[k]+zd*r->ron[k];
382 rayvalue(&ar);
383 if (ar.rot < FHUGE)
384 arad += 1.0 / ar.rot;
385 /* recompute error */
386 copycolor(dnew.v, div[0].v);
387 addcolor(dnew.v, ar.rcol);
388 dnew.n = div[0].n + 1;
389 dnew.t = div[0].t; dnew.p = div[0].p;
390 b2 = bright(dnew.v)/dnew.n - bright(ar.rcol);
391 b2 = b2*b2 + div[0].k*(div[0].n*div[0].n);
392 dnew.k = b2/(dnew.n*dnew.n);
393 /* reinsert */
394 for (k = 0; k < ne-1 && dnew.k < div[k+1].k; k++)
395 bcopy(&div[k+1], &div[k], sizeof(AMBSAMP));
396 bcopy(&dnew, &div[k], sizeof(AMBSAMP));
397
398 if (ne >= i) { /* extract darkest division */
399 ne--;
400 if (div[ne].n > 1)
401 scalecolor(div[ne].v, 1.0/div[ne].n);
402 addcolor(acol, div[ne].v);
403 }
404 }
405 scalecolor(acol, 1.0/ndivs);
406 if (arad <= FTINY)
407 arad = FHUGE;
408 else
409 arad = (ndivs+ns) / arad / sqrt(r->rweight);
410 if (arad > maxarad)
411 arad = maxarad;
412 else if (arad < minarad)
413 arad = minarad;
414 if (ns > 0)
415 free((char *)div);
416 return(arad);
417 }
418
419
420 static int
421 ambcmp(d1, d2) /* decreasing order */
422 AMBSAMP *d1, *d2;
423 {
424 if (d1->k < d2->k)
425 return(1);
426 if (d1->k > d2->k)
427 return(-1);
428 return(0);
429 }
430
431
432 static
433 avsave(av) /* save an ambient value */
434 AMBVAL *av;
435 {
436 #ifdef AMBFLUSH
437 static int nunflshed = 0;
438 #endif
439 if (ambfp == NULL)
440 return;
441 if (fwrite(av, sizeof(AMBVAL), 1, ambfp) != 1)
442 goto writerr;
443 #ifdef AMBFLUSH
444 if (++nunflshed >= AMBFLUSH) {
445 if (fflush(ambfp) == EOF)
446 goto writerr;
447 nunflshed = 0;
448 }
449 #endif
450 return;
451 writerr:
452 error(SYSTEM, "error writing ambient file");
453 }
454
455
456 static
457 avinsert(aval, at, c0, s) /* insert ambient value in a tree */
458 AMBVAL *aval;
459 register AMBTREE *at;
460 FVECT c0;
461 double s;
462 {
463 FVECT ck0;
464 int branch;
465 register AMBVAL *av;
466 register int i;
467
468 if ((av = newambval()) == NULL)
469 goto memerr;
470 bcopy(aval, av, sizeof(AMBVAL));
471 VCOPY(ck0, c0);
472 while (s*(OCTSCALE/2) > av->rad*ambacc) {
473 if (at->kid == NULL)
474 if ((at->kid = newambtree()) == NULL)
475 goto memerr;
476 s *= 0.5;
477 branch = 0;
478 for (i = 0; i < 3; i++)
479 if (av->pos[i] > ck0[i] + s) {
480 ck0[i] += s;
481 branch |= 1 << i;
482 }
483 at = at->kid + branch;
484 }
485 av->next = at->alist;
486 at->alist = av;
487 return;
488 memerr:
489 error(SYSTEM, "out of memory in avinsert");
490 }