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

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: ambcomp.c,v 2.22 2010/09/26 15:51:15 greg Exp $";
3 #endif
4 /*
5 * Routines to compute "ambient" values using Monte Carlo
6 *
7 * Declarations of external symbols in ambient.h
8 */
9
10 #include "copyright.h"
11
12 #include "ray.h"
13
14 #include "ambient.h"
15
16 #include "random.h"
17
18
19 void
20 inithemi( /* initialize sampling hemisphere */
21 AMBHEMI *hp,
22 COLOR ac,
23 RAY *r,
24 double wt
25 )
26 {
27 double d;
28 int i;
29 /* set number of divisions */
30 if (ambacc <= FTINY &&
31 wt > (d = 0.8*intens(ac)*r->rweight/(ambdiv*minweight)))
32 wt = d; /* avoid ray termination */
33 hp->nt = sqrt(ambdiv * wt / PI) + 0.5;
34 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 hp->ns = ambssamp * wt + 0.5;
40 /* assign coefficient */
41 copycolor(hp->acoef, ac);
42 d = 1.0/(hp->nt*hp->np);
43 scalecolor(hp->acoef, d);
44 /* 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 }
57
58
59 int
60 divsample( /* sample a division */
61 AMBSAMP *dp,
62 AMBHEMI *h,
63 RAY *r
64 )
65 {
66 RAY ar;
67 int hlist[3];
68 double spt[2];
69 double xd, yd, zd;
70 double b2;
71 double phi;
72 int i;
73 /* ambient coefficient for weight */
74 if (ambacc > FTINY)
75 setcolor(ar.rcoef, AVGREFL, AVGREFL, AVGREFL);
76 else
77 copycolor(ar.rcoef, h->acoef);
78 if (rayorigin(&ar, AMBIENT, r, ar.rcoef) < 0)
79 return(-1);
80 if (ambacc > FTINY) {
81 multcolor(ar.rcoef, h->acoef);
82 scalecolor(ar.rcoef, 1./AVGREFL);
83 }
84 hlist[0] = r->rno;
85 hlist[1] = dp->t;
86 hlist[2] = dp->p;
87 multisamp(spt, 2, urand(ilhash(hlist,3)+dp->n));
88 zd = sqrt((dp->t + spt[0])/h->nt);
89 phi = 2.0*PI * (dp->p + spt[1])/h->np;
90 xd = tcos(phi) * zd;
91 yd = tsin(phi) * zd;
92 zd = sqrt(1.0 - zd*zd);
93 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 checknorm(ar.rdir);
98 dimlist[ndims++] = dp->t*h->np + dp->p + 90171;
99 rayvalue(&ar);
100 ndims--;
101 multcolor(ar.rcol, ar.rcoef); /* apply coefficient */
102 addcolor(dp->v, ar.rcol);
103 /* use rt to improve gradient calc */
104 if (ar.rt > FTINY && ar.rt < FHUGE)
105 dp->r += 1.0/ar.rt;
106 /* (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 return(0);
114 }
115
116
117 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 int c;
143
144 if ( (c = d1->t - d2->t) )
145 return(c);
146 return(d1->p - d2->p);
147 }
148
149
150 double
151 doambient( /* compute ambient component */
152 COLOR rcol,
153 RAY *r,
154 double wt,
155 FVECT pg,
156 FVECT dg
157 )
158 {
159 double b, d;
160 AMBHEMI hemi;
161 AMBSAMP *div;
162 AMBSAMP dnew;
163 double acol[3];
164 AMBSAMP *dp;
165 double arad;
166 int divcnt;
167 int i, j;
168 /* initialize hemisphere */
169 inithemi(&hemi, rcol, r, wt);
170 divcnt = hemi.nt * hemi.np;
171 /* 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 setcolor(rcol, 0.0, 0.0, 0.0);
177 if (divcnt == 0)
178 return(0.0);
179 /* allocate super-samples */
180 if (hemi.ns > 0 || pg != NULL || dg != NULL) {
181 div = (AMBSAMP *)malloc(divcnt*sizeof(AMBSAMP));
182 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 acol[0] = acol[1] = acol[2] = 0.0;
189 if ((dp = div) == NULL)
190 dp = &dnew;
191 divcnt = 0;
192 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 dp->r = 0.0;
197 dp->n = 0;
198 if (divsample(dp, &hemi, r) < 0) {
199 if (div != NULL)
200 dp++;
201 continue;
202 }
203 arad += dp->r;
204 divcnt++;
205 if (div != NULL)
206 dp++;
207 else
208 addcolor(acol, dp->v);
209 }
210 if (!divcnt) {
211 if (div != NULL)
212 free((void *)div);
213 return(0.0); /* no samples taken */
214 }
215 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 hemi.ns = 0; /* close enough */
220 } else if (hemi.ns > 0) { /* else perform super-sampling? */
221 comperrs(div, &hemi); /* compute errors */
222 qsort(div, divcnt, sizeof(AMBSAMP), ambcmp); /* sort divs */
223 /* super-sample */
224 for (i = hemi.ns; i > 0; i--) {
225 dnew = *div;
226 if (divsample(&dnew, &hemi, r) < 0) {
227 dp++;
228 continue;
229 }
230 dp = div; /* reinsert */
231 j = divcnt < i ? divcnt : i;
232 while (--j > 0 && dnew.k < dp[1].k) {
233 *dp = *(dp+1);
234 dp++;
235 }
236 *dp = dnew;
237 }
238 if (pg != NULL || dg != NULL) /* restore order */
239 qsort(div, divcnt, sizeof(AMBSAMP), ambnorm);
240 }
241 /* compute returned values */
242 if (div != NULL) {
243 arad = 0.0; /* note: divcnt may be < nt*np */
244 for (i = hemi.nt*hemi.np, dp = div; i-- > 0; dp++) {
245 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 b = bright(acol);
255 if (b > FTINY) {
256 b = 1.0/b; /* compute & normalize gradient(s) */
257 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 }
268 free((void *)div);
269 }
270 copycolor(rcol, acol);
271 if (arad <= FTINY)
272 arad = maxarad;
273 else
274 arad = (divcnt+hemi.ns)/arad;
275 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 if (arad < minarad) {
281 arad = minarad;
282 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 if ((arad /= sqrt(wt)) > maxarad)
289 arad = maxarad;
290 return(arad);
291 }
292
293
294 void
295 comperrs( /* compute initial error estimates */
296 AMBSAMP *da, /* assumes standard ordering */
297 AMBHEMI *hp
298 )
299 {
300 double b, b2;
301 int i, j;
302 AMBSAMP *dp;
303 /* sum differences from neighbors */
304 dp = da;
305 for (i = 0; i < hp->nt; i++)
306 for (j = 0; j < hp->np; j++) {
307 #ifdef DEBUG
308 if (dp->t != i || dp->p != j)
309 error(CONSISTENCY,
310 "division order in comperrs");
311 #endif
312 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 } else { /* around */
325 b2 = bright(dp[hp->np-1].v) - b;
326 b2 *= b2 * 0.25;
327 dp[0].k += b2;
328 dp[hp->np-1].k += b2;
329 }
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 void
347 posgradient( /* compute position gradient */
348 FVECT gv,
349 AMBSAMP *da, /* assumes standard ordering */
350 AMBHEMI *hp
351 )
352 {
353 int i, j;
354 double nextsine, lastsine, b, d;
355 double mag0, mag1;
356 double phi, cosp, sinp, xd, yd;
357 AMBSAMP *dp;
358
359 xd = yd = 0.0;
360 for (j = 0; j < hp->np; j++) {
361 dp = da + j;
362 mag0 = mag1 = 0.0;
363 lastsine = 0.0;
364 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 /* sin(t)*cos(t)^2 */
375 d *= lastsine * (1.0 - (double)i/hp->nt);
376 mag0 += d*(b - bright(dp[-hp->np].v));
377 }
378 nextsine = sqrt((double)(i+1)/hp->nt);
379 if (j > 0) {
380 d = dp[-1].r;
381 if (dp[0].r > d) d = dp[0].r;
382 mag1 += d * (nextsine - lastsine) *
383 (b - bright(dp[-1].v));
384 } else {
385 d = dp[hp->np-1].r;
386 if (dp[0].r > d) d = dp[0].r;
387 mag1 += d * (nextsine - lastsine) *
388 (b - bright(dp[hp->np-1].v));
389 }
390 dp += hp->np;
391 lastsine = nextsine;
392 }
393 mag0 *= 2.0*PI / hp->np;
394 phi = 2.0*PI * (double)j/hp->np;
395 cosp = tcos(phi); sinp = tsin(phi);
396 xd += mag0*cosp - mag1*sinp;
397 yd += mag0*sinp + mag1*cosp;
398 }
399 for (i = 0; i < 3; i++)
400 gv[i] = (xd*hp->ux[i] + yd*hp->uy[i])*(hp->nt*hp->np)/PI;
401 }
402
403
404 void
405 dirgradient( /* compute direction gradient */
406 FVECT gv,
407 AMBSAMP *da, /* assumes standard ordering */
408 AMBHEMI *hp
409 )
410 {
411 int i, j;
412 double mag;
413 double phi, xd, yd;
414 AMBSAMP *dp;
415
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 /* tan(t) */
427 mag += bright(dp->v)/sqrt(hp->nt/(i+.5) - 1.0);
428 dp += hp->np;
429 }
430 phi = 2.0*PI * (j+.5)/hp->np + PI/2.0;
431 xd += mag * tcos(phi);
432 yd += mag * tsin(phi);
433 }
434 for (i = 0; i < 3; i++)
435 gv[i] = xd*hp->ux[i] + yd*hp->uy[i];
436 }