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

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: ambcomp.c,v 2.14 2005/04/19 01:15:06 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 RAY *r,
23 COLOR ac,
24 double wt
25 )
26 {
27 register int i;
28 /* set number of divisions */
29 hp->nt = sqrt(ambdiv * wt * (1./PI/AVGREFL)) + 0.5;
30 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 hp->ns = ambssamp * wt + 0.5;
36 /* assign coefficients */
37 copycolor(hp->acoef, ac);
38 if (wt >= r->rweight)
39 hp->drc = 1.;
40 else
41 hp->drc = wt / r->rweight;
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 }
55
56
57 int
58 divsample( /* sample a division */
59 register AMBSAMP *dp,
60 AMBHEMI *h,
61 RAY *r
62 )
63 {
64 RAY ar;
65 int hlist[3];
66 double spt[2];
67 double xd, yd, zd;
68 double b2;
69 double phi;
70 register int i;
71 /* ambient coefficient for weight */
72 setcolor(ar.rcoef, h->drc, h->drc, h->drc);
73 if (rayorigin(&ar, AMBIENT, r, ar.rcoef) < 0)
74 return(-1);
75 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 hlist[0] = r->rno;
79 hlist[1] = dp->t;
80 hlist[2] = dp->p;
81 multisamp(spt, 2, urand(ilhash(hlist,3)+dp->n));
82 zd = sqrt((dp->t + spt[0])/h->nt);
83 phi = 2.0*PI * (dp->p + spt[1])/h->np;
84 xd = tcos(phi) * zd;
85 yd = tsin(phi) * zd;
86 zd = sqrt(1.0 - zd*zd);
87 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 rayvalue(&ar);
93 ndims--;
94 addcolor(dp->v, ar.rcol);
95 /* use rt to improve gradient calc */
96 if (ar.rt > FTINY && ar.rt < FHUGE)
97 dp->r += 1.0/ar.rt;
98 /* (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 return(0);
106 }
107
108
109 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 double
143 doambient( /* compute ambient component */
144 COLOR acol,
145 RAY *r,
146 COLOR ac,
147 double wt,
148 FVECT pg,
149 FVECT dg
150 )
151 {
152 double b, d;
153 AMBHEMI hemi;
154 AMBSAMP *div;
155 AMBSAMP dnew;
156 register AMBSAMP *dp;
157 double arad;
158 int ndivs;
159 register int i, j;
160 /* initialize color */
161 setcolor(acol, 0.0, 0.0, 0.0);
162 /* initialize hemisphere */
163 inithemi(&hemi, r, ac, wt);
164 ndivs = hemi.nt * hemi.np;
165 if (ndivs == 0)
166 return(0.0);
167 /* allocate super-samples */
168 if (hemi.ns > 0 || pg != NULL || dg != NULL) {
169 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 dp->r = 0.0;
183 dp->n = 0;
184 if (divsample(dp, &hemi, r) < 0)
185 goto oopsy;
186 arad += dp->r;
187 if (div != NULL)
188 dp++;
189 else
190 addcolor(acol, dp->v);
191 }
192 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 comperrs(div, &hemi); /* compute errors */
196 qsort(div, ndivs, sizeof(AMBSAMP), ambcmp); /* sort divs */
197 /* super-sample */
198 for (i = hemi.ns; i > 0; i--) {
199 dnew = *div;
200 if (divsample(&dnew, &hemi, r) < 0)
201 goto oopsy;
202 /* reinsert */
203 dp = div;
204 j = ndivs < i ? ndivs : i;
205 while (--j > 0 && dnew.k < dp[1].k) {
206 *dp = *(dp+1);
207 dp++;
208 }
209 *dp = dnew;
210 }
211 if (pg != NULL || dg != NULL) /* restore order */
212 qsort(div, ndivs, sizeof(AMBSAMP), ambnorm);
213 }
214 /* compute returned values */
215 if (div != NULL) {
216 arad = 0.0;
217 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 b = bright(acol);
228 if (b > FTINY) {
229 b = ndivs/b;
230 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 }
248 free((void *)div);
249 }
250 b = 1.0/ndivs;
251 scalecolor(acol, b);
252 if (arad <= FTINY)
253 arad = maxarad;
254 else
255 arad = (ndivs+hemi.ns)/arad;
256 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 if (arad < minarad) {
262 arad = minarad;
263 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 if ((arad /= sqrt(wt)) > maxarad)
270 arad = maxarad;
271 return(arad);
272 oopsy:
273 if (div != NULL)
274 free((void *)div);
275 return(0.0);
276 }
277
278
279 void
280 comperrs( /* compute initial error estimates */
281 AMBSAMP *da, /* assumes standard ordering */
282 register AMBHEMI *hp
283 )
284 {
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 #ifdef DEBUG
293 if (dp->t != i || dp->p != j)
294 error(CONSISTENCY,
295 "division order in comperrs");
296 #endif
297 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 } else { /* around */
310 b2 = bright(dp[hp->np-1].v) - b;
311 b2 *= b2 * 0.25;
312 dp[0].k += b2;
313 dp[hp->np-1].k += b2;
314 }
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 void
332 posgradient( /* compute position gradient */
333 FVECT gv,
334 AMBSAMP *da, /* assumes standard ordering */
335 register AMBHEMI *hp
336 )
337 {
338 register int i, j;
339 double nextsine, lastsine, b, d;
340 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 lastsine = 0.0;
349 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 /* sin(t)*cos(t)^2 */
360 d *= lastsine * (1.0 - (double)i/hp->nt);
361 mag0 += d*(b - bright(dp[-hp->np].v));
362 }
363 nextsine = sqrt((double)(i+1)/hp->nt);
364 if (j > 0) {
365 d = dp[-1].r;
366 if (dp[0].r > d) d = dp[0].r;
367 mag1 += d * (nextsine - lastsine) *
368 (b - bright(dp[-1].v));
369 } else {
370 d = dp[hp->np-1].r;
371 if (dp[0].r > d) d = dp[0].r;
372 mag1 += d * (nextsine - lastsine) *
373 (b - bright(dp[hp->np-1].v));
374 }
375 dp += hp->np;
376 lastsine = nextsine;
377 }
378 mag0 *= 2.0*PI / hp->np;
379 phi = 2.0*PI * (double)j/hp->np;
380 cosp = tcos(phi); sinp = tsin(phi);
381 xd += mag0*cosp - mag1*sinp;
382 yd += mag0*sinp + mag1*cosp;
383 }
384 for (i = 0; i < 3; i++)
385 gv[i] = (xd*hp->ux[i] + yd*hp->uy[i])/PI;
386 }
387
388
389 void
390 dirgradient( /* compute direction gradient */
391 FVECT gv,
392 AMBSAMP *da, /* assumes standard ordering */
393 register AMBHEMI *hp
394 )
395 {
396 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 /* tan(t) */
412 mag += bright(dp->v)/sqrt(hp->nt/(i+.5) - 1.0);
413 dp += hp->np;
414 }
415 phi = 2.0*PI * (j+.5)/hp->np + PI/2.0;
416 xd += mag * tcos(phi);
417 yd += mag * tsin(phi);
418 }
419 for (i = 0; i < 3; i++)
420 gv[i] = (xd*hp->ux[i] + yd*hp->uy[i])/(hp->nt*hp->np);
421 }