ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/ambcomp.c
Revision: 2.14
Committed: Tue Apr 19 01:15:06 2005 UTC (19 years ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.13: +105 -74 lines
Log Message:
Extensive changes to enable rtrace -oTW option for tracking ray contributions

File Contents

# User Rev Content
1 greg 1.1 #ifndef lint
2 greg 2.14 static const char RCSid[] = "$Id: ambcomp.c,v 2.13 2005/04/13 23:00:59 greg Exp $";
3 greg 1.1 #endif
4     /*
5     * Routines to compute "ambient" values using Monte Carlo
6 greg 2.9 *
7     * Declarations of external symbols in ambient.h
8     */
9    
10 greg 2.10 #include "copyright.h"
11 greg 1.1
12     #include "ray.h"
13    
14     #include "ambient.h"
15    
16     #include "random.h"
17    
18    
19 greg 2.14 int
20     inithemi( /* initialize sampling hemisphere */
21     register AMBHEMI *hp,
22     RAY *r,
23     COLOR ac,
24     double wt
25     )
26 greg 1.1 {
27 greg 2.14 int ns;
28     double d;
29     register int i;
30     /* set number of divisions */
31     hp->nt = sqrt(ambdiv * wt / PI) + 0.5;
32     i = ambacc > FTINY ? 3 : 1; /* minimum number of samples */
33     if (hp->nt < i)
34     hp->nt = i;
35     hp->np = PI * hp->nt + 0.5;
36     /* set number of super-samples */
37     ns = ambssamp * wt + 0.5;
38     /* assign coefficient */
39     d = 1.0/(hp->nt*hp->np + ns); /* XXX weight not uniform if ns > 0 */
40     copycolor(hp->acoef, ac);
41     scalecolor(hp->acoef, d);
42     /* make axes */
43     VCOPY(hp->uz, r->ron);
44     hp->uy[0] = hp->uy[1] = hp->uy[2] = 0.0;
45     for (i = 0; i < 3; i++)
46     if (hp->uz[i] < 0.6 && hp->uz[i] > -0.6)
47     break;
48     if (i >= 3)
49     error(CONSISTENCY, "bad ray direction in inithemi");
50     hp->uy[i] = 1.0;
51     fcross(hp->ux, hp->uy, hp->uz);
52     normalize(hp->ux);
53     fcross(hp->uy, hp->uz, hp->ux);
54     return(ns);
55 greg 1.1 }
56    
57    
58 greg 2.9 int
59 greg 2.14 divsample( /* sample a division */
60     register AMBSAMP *dp,
61     AMBHEMI *h,
62     RAY *r
63     )
64 greg 1.1 {
65     RAY ar;
66 greg 1.11 int hlist[3];
67     double spt[2];
68 greg 1.1 double xd, yd, zd;
69     double b2;
70     double phi;
71 greg 1.2 register int i;
72 greg 2.14 /* assign coefficient */
73     if (ambacc <= FTINY) /* no storage, so report accurately */
74     copycolor(ar.rcoef, h->acoef);
75     else /* else lie for sake of cache */
76     setcolor(ar.rcoef, AVGREFL, AVGREFL, AVGREFL);
77     if (rayorigin(&ar, AMBIENT, r, ar.rcoef) < 0)
78 greg 1.4 return(-1);
79 greg 2.14 copycolor(ar.rcoef, h->acoef); /* correct coefficient rtrace output */
80 greg 1.1 hlist[0] = r->rno;
81     hlist[1] = dp->t;
82     hlist[2] = dp->p;
83 greg 1.13 multisamp(spt, 2, urand(ilhash(hlist,3)+dp->n));
84 greg 1.11 zd = sqrt((dp->t + spt[0])/h->nt);
85     phi = 2.0*PI * (dp->p + spt[1])/h->np;
86 gwlarson 2.8 xd = tcos(phi) * zd;
87     yd = tsin(phi) * zd;
88 greg 1.1 zd = sqrt(1.0 - zd*zd);
89 greg 1.2 for (i = 0; i < 3; i++)
90     ar.rdir[i] = xd*h->ux[i] +
91     yd*h->uy[i] +
92     zd*h->uz[i];
93     dimlist[ndims++] = dp->t*h->np + dp->p + 90171;
94 greg 1.1 rayvalue(&ar);
95     ndims--;
96     addcolor(dp->v, ar.rcol);
97 greg 2.9 /* use rt to improve gradient calc */
98     if (ar.rt > FTINY && ar.rt < FHUGE)
99     dp->r += 1.0/ar.rt;
100 greg 1.1 /* (re)initialize error */
101     if (dp->n++) {
102     b2 = bright(dp->v)/dp->n - bright(ar.rcol);
103     b2 = b2*b2 + dp->k*((dp->n-1)*(dp->n-1));
104     dp->k = b2/(dp->n*dp->n);
105     } else
106     dp->k = 0.0;
107 greg 1.4 return(0);
108 greg 1.1 }
109    
110    
111 greg 2.14 static int
112     ambcmp( /* decreasing order */
113     const void *p1,
114     const void *p2
115     )
116     {
117     const AMBSAMP *d1 = (const AMBSAMP *)p1;
118     const AMBSAMP *d2 = (const AMBSAMP *)p2;
119    
120     if (d1->k < d2->k)
121     return(1);
122     if (d1->k > d2->k)
123     return(-1);
124     return(0);
125     }
126    
127    
128     static int
129     ambnorm( /* standard order */
130     const void *p1,
131     const void *p2
132     )
133     {
134     const AMBSAMP *d1 = (const AMBSAMP *)p1;
135     const AMBSAMP *d2 = (const AMBSAMP *)p2;
136     register int c;
137    
138     if ( (c = d1->t - d2->t) )
139     return(c);
140     return(d1->p - d2->p);
141     }
142    
143    
144 greg 1.1 double
145 greg 2.14 doambient( /* compute ambient component */
146     COLOR acol,
147     RAY *r,
148     COLOR ac,
149     double wt,
150     FVECT pg,
151     FVECT dg
152     )
153 greg 1.1 {
154     double b, d;
155     AMBHEMI hemi;
156     AMBSAMP *div;
157     AMBSAMP dnew;
158     register AMBSAMP *dp;
159     double arad;
160     int ndivs, ns;
161     register int i, j;
162     /* initialize color */
163     setcolor(acol, 0.0, 0.0, 0.0);
164     /* initialize hemisphere */
165 greg 2.14 ns = inithemi(&hemi, r, ac, wt);
166 greg 1.1 ndivs = hemi.nt * hemi.np;
167     if (ndivs == 0)
168     return(0.0);
169 greg 2.14 /* allocate super-samples */
170 greg 1.1 if (ns > 0 || pg != NULL || dg != NULL) {
171     div = (AMBSAMP *)malloc(ndivs*sizeof(AMBSAMP));
172     if (div == NULL)
173     error(SYSTEM, "out of memory in doambient");
174     } else
175     div = NULL;
176     /* sample the divisions */
177     arad = 0.0;
178     if ((dp = div) == NULL)
179     dp = &dnew;
180     for (i = 0; i < hemi.nt; i++)
181     for (j = 0; j < hemi.np; j++) {
182     dp->t = i; dp->p = j;
183     setcolor(dp->v, 0.0, 0.0, 0.0);
184 greg 1.2 dp->r = 0.0;
185 greg 1.1 dp->n = 0;
186 greg 1.4 if (divsample(dp, &hemi, r) < 0)
187 greg 1.1 goto oopsy;
188 greg 2.6 arad += dp->r;
189 greg 1.1 if (div != NULL)
190     dp++;
191 greg 2.6 else
192 greg 1.1 addcolor(acol, dp->v);
193     }
194 greg 2.5 if (ns > 0 && arad > FTINY && ndivs/arad < minarad)
195     ns = 0; /* close enough */
196     else if (ns > 0) { /* else perform super-sampling */
197 greg 1.4 comperrs(div, &hemi); /* compute errors */
198 greg 1.1 qsort(div, ndivs, sizeof(AMBSAMP), ambcmp); /* sort divs */
199     /* super-sample */
200     for (i = ns; i > 0; i--) {
201 schorsch 2.11 dnew = *div;
202 greg 1.4 if (divsample(&dnew, &hemi, r) < 0)
203 greg 1.1 goto oopsy;
204     /* reinsert */
205     dp = div;
206     j = ndivs < i ? ndivs : i;
207     while (--j > 0 && dnew.k < dp[1].k) {
208 schorsch 2.11 *dp = *(dp+1);
209 greg 1.1 dp++;
210     }
211 schorsch 2.11 *dp = dnew;
212 greg 1.1 }
213 greg 1.2 if (pg != NULL || dg != NULL) /* restore order */
214 greg 1.1 qsort(div, ndivs, sizeof(AMBSAMP), ambnorm);
215     }
216     /* compute returned values */
217 greg 1.3 if (div != NULL) {
218 greg 2.6 arad = 0.0;
219 greg 1.3 for (i = ndivs, dp = div; i-- > 0; dp++) {
220     arad += dp->r;
221     if (dp->n > 1) {
222     b = 1.0/dp->n;
223     scalecolor(dp->v, b);
224     dp->r *= b;
225     dp->n = 1;
226     }
227     addcolor(acol, dp->v);
228     }
229 greg 1.5 b = bright(acol);
230 greg 1.6 if (b > FTINY) {
231 greg 1.5 b = ndivs/b;
232 greg 1.6 if (pg != NULL) {
233     posgradient(pg, div, &hemi);
234     for (i = 0; i < 3; i++)
235     pg[i] *= b;
236     }
237     if (dg != NULL) {
238     dirgradient(dg, div, &hemi);
239     for (i = 0; i < 3; i++)
240     dg[i] *= b;
241     }
242     } else {
243     if (pg != NULL)
244     for (i = 0; i < 3; i++)
245     pg[i] = 0.0;
246     if (dg != NULL)
247     for (i = 0; i < 3; i++)
248     dg[i] = 0.0;
249 greg 1.5 }
250 greg 2.9 free((void *)div);
251 greg 1.3 }
252 greg 1.1 b = 1.0/ndivs;
253     scalecolor(acol, b);
254     if (arad <= FTINY)
255 greg 1.16 arad = maxarad;
256 greg 2.3 else
257 greg 1.1 arad = (ndivs+ns)/arad;
258 greg 1.15 if (pg != NULL) { /* reduce radius if gradient large */
259     d = DOT(pg,pg);
260     if (d*arad*arad > 1.0)
261     arad = 1.0/sqrt(d);
262     }
263 greg 1.16 if (arad < minarad) {
264 greg 1.1 arad = minarad;
265 greg 1.16 if (pg != NULL && d*arad*arad > 1.0) { /* cap gradient */
266     d = 1.0/arad/sqrt(d);
267     for (i = 0; i < 3; i++)
268     pg[i] *= d;
269     }
270     }
271 greg 2.3 if ((arad /= sqrt(wt)) > maxarad)
272     arad = maxarad;
273     return(arad);
274 greg 1.1 oopsy:
275     if (div != NULL)
276 greg 2.9 free((void *)div);
277 greg 1.1 return(0.0);
278     }
279    
280    
281 greg 2.9 void
282 greg 2.14 comperrs( /* compute initial error estimates */
283     AMBSAMP *da, /* assumes standard ordering */
284     register AMBHEMI *hp
285     )
286 greg 1.1 {
287     double b, b2;
288     int i, j;
289     register AMBSAMP *dp;
290     /* sum differences from neighbors */
291     dp = da;
292     for (i = 0; i < hp->nt; i++)
293     for (j = 0; j < hp->np; j++) {
294 greg 1.6 #ifdef DEBUG
295     if (dp->t != i || dp->p != j)
296     error(CONSISTENCY,
297     "division order in comperrs");
298     #endif
299 greg 1.1 b = bright(dp[0].v);
300     if (i > 0) { /* from above */
301     b2 = bright(dp[-hp->np].v) - b;
302     b2 *= b2 * 0.25;
303     dp[0].k += b2;
304     dp[-hp->np].k += b2;
305     }
306     if (j > 0) { /* from behind */
307     b2 = bright(dp[-1].v) - b;
308     b2 *= b2 * 0.25;
309     dp[0].k += b2;
310     dp[-1].k += b2;
311 greg 1.4 } else { /* around */
312     b2 = bright(dp[hp->np-1].v) - b;
313 greg 1.1 b2 *= b2 * 0.25;
314     dp[0].k += b2;
315 greg 1.4 dp[hp->np-1].k += b2;
316 greg 1.1 }
317     dp++;
318     }
319     /* divide by number of neighbors */
320     dp = da;
321     for (j = 0; j < hp->np; j++) /* top row */
322     (dp++)->k *= 1.0/3.0;
323     if (hp->nt < 2)
324     return;
325     for (i = 1; i < hp->nt-1; i++) /* central region */
326     for (j = 0; j < hp->np; j++)
327     (dp++)->k *= 0.25;
328     for (j = 0; j < hp->np; j++) /* bottom row */
329     (dp++)->k *= 1.0/3.0;
330     }
331    
332    
333 greg 2.9 void
334 greg 2.14 posgradient( /* compute position gradient */
335     FVECT gv,
336     AMBSAMP *da, /* assumes standard ordering */
337     register AMBHEMI *hp
338     )
339 greg 1.1 {
340 greg 1.2 register int i, j;
341 greg 2.2 double nextsine, lastsine, b, d;
342 greg 1.2 double mag0, mag1;
343     double phi, cosp, sinp, xd, yd;
344     register AMBSAMP *dp;
345    
346     xd = yd = 0.0;
347     for (j = 0; j < hp->np; j++) {
348     dp = da + j;
349     mag0 = mag1 = 0.0;
350 greg 2.2 lastsine = 0.0;
351 greg 1.2 for (i = 0; i < hp->nt; i++) {
352     #ifdef DEBUG
353     if (dp->t != i || dp->p != j)
354     error(CONSISTENCY,
355     "division order in posgradient");
356     #endif
357     b = bright(dp->v);
358     if (i > 0) {
359     d = dp[-hp->np].r;
360     if (dp[0].r > d) d = dp[0].r;
361 greg 2.2 /* sin(t)*cos(t)^2 */
362     d *= lastsine * (1.0 - (double)i/hp->nt);
363 greg 1.2 mag0 += d*(b - bright(dp[-hp->np].v));
364     }
365 greg 2.2 nextsine = sqrt((double)(i+1)/hp->nt);
366 greg 1.2 if (j > 0) {
367     d = dp[-1].r;
368     if (dp[0].r > d) d = dp[0].r;
369 greg 2.2 mag1 += d * (nextsine - lastsine) *
370     (b - bright(dp[-1].v));
371 greg 1.2 } else {
372     d = dp[hp->np-1].r;
373     if (dp[0].r > d) d = dp[0].r;
374 greg 2.2 mag1 += d * (nextsine - lastsine) *
375     (b - bright(dp[hp->np-1].v));
376 greg 1.2 }
377     dp += hp->np;
378 greg 2.2 lastsine = nextsine;
379 greg 1.2 }
380 greg 2.2 mag0 *= 2.0*PI / hp->np;
381 greg 1.2 phi = 2.0*PI * (double)j/hp->np;
382 gwlarson 2.8 cosp = tcos(phi); sinp = tsin(phi);
383 greg 1.2 xd += mag0*cosp - mag1*sinp;
384     yd += mag0*sinp + mag1*cosp;
385     }
386     for (i = 0; i < 3; i++)
387 greg 1.5 gv[i] = (xd*hp->ux[i] + yd*hp->uy[i])/PI;
388 greg 1.1 }
389    
390    
391 greg 2.9 void
392 greg 2.14 dirgradient( /* compute direction gradient */
393     FVECT gv,
394     AMBSAMP *da, /* assumes standard ordering */
395     register AMBHEMI *hp
396     )
397 greg 1.1 {
398 greg 1.2 register int i, j;
399     double mag;
400     double phi, xd, yd;
401     register AMBSAMP *dp;
402    
403     xd = yd = 0.0;
404     for (j = 0; j < hp->np; j++) {
405     dp = da + j;
406     mag = 0.0;
407     for (i = 0; i < hp->nt; i++) {
408     #ifdef DEBUG
409     if (dp->t != i || dp->p != j)
410     error(CONSISTENCY,
411     "division order in dirgradient");
412     #endif
413 greg 2.2 /* tan(t) */
414     mag += bright(dp->v)/sqrt(hp->nt/(i+.5) - 1.0);
415 greg 1.2 dp += hp->np;
416     }
417     phi = 2.0*PI * (j+.5)/hp->np + PI/2.0;
418 gwlarson 2.8 xd += mag * tcos(phi);
419     yd += mag * tsin(phi);
420 greg 1.2 }
421     for (i = 0; i < 3; i++)
422 greg 2.2 gv[i] = (xd*hp->ux[i] + yd*hp->uy[i])/(hp->nt*hp->np);
423 greg 1.1 }