ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/ambcomp.c
Revision: 2.25
Committed: Fri Apr 11 20:31:37 2014 UTC (10 years ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.24: +7 -3 lines
Log Message:
Partial implementation of Hessian gradient calculation (-DNEWAMB)

File Contents

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