ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/ambcomp.c
Revision: 2.15
Committed: Sat May 28 22:27:54 2005 UTC (18 years, 11 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.14: +22 -24 lines
Log Message:
Fixed application of ray weights and coefficients in ambient calculation

File Contents

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