ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/ambcomp.c
Revision: 2.17
Committed: Sat Jun 4 06:10:12 2005 UTC (18 years, 10 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.16: +13 -12 lines
Log Message:
Bug fix for -aa 0 -as > 0

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: ambcomp.c,v 2.16 2005/05/31 18:01:09 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 register AMBHEMI *hp,
22 COLOR ac,
23 RAY *r,
24 double wt
25 )
26 {
27 double d;
28 register int i;
29 /* set number of divisions */
30 if (ambacc <= FTINY &&
31 wt > (d = 0.8*bright(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 register 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 register 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 dimlist[ndims++] = dp->t*h->np + dp->p + 90171;
98 rayvalue(&ar);
99 ndims--;
100 multcolor(ar.rcol, ar.rcoef); /* apply coefficient */
101 addcolor(dp->v, ar.rcol);
102 /* use rt to improve gradient calc */
103 if (ar.rt > FTINY && ar.rt < FHUGE)
104 dp->r += 1.0/ar.rt;
105 /* (re)initialize error */
106 if (dp->n++) {
107 b2 = bright(dp->v)/dp->n - bright(ar.rcol);
108 b2 = b2*b2 + dp->k*((dp->n-1)*(dp->n-1));
109 dp->k = b2/(dp->n*dp->n);
110 } else
111 dp->k = 0.0;
112 return(0);
113 }
114
115
116 static int
117 ambcmp( /* decreasing order */
118 const void *p1,
119 const void *p2
120 )
121 {
122 const AMBSAMP *d1 = (const AMBSAMP *)p1;
123 const AMBSAMP *d2 = (const AMBSAMP *)p2;
124
125 if (d1->k < d2->k)
126 return(1);
127 if (d1->k > d2->k)
128 return(-1);
129 return(0);
130 }
131
132
133 static int
134 ambnorm( /* standard order */
135 const void *p1,
136 const void *p2
137 )
138 {
139 const AMBSAMP *d1 = (const AMBSAMP *)p1;
140 const AMBSAMP *d2 = (const AMBSAMP *)p2;
141 register int c;
142
143 if ( (c = d1->t - d2->t) )
144 return(c);
145 return(d1->p - d2->p);
146 }
147
148
149 double
150 doambient( /* compute ambient component */
151 COLOR acol,
152 RAY *r,
153 double wt,
154 FVECT pg,
155 FVECT dg
156 )
157 {
158 double b, d;
159 AMBHEMI hemi;
160 AMBSAMP *div;
161 AMBSAMP dnew;
162 register AMBSAMP *dp;
163 double arad;
164 int ndivs;
165 register int i, j;
166 /* initialize hemisphere */
167 inithemi(&hemi, acol, r, wt);
168 ndivs = hemi.nt * hemi.np;
169 /* initialize */
170 if (pg != NULL)
171 pg[0] = pg[1] = pg[2] = 0.0;
172 if (dg != NULL)
173 dg[0] = dg[1] = dg[2] = 0.0;
174 setcolor(acol, 0.0, 0.0, 0.0);
175 if (ndivs == 0)
176 return(0.0);
177 /* allocate super-samples */
178 if (hemi.ns > 0 || pg != NULL || dg != NULL) {
179 div = (AMBSAMP *)malloc(ndivs*sizeof(AMBSAMP));
180 if (div == NULL)
181 error(SYSTEM, "out of memory in doambient");
182 } else
183 div = NULL;
184 /* sample the divisions */
185 arad = 0.0;
186 if ((dp = div) == NULL)
187 dp = &dnew;
188 for (i = 0; i < hemi.nt; i++)
189 for (j = 0; j < hemi.np; j++) {
190 dp->t = i; dp->p = j;
191 setcolor(dp->v, 0.0, 0.0, 0.0);
192 dp->r = 0.0;
193 dp->n = 0;
194 if (divsample(dp, &hemi, r) < 0) {
195 if (div != NULL) dp++;
196 hemi.ns = 0; /* incomplete sampling */
197 pg = dg = NULL;
198 continue;
199 }
200 arad += dp->r;
201 if (div != NULL)
202 dp++;
203 else
204 addcolor(acol, dp->v);
205 }
206 if (hemi.ns > 0 && arad > FTINY && ndivs/arad < minarad)
207 hemi.ns = 0; /* close enough */
208 else if (hemi.ns > 0) { /* else perform super-sampling */
209 comperrs(div, &hemi); /* compute errors */
210 qsort(div, ndivs, sizeof(AMBSAMP), ambcmp); /* sort divs */
211 /* super-sample */
212 for (i = hemi.ns; i > 0; i--) {
213 dnew = *div;
214 if (divsample(&dnew, &hemi, r) < 0) {
215 dp++;
216 continue;
217 }
218 dp = div; /* reinsert */
219 j = ndivs < i ? ndivs : i;
220 while (--j > 0 && dnew.k < dp[1].k) {
221 *dp = *(dp+1);
222 dp++;
223 }
224 *dp = dnew;
225 }
226 if (pg != NULL || dg != NULL) /* restore order */
227 qsort(div, ndivs, sizeof(AMBSAMP), ambnorm);
228 }
229 /* compute returned values */
230 if (div != NULL) {
231 arad = 0.0;
232 for (i = ndivs, dp = div; i-- > 0; dp++) {
233 arad += dp->r;
234 if (dp->n > 1) {
235 b = 1.0/dp->n;
236 scalecolor(dp->v, b);
237 dp->r *= b;
238 dp->n = 1;
239 }
240 addcolor(acol, dp->v);
241 }
242 b = bright(acol);
243 if (b > FTINY) {
244 b = 1.0/b; /* compute & normalize gradient(s) */
245 if (pg != NULL) {
246 posgradient(pg, div, &hemi);
247 for (i = 0; i < 3; i++)
248 pg[i] *= b;
249 }
250 if (dg != NULL) {
251 dirgradient(dg, div, &hemi);
252 for (i = 0; i < 3; i++)
253 dg[i] *= b;
254 }
255 }
256 free((void *)div);
257 }
258 if (arad <= FTINY)
259 arad = maxarad;
260 else
261 arad = (ndivs+hemi.ns)/arad;
262 if (pg != NULL) { /* reduce radius if gradient large */
263 d = DOT(pg,pg);
264 if (d*arad*arad > 1.0)
265 arad = 1.0/sqrt(d);
266 }
267 if (arad < minarad) {
268 arad = minarad;
269 if (pg != NULL && d*arad*arad > 1.0) { /* cap gradient */
270 d = 1.0/arad/sqrt(d);
271 for (i = 0; i < 3; i++)
272 pg[i] *= d;
273 }
274 }
275 if ((arad /= sqrt(wt)) > maxarad)
276 arad = maxarad;
277 return(arad);
278 }
279
280
281 void
282 comperrs( /* compute initial error estimates */
283 AMBSAMP *da, /* assumes standard ordering */
284 register AMBHEMI *hp
285 )
286 {
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 #ifdef DEBUG
295 if (dp->t != i || dp->p != j)
296 error(CONSISTENCY,
297 "division order in comperrs");
298 #endif
299 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 } else { /* around */
312 b2 = bright(dp[hp->np-1].v) - b;
313 b2 *= b2 * 0.25;
314 dp[0].k += b2;
315 dp[hp->np-1].k += b2;
316 }
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 void
334 posgradient( /* compute position gradient */
335 FVECT gv,
336 AMBSAMP *da, /* assumes standard ordering */
337 register AMBHEMI *hp
338 )
339 {
340 register int i, j;
341 double nextsine, lastsine, b, d;
342 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 lastsine = 0.0;
351 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 /* sin(t)*cos(t)^2 */
362 d *= lastsine * (1.0 - (double)i/hp->nt);
363 mag0 += d*(b - bright(dp[-hp->np].v));
364 }
365 nextsine = sqrt((double)(i+1)/hp->nt);
366 if (j > 0) {
367 d = dp[-1].r;
368 if (dp[0].r > d) d = dp[0].r;
369 mag1 += d * (nextsine - lastsine) *
370 (b - bright(dp[-1].v));
371 } else {
372 d = dp[hp->np-1].r;
373 if (dp[0].r > d) d = dp[0].r;
374 mag1 += d * (nextsine - lastsine) *
375 (b - bright(dp[hp->np-1].v));
376 }
377 dp += hp->np;
378 lastsine = nextsine;
379 }
380 mag0 *= 2.0*PI / hp->np;
381 phi = 2.0*PI * (double)j/hp->np;
382 cosp = tcos(phi); sinp = tsin(phi);
383 xd += mag0*cosp - mag1*sinp;
384 yd += mag0*sinp + mag1*cosp;
385 }
386 for (i = 0; i < 3; i++)
387 gv[i] = (xd*hp->ux[i] + yd*hp->uy[i])*(hp->nt*hp->np)/PI;
388 }
389
390
391 void
392 dirgradient( /* compute direction gradient */
393 FVECT gv,
394 AMBSAMP *da, /* assumes standard ordering */
395 register AMBHEMI *hp
396 )
397 {
398 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 /* tan(t) */
414 mag += bright(dp->v)/sqrt(hp->nt/(i+.5) - 1.0);
415 dp += hp->np;
416 }
417 phi = 2.0*PI * (j+.5)/hp->np + PI/2.0;
418 xd += mag * tcos(phi);
419 yd += mag * tsin(phi);
420 }
421 for (i = 0; i < 3; i++)
422 gv[i] = xd*hp->ux[i] + yd*hp->uy[i];
423 }