ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/ambcomp.c
Revision: 2.23
Committed: Tue Feb 5 05:40:06 2013 UTC (11 years, 2 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.22: +22 -19 lines
Log Message:
Improved accuracy of ambient calculation for large -ad settings

File Contents

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