ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cv/bsdfrbf.c
Revision: 2.26
Committed: Fri Aug 22 05:38:44 2014 UTC (9 years, 8 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad4R2P2, rad5R0, rad4R2P1
Changes since 2.25: +2 -2 lines
Log Message:
Set minimum cosine to 0.02 to avoid blowing-up values near grazing

File Contents

# User Rev Content
1 greg 2.1 #ifndef lint
2 greg 2.26 static const char RCSid[] = "$Id: bsdfrbf.c,v 2.25 2014/03/30 00:19:09 greg Exp $";
3 greg 2.1 #endif
4     /*
5     * Radial basis function representation for BSDF data.
6     *
7     * G. Ward
8     */
9    
10 greg 2.13 /****************************************************************
11     1) Collect samples into a grid using the Shirley-Chiu
12     angular mapping from a hemisphere to a square.
13    
14     2) Compute an adaptive quadtree by subdividing the grid so that
15     each leaf node has at least one sample up to as many
16     samples as fit nicely on a plane to within a certain
17     MSE tolerance.
18    
19     3) Place one Gaussian lobe at each leaf node in the quadtree,
20     sizing it to have a radius equal to the leaf size and
21     a volume equal to the energy in that node.
22     *****************************************************************/
23    
24 greg 2.1 #define _USE_MATH_DEFINES
25     #include <stdio.h>
26     #include <stdlib.h>
27     #include <string.h>
28     #include <math.h>
29     #include "bsdfrep.h"
30    
31 greg 2.12 #ifndef RSCA
32 greg 2.25 #define RSCA 2.0 /* radius scaling factor (empirical) */
33 greg 2.9 #endif
34 greg 2.12 #ifndef SMOOTH_MSE
35 greg 2.19 #define SMOOTH_MSE 5e-5 /* acceptable mean squared error */
36 greg 2.1 #endif
37 greg 2.12 #ifndef SMOOTH_MSER
38 greg 2.18 #define SMOOTH_MSER 0.03 /* acceptable relative MSE */
39 greg 2.7 #endif
40 greg 2.12 #define MAX_RAD (GRIDRES/8) /* maximum lobe radius */
41    
42     #define RBFALLOCB 10 /* RBF allocation block size */
43    
44 greg 2.25 /* loaded grid or comparison DSFs */
45 greg 2.1 GRIDVAL dsf_grid[GRIDRES][GRIDRES];
46    
47     /* Start new DSF input grid */
48     void
49     new_bsdf_data(double new_theta, double new_phi)
50     {
51     if (!new_input_direction(new_theta, new_phi))
52     exit(1);
53     memset(dsf_grid, 0, sizeof(dsf_grid));
54     }
55    
56     /* Add BSDF data point */
57     void
58     add_bsdf_data(double theta_out, double phi_out, double val, int isDSF)
59     {
60     FVECT ovec;
61     int pos[2];
62    
63     if (!output_orient) /* check output orientation */
64     output_orient = 1 - 2*(theta_out > 90.);
65     else if (output_orient > 0 ^ theta_out < 90.) {
66     fputs("Cannot handle output angles on both sides of surface\n",
67     stderr);
68     exit(1);
69     }
70     ovec[2] = sin((M_PI/180.)*theta_out);
71     ovec[0] = cos((M_PI/180.)*phi_out) * ovec[2];
72     ovec[1] = sin((M_PI/180.)*phi_out) * ovec[2];
73     ovec[2] = sqrt(1. - ovec[2]*ovec[2]);
74    
75 greg 2.21 if (!isDSF)
76 greg 2.26 val *= COSF(ovec[2]); /* convert from BSDF to DSF */
77 greg 2.1
78 greg 2.4 /* update BSDF histogram */
79     if (val < BSDF2BIG*ovec[2] && val > BSDF2SML*ovec[2])
80     ++bsdf_hist[histndx(val/ovec[2])];
81    
82 greg 2.1 pos_from_vec(pos, ovec);
83    
84 greg 2.20 dsf_grid[pos[0]][pos[1]].sum.v += val;
85     dsf_grid[pos[0]][pos[1]].sum.n++;
86 greg 2.1 }
87    
88 greg 2.11 /* Compute minimum BSDF from histogram (does not clear) */
89 greg 2.5 static void
90     comp_bsdf_min()
91     {
92 greg 2.17 unsigned long cnt, target;
93     int i;
94 greg 2.5
95     cnt = 0;
96     for (i = HISTLEN; i--; )
97     cnt += bsdf_hist[i];
98     if (!cnt) { /* shouldn't happen */
99     bsdf_min = 0;
100     return;
101     }
102     target = cnt/100; /* ignore bottom 1% */
103     cnt = 0;
104     for (i = 0; cnt <= target; i++)
105     cnt += bsdf_hist[i];
106     bsdf_min = histval(i-1);
107     }
108    
109 greg 2.12 /* Determine if the given region is empty of grid samples */
110 greg 2.6 static int
111 greg 2.12 empty_region(int x0, int x1, int y0, int y1)
112 greg 2.6 {
113 greg 2.12 int x, y;
114    
115     for (x = x0; x < x1; x++)
116     for (y = y0; y < y1; y++)
117 greg 2.20 if (dsf_grid[x][y].sum.n)
118 greg 2.12 return(0);
119     return(1);
120     }
121    
122     /* Determine if the given region is smooth enough to be a single lobe */
123     static int
124     smooth_region(int x0, int x1, int y0, int y1)
125     {
126     RREAL rMtx[3][3];
127     FVECT xvec;
128     double A, B, C, nvs, sqerr;
129     int x, y, n;
130     /* compute planar regression */
131     memset(rMtx, 0, sizeof(rMtx));
132     memset(xvec, 0, sizeof(xvec));
133     for (x = x0; x < x1; x++)
134     for (y = y0; y < y1; y++)
135 greg 2.20 if ((n = dsf_grid[x][y].sum.n) > 0) {
136     double z = dsf_grid[x][y].sum.v;
137 greg 2.13 rMtx[0][0] += x*x*(double)n;
138     rMtx[0][1] += x*y*(double)n;
139     rMtx[0][2] += x*(double)n;
140     rMtx[1][1] += y*y*(double)n;
141     rMtx[1][2] += y*(double)n;
142     rMtx[2][2] += (double)n;
143 greg 2.12 xvec[0] += x*z;
144     xvec[1] += y*z;
145     xvec[2] += z;
146     }
147     rMtx[1][0] = rMtx[0][1];
148 greg 2.15 rMtx[2][0] = rMtx[0][2];
149 greg 2.12 rMtx[2][1] = rMtx[1][2];
150     nvs = rMtx[2][2];
151     if (SDinvXform(rMtx, rMtx) != SDEnone)
152 greg 2.16 return(1); /* colinear values */
153 greg 2.12 A = DOT(rMtx[0], xvec);
154     B = DOT(rMtx[1], xvec);
155     C = DOT(rMtx[2], xvec);
156     sqerr = 0.0; /* compute mean squared error */
157     for (x = x0; x < x1; x++)
158     for (y = y0; y < y1; y++)
159 greg 2.20 if ((n = dsf_grid[x][y].sum.n) > 0) {
160     double d = A*x + B*y + C - dsf_grid[x][y].sum.v/n;
161 greg 2.12 sqerr += n*d*d;
162 greg 2.6 }
163 greg 2.12 if (sqerr <= nvs*SMOOTH_MSE) /* below absolute MSE threshold? */
164     return(1);
165 greg 2.13 /* OR below relative MSE threshold? */
166 greg 2.12 return(sqerr*nvs <= xvec[2]*xvec[2]*SMOOTH_MSER);
167     }
168    
169     /* Create new lobe based on integrated samples in region */
170 greg 2.21 static int
171 greg 2.12 create_lobe(RBFVAL *rvp, int x0, int x1, int y0, int y1)
172     {
173     double vtot = 0.0;
174     int nv = 0;
175 greg 2.25 double wxsum = 0.0, wysum = 0.0, wtsum = 0.0;
176 greg 2.12 double rad;
177     int x, y;
178     /* compute average for region */
179     for (x = x0; x < x1; x++)
180 greg 2.25 for (y = y0; y < y1; y++)
181     if (dsf_grid[x][y].sum.n) {
182     const double v = dsf_grid[x][y].sum.v;
183     const int n = dsf_grid[x][y].sum.n;
184    
185     if (v > 0) {
186     double wt = v / (double)n;
187     wxsum += wt * x;
188     wysum += wt * y;
189     wtsum += wt;
190     }
191     vtot += v;
192     nv += n;
193     }
194 greg 2.12 if (!nv) {
195     fprintf(stderr, "%s: internal - missing samples in create_lobe\n",
196     progname);
197     exit(1);
198 greg 2.6 }
199 greg 2.21 if (vtot <= 0) /* only create positive lobes */
200     return(0);
201 greg 2.12 /* peak value based on integral */
202     vtot *= (x1-x0)*(y1-y0)*(2.*M_PI/GRIDRES/GRIDRES)/(double)nv;
203     rad = (RSCA/(double)GRIDRES)*(x1-x0);
204     rvp->peak = vtot / ((2.*M_PI) * rad*rad);
205 greg 2.25 rvp->crad = ANG2R(rad); /* put peak at centroid */
206     rvp->gx = (int)(wxsum/wtsum + .5);
207     rvp->gy = (int)(wysum/wtsum + .5);
208 greg 2.21 return(1);
209 greg 2.6 }
210    
211 greg 2.12 /* Recursive function to build radial basis function representation */
212 greg 2.6 static int
213 greg 2.12 build_rbfrep(RBFVAL **arp, int *np, int x0, int x1, int y0, int y1)
214 greg 2.6 {
215 greg 2.12 int xmid = (x0+x1)>>1;
216     int ymid = (y0+y1)>>1;
217     int branched[4];
218     int nadded, nleaves;
219     /* need to make this a leaf? */
220     if (empty_region(x0, xmid, y0, ymid) ||
221     empty_region(xmid, x1, y0, ymid) ||
222     empty_region(x0, xmid, ymid, y1) ||
223     empty_region(xmid, x1, ymid, y1))
224     return(0);
225     /* add children (branches+leaves) */
226     if ((branched[0] = build_rbfrep(arp, np, x0, xmid, y0, ymid)) < 0)
227     return(-1);
228     if ((branched[1] = build_rbfrep(arp, np, xmid, x1, y0, ymid)) < 0)
229     return(-1);
230     if ((branched[2] = build_rbfrep(arp, np, x0, xmid, ymid, y1)) < 0)
231     return(-1);
232     if ((branched[3] = build_rbfrep(arp, np, xmid, x1, ymid, y1)) < 0)
233     return(-1);
234     nadded = branched[0] + branched[1] + branched[2] + branched[3];
235     nleaves = !branched[0] + !branched[1] + !branched[2] + !branched[3];
236     if (!nleaves) /* nothing but branches? */
237     return(nadded);
238     /* combine 4 leaves into 1? */
239 greg 2.14 if ((nleaves == 4) & (x1-x0 <= MAX_RAD) &&
240     smooth_region(x0, x1, y0, y1))
241 greg 2.12 return(0);
242     /* need more array space? */
243     if ((*np+nleaves-1)>>RBFALLOCB != (*np-1)>>RBFALLOCB) {
244     *arp = (RBFVAL *)realloc(*arp,
245     sizeof(RBFVAL)*(*np+nleaves-1+(1<<RBFALLOCB)));
246     if (*arp == NULL)
247     return(-1);
248 greg 2.6 }
249 greg 2.12 /* create lobes for leaves */
250 greg 2.21 if (!branched[0] && create_lobe(*arp+*np, x0, xmid, y0, ymid)) {
251     ++(*np); ++nadded;
252     }
253     if (!branched[1] && create_lobe(*arp+*np, xmid, x1, y0, ymid)) {
254     ++(*np); ++nadded;
255     }
256     if (!branched[2] && create_lobe(*arp+*np, x0, xmid, ymid, y1)) {
257     ++(*np); ++nadded;
258     }
259     if (!branched[3] && create_lobe(*arp+*np, xmid, x1, ymid, y1)) {
260     ++(*np); ++nadded;
261     }
262 greg 2.12 return(nadded);
263 greg 2.6 }
264    
265 greg 2.1 /* Count up filled nodes and build RBF representation from current grid */
266     RBFNODE *
267 greg 2.12 make_rbfrep()
268 greg 2.1 {
269 greg 2.12 RBFNODE *newnode;
270     RBFVAL *rbfarr;
271 greg 2.1 int nn;
272 greg 2.5 /* compute minimum BSDF */
273     comp_bsdf_min();
274 greg 2.12 /* create RBF node list */
275     rbfarr = NULL; nn = 0;
276 greg 2.22 if (build_rbfrep(&rbfarr, &nn, 0, GRIDRES, 0, GRIDRES) <= 0) {
277     if (nn)
278     goto memerr;
279 greg 2.24 fprintf(stderr,
280     "%s: warning - skipping bad incidence (%.1f,%.1f)\n",
281     progname, theta_in_deg, phi_in_deg);
282     return(NULL);
283 greg 2.22 }
284 greg 2.12 /* (re)allocate RBF array */
285     newnode = (RBFNODE *)realloc(rbfarr,
286     sizeof(RBFNODE) + sizeof(RBFVAL)*(nn-1));
287 greg 2.2 if (newnode == NULL)
288     goto memerr;
289 greg 2.12 /* copy computed lobes into RBF node */
290     memmove(newnode->rbfa, newnode, sizeof(RBFVAL)*nn);
291 greg 2.1 newnode->ord = -1;
292     newnode->next = NULL;
293     newnode->ejl = NULL;
294     newnode->invec[2] = sin((M_PI/180.)*theta_in_deg);
295     newnode->invec[0] = cos((M_PI/180.)*phi_in_deg)*newnode->invec[2];
296     newnode->invec[1] = sin((M_PI/180.)*phi_in_deg)*newnode->invec[2];
297     newnode->invec[2] = input_orient*sqrt(1. - newnode->invec[2]*newnode->invec[2]);
298 greg 2.12 newnode->vtotal = .0;
299 greg 2.1 newnode->nrbf = nn;
300 greg 2.12 /* compute sum for normalization */
301     while (nn-- > 0)
302     newnode->vtotal += rbf_volume(&newnode->rbfa[nn]);
303 greg 2.3 #ifdef DEBUG
304 greg 2.12 fprintf(stderr, "Built RBF with %d lobes\n", newnode->nrbf);
305 greg 2.3 fprintf(stderr, "Integrated DSF at (%.1f,%.1f) deg. is %.2f\n",
306     get_theta180(newnode->invec), get_phi360(newnode->invec),
307     newnode->vtotal);
308     #endif
309 greg 2.1 insert_dsf(newnode);
310     return(newnode);
311 greg 2.2 memerr:
312     fprintf(stderr, "%s: Out of memory in make_rbfrep()\n", progname);
313     exit(1);
314 greg 2.1 }