ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/ambcomp.c
Revision: 2.16
Committed: Tue May 31 18:01:09 2005 UTC (18 years, 11 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.15: +32 -31 lines
Log Message:
Added Russian roulette ray termination and fixed ambient weights & measures

File Contents

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