ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cv/bsdfrbf.c
(Generate patch)

Comparing ray/src/cv/bsdfrbf.c (file contents):
Revision 2.4 by greg, Wed Mar 20 01:00:22 2013 UTC vs.
Revision 2.23 by greg, Fri Mar 21 00:42:46 2014 UTC

# Line 7 | Line 7 | static const char RCSid[] = "$Id$";
7   *      G. Ward
8   */
9  
10 + /****************************************************************
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   #define _USE_MATH_DEFINES
25   #include <stdio.h>
26   #include <stdlib.h>
# Line 15 | Line 29 | static const char RCSid[] = "$Id$";
29   #include "bsdfrep.h"
30  
31   #ifndef RSCA
32 < #define RSCA            2.7             /* radius scaling factor (empirical) */
32 > #define RSCA            2.2             /* radius scaling factor (empirical) */
33   #endif
34 <                                /* our loaded grid for this incident angle */
34 > #ifndef SMOOTH_MSE
35 > #define SMOOTH_MSE      5e-5            /* acceptable mean squared error */
36 > #endif
37 > #ifndef SMOOTH_MSER
38 > #define SMOOTH_MSER     0.03            /* acceptable relative MSE */
39 > #endif
40 > #define MAX_RAD         (GRIDRES/8)     /* maximum lobe radius */
41 >
42 > #define RBFALLOCB       10              /* RBF allocation block size */
43 >
44 >                                /* our loaded grid or comparison DSFs */
45   GRIDVAL                 dsf_grid[GRIDRES][GRIDRES];
46  
47   /* Start new DSF input grid */
# Line 57 | Line 81 | add_bsdf_data(double theta_out, double phi_out, double
81  
82          pos_from_vec(pos, ovec);
83  
84 <        dsf_grid[pos[0]][pos[1]].vsum += val;
85 <        dsf_grid[pos[0]][pos[1]].nval++;
84 >        dsf_grid[pos[0]][pos[1]].sum.v += val;
85 >        dsf_grid[pos[0]][pos[1]].sum.n++;
86   }
87  
88 < /* Compute radii for non-empty bins */
65 < /* (distance to furthest empty bin for which non-empty bin is the closest) */
88 > /* Compute minimum BSDF from histogram (does not clear) */
89   static void
90 < compute_radii(void)
90 > comp_bsdf_min()
91   {
92 <        unsigned int    fill_grid[GRIDRES][GRIDRES];
93 <        unsigned short  fill_cnt[GRIDRES][GRIDRES];
71 <        FVECT           ovec0, ovec1;
72 <        double          ang2, lastang2;
73 <        int             r, i, j, jn, ii, jj, inear, jnear;
92 >        unsigned long   cnt, target;
93 >        int             i;
94  
95 <        r = GRIDRES/2;                          /* proceed in zig-zag */
96 <        for (i = 0; i < GRIDRES; i++)
97 <            for (jn = 0; jn < GRIDRES; jn++) {
98 <                j = (i&1) ? jn : GRIDRES-1-jn;
99 <                if (dsf_grid[i][j].nval)        /* find empty grid pos. */
100 <                        continue;
101 <                ovec_from_pos(ovec0, i, j);
102 <                inear = jnear = -1;             /* find nearest non-empty */
103 <                lastang2 = M_PI*M_PI;
104 <                for (ii = i-r; ii <= i+r; ii++) {
105 <                    if (ii < 0) continue;
106 <                    if (ii >= GRIDRES) break;
107 <                    for (jj = j-r; jj <= j+r; jj++) {
108 <                        if (jj < 0) continue;
109 <                        if (jj >= GRIDRES) break;
110 <                        if (!dsf_grid[ii][jj].nval)
111 <                                continue;
112 <                        ovec_from_pos(ovec1, ii, jj);
113 <                        ang2 = 2. - 2.*DOT(ovec0,ovec1);
114 <                        if (ang2 >= lastang2)
115 <                                continue;
116 <                        lastang2 = ang2;
117 <                        inear = ii; jnear = jj;
118 <                    }
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 > /* Determine if the given region is empty of grid samples */
110 > static int
111 > empty_region(int x0, int x1, int y0, int y1)
112 > {
113 >        int     x, y;
114 >
115 >        for (x = x0; x < x1; x++)
116 >            for (y = y0; y < y1; y++)
117 >                if (dsf_grid[x][y].sum.n)
118 >                        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 >                if ((n = dsf_grid[x][y].sum.n) > 0) {
136 >                        double  z = dsf_grid[x][y].sum.v;
137 >                        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 >                        xvec[0] += x*z;
144 >                        xvec[1] += y*z;
145 >                        xvec[2] += z;
146                  }
147 <                if (inear < 0) {
148 <                        fprintf(stderr,
149 <                                "%s: Could not find non-empty neighbor!\n",
150 <                                        progname);
151 <                        exit(1);
147 >        rMtx[1][0] = rMtx[0][1];
148 >        rMtx[2][0] = rMtx[0][2];
149 >        rMtx[2][1] = rMtx[1][2];
150 >        nvs = rMtx[2][2];
151 >        if (SDinvXform(rMtx, rMtx) != SDEnone)
152 >                return(1);              /* colinear values */
153 >        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 >                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 >                        sqerr += n*d*d;
162                  }
163 <                ang2 = sqrt(lastang2);
164 <                r = ANG2R(ang2);                /* record if > previous */
165 <                if (r > dsf_grid[inear][jnear].crad)
166 <                        dsf_grid[inear][jnear].crad = r;
110 <                                                /* next search radius */
111 <                r = ang2*(2.*GRIDRES/M_PI) + 3;
112 <            }
113 <                                                /* blur radii over hemisphere */
114 <        memset(fill_grid, 0, sizeof(fill_grid));
115 <        memset(fill_cnt, 0, sizeof(fill_cnt));
116 <        for (i = 0; i < GRIDRES; i++)
117 <            for (j = 0; j < GRIDRES; j++) {
118 <                if (!dsf_grid[i][j].crad)
119 <                        continue;               /* missing distance */
120 <                r = R2ANG(dsf_grid[i][j].crad)*(2.*RSCA*GRIDRES/M_PI);
121 <                for (ii = i-r; ii <= i+r; ii++) {
122 <                    if (ii < 0) continue;
123 <                    if (ii >= GRIDRES) break;
124 <                    for (jj = j-r; jj <= j+r; jj++) {
125 <                        if (jj < 0) continue;
126 <                        if (jj >= GRIDRES) break;
127 <                        if ((ii-i)*(ii-i) + (jj-j)*(jj-j) > r*r)
128 <                                continue;
129 <                        fill_grid[ii][jj] += dsf_grid[i][j].crad;
130 <                        fill_cnt[ii][jj]++;
131 <                    }
132 <                }
133 <            }
134 <                                                /* copy back blurred radii */
135 <        for (i = 0; i < GRIDRES; i++)
136 <            for (j = 0; j < GRIDRES; j++)
137 <                if (fill_cnt[i][j])
138 <                        dsf_grid[i][j].crad = fill_grid[i][j]/fill_cnt[i][j];
163 >        if (sqerr <= nvs*SMOOTH_MSE)    /* below absolute MSE threshold? */
164 >                return(1);
165 >                                        /* OR below relative MSE threshold? */
166 >        return(sqerr*nvs <= xvec[2]*xvec[2]*SMOOTH_MSER);
167   }
168  
169 < /* Cull points for more uniform distribution, leave all nval 0 or 1 */
170 < static void
171 < cull_values(void)
169 > /* Create new lobe based on integrated samples in region */
170 > static int
171 > create_lobe(RBFVAL *rvp, int x0, int x1, int y0, int y1)
172   {
173 <        FVECT   ovec0, ovec1;
174 <        double  maxang, maxang2;
175 <        int     i, j, ii, jj, r;
176 <                                                /* simple greedy algorithm */
177 <        for (i = 0; i < GRIDRES; i++)
178 <            for (j = 0; j < GRIDRES; j++) {
179 <                if (!dsf_grid[i][j].nval)
180 <                        continue;
181 <                if (!dsf_grid[i][j].crad)
154 <                        continue;               /* shouldn't happen */
155 <                ovec_from_pos(ovec0, i, j);
156 <                maxang = 2.*R2ANG(dsf_grid[i][j].crad);
157 <                if (maxang > ovec0[2])          /* clamp near horizon */
158 <                        maxang = ovec0[2];
159 <                r = maxang*(2.*GRIDRES/M_PI) + 1;
160 <                maxang2 = maxang*maxang;
161 <                for (ii = i-r; ii <= i+r; ii++) {
162 <                    if (ii < 0) continue;
163 <                    if (ii >= GRIDRES) break;
164 <                    for (jj = j-r; jj <= j+r; jj++) {
165 <                        if (jj < 0) continue;
166 <                        if (jj >= GRIDRES) break;
167 <                        if (!dsf_grid[ii][jj].nval)
168 <                                continue;
169 <                        if ((ii == i) & (jj == j))
170 <                                continue;       /* don't get self-absorbed */
171 <                        ovec_from_pos(ovec1, ii, jj);
172 <                        if (2. - 2.*DOT(ovec0,ovec1) >= maxang2)
173 <                                continue;
174 <                                                /* absorb sum */
175 <                        dsf_grid[i][j].vsum += dsf_grid[ii][jj].vsum;
176 <                        dsf_grid[i][j].nval += dsf_grid[ii][jj].nval;
177 <                                                /* keep value, though */
178 <                        dsf_grid[ii][jj].vsum /= (float)dsf_grid[ii][jj].nval;
179 <                        dsf_grid[ii][jj].nval = 0;
180 <                    }
181 <                }
173 >        double  vtot = 0.0;
174 >        int     nv = 0;
175 >        double  rad;
176 >        int     x, y;
177 >                                        /* compute average for region */
178 >        for (x = x0; x < x1; x++)
179 >            for (y = y0; y < y1; y++) {
180 >                vtot += dsf_grid[x][y].sum.v;
181 >                nv += dsf_grid[x][y].sum.n;
182              }
183 <                                                /* final averaging pass */
184 <        for (i = 0; i < GRIDRES; i++)
185 <            for (j = 0; j < GRIDRES; j++)
186 <                if (dsf_grid[i][j].nval > 1) {
187 <                        dsf_grid[i][j].vsum /= (float)dsf_grid[i][j].nval;
188 <                        dsf_grid[i][j].nval = 1;
189 <                }
183 >        if (!nv) {
184 >                fprintf(stderr, "%s: internal - missing samples in create_lobe\n",
185 >                                progname);
186 >                exit(1);
187 >        }
188 >        if (vtot <= 0)                  /* only create positive lobes */
189 >                return(0);
190 >                                        /* peak value based on integral */
191 >        vtot *= (x1-x0)*(y1-y0)*(2.*M_PI/GRIDRES/GRIDRES)/(double)nv;
192 >        rad = (RSCA/(double)GRIDRES)*(x1-x0);
193 >        rvp->peak =  vtot / ((2.*M_PI) * rad*rad);
194 >        rvp->crad = ANG2R(rad);
195 >        rvp->gx = (x0+x1)>>1;
196 >        rvp->gy = (y0+y1)>>1;
197 >        return(1);
198   }
199  
200 + /* Recursive function to build radial basis function representation */
201 + static int
202 + build_rbfrep(RBFVAL **arp, int *np, int x0, int x1, int y0, int y1)
203 + {
204 +        int     xmid = (x0+x1)>>1;
205 +        int     ymid = (y0+y1)>>1;
206 +        int     branched[4];
207 +        int     nadded, nleaves;
208 +                                        /* need to make this a leaf? */
209 +        if (empty_region(x0, xmid, y0, ymid) ||
210 +                        empty_region(xmid, x1, y0, ymid) ||
211 +                        empty_region(x0, xmid, ymid, y1) ||
212 +                        empty_region(xmid, x1, ymid, y1))
213 +                return(0);
214 +                                        /* add children (branches+leaves) */
215 +        if ((branched[0] = build_rbfrep(arp, np, x0, xmid, y0, ymid)) < 0)
216 +                return(-1);
217 +        if ((branched[1] = build_rbfrep(arp, np, xmid, x1, y0, ymid)) < 0)
218 +                return(-1);
219 +        if ((branched[2] = build_rbfrep(arp, np, x0, xmid, ymid, y1)) < 0)
220 +                return(-1);
221 +        if ((branched[3] = build_rbfrep(arp, np, xmid, x1, ymid, y1)) < 0)
222 +                return(-1);
223 +        nadded = branched[0] + branched[1] + branched[2] + branched[3];
224 +        nleaves = !branched[0] + !branched[1] + !branched[2] + !branched[3];
225 +        if (!nleaves)                   /* nothing but branches? */
226 +                return(nadded);
227 +                                        /* combine 4 leaves into 1? */
228 +        if ((nleaves == 4) & (x1-x0 <= MAX_RAD) &&
229 +                        smooth_region(x0, x1, y0, y1))
230 +                return(0);
231 +                                        /* need more array space? */
232 +        if ((*np+nleaves-1)>>RBFALLOCB != (*np-1)>>RBFALLOCB) {
233 +                *arp = (RBFVAL *)realloc(*arp,
234 +                                sizeof(RBFVAL)*(*np+nleaves-1+(1<<RBFALLOCB)));
235 +                if (*arp == NULL)
236 +                        return(-1);
237 +        }
238 +                                        /* create lobes for leaves */
239 +        if (!branched[0] && create_lobe(*arp+*np, x0, xmid, y0, ymid)) {
240 +                ++(*np); ++nadded;
241 +        }
242 +        if (!branched[1] && create_lobe(*arp+*np, xmid, x1, y0, ymid)) {
243 +                ++(*np); ++nadded;
244 +        }
245 +        if (!branched[2] && create_lobe(*arp+*np, x0, xmid, ymid, y1)) {
246 +                ++(*np); ++nadded;
247 +        }
248 +        if (!branched[3] && create_lobe(*arp+*np, xmid, x1, ymid, y1)) {
249 +                ++(*np); ++nadded;
250 +        }
251 +        return(nadded);
252 + }
253 +
254   /* Count up filled nodes and build RBF representation from current grid */
255   RBFNODE *
256 < make_rbfrep(void)
256 > make_rbfrep()
257   {
196        int     niter = 16;
197        double  lastVar, thisVar = 100.;
198        int     nn;
258          RBFNODE *newnode;
259 <        RBFVAL  *itera;
260 <        int     i, j;
261 <                                /* compute RBF radii */
262 <        compute_radii();
263 <                                /* coagulate lobes */
264 <        cull_values();
265 <        nn = 0;                 /* count selected bins */
266 <        for (i = 0; i < GRIDRES; i++)
267 <            for (j = 0; j < GRIDRES; j++)
268 <                nn += dsf_grid[i][j].nval;
269 <                                /* allocate RBF array */
270 <        newnode = (RBFNODE *)malloc(sizeof(RBFNODE) + sizeof(RBFVAL)*(nn-1));
259 >        RBFVAL  *rbfarr;
260 >        int     nn;
261 >                                /* compute minimum BSDF */
262 >        comp_bsdf_min();
263 >                                /* create RBF node list */
264 >        rbfarr = NULL; nn = 0;
265 >        if (build_rbfrep(&rbfarr, &nn, 0, GRIDRES, 0, GRIDRES) <= 0) {
266 >                if (nn)
267 >                        goto memerr;
268 >                fprintf(stderr, "%s: no usable data in make_rbfrep()\n",
269 >                                progname);
270 >                exit(1);
271 >        }
272 >                                /* (re)allocate RBF array */
273 >        newnode = (RBFNODE *)realloc(rbfarr,
274 >                        sizeof(RBFNODE) + sizeof(RBFVAL)*(nn-1));
275          if (newnode == NULL)
276                  goto memerr;
277 +                                /* copy computed lobes into RBF node */
278 +        memmove(newnode->rbfa, newnode, sizeof(RBFVAL)*nn);
279          newnode->ord = -1;
280          newnode->next = NULL;
281          newnode->ejl = NULL;
# Line 218 | Line 283 | make_rbfrep(void)
283          newnode->invec[0] = cos((M_PI/180.)*phi_in_deg)*newnode->invec[2];
284          newnode->invec[1] = sin((M_PI/180.)*phi_in_deg)*newnode->invec[2];
285          newnode->invec[2] = input_orient*sqrt(1. - newnode->invec[2]*newnode->invec[2]);
286 <        newnode->vtotal = 0;
286 >        newnode->vtotal = .0;
287          newnode->nrbf = nn;
288 <        nn = 0;                 /* fill RBF array */
289 <        for (i = 0; i < GRIDRES; i++)
290 <            for (j = 0; j < GRIDRES; j++)
226 <                if (dsf_grid[i][j].nval) {
227 <                        newnode->rbfa[nn].peak = dsf_grid[i][j].vsum;
228 <                        newnode->rbfa[nn].crad = RSCA*dsf_grid[i][j].crad + .5;
229 <                        newnode->rbfa[nn].gx = i;
230 <                        newnode->rbfa[nn].gy = j;
231 <                        ++nn;
232 <                }
233 <                                /* iterate to improve interpolation accuracy */
234 <        itera = (RBFVAL *)malloc(sizeof(RBFVAL)*newnode->nrbf);
235 <        if (itera == NULL)
236 <                goto memerr;
237 <        memcpy(itera, newnode->rbfa, sizeof(RBFVAL)*newnode->nrbf);
238 <        do {
239 <                double  dsum = 0, dsum2 = 0;
240 <                nn = 0;
241 <                for (i = 0; i < GRIDRES; i++)
242 <                    for (j = 0; j < GRIDRES; j++)
243 <                        if (dsf_grid[i][j].nval) {
244 <                                FVECT   odir;
245 <                                double  corr;
246 <                                ovec_from_pos(odir, i, j);
247 <                                itera[nn++].peak *= corr =
248 <                                        dsf_grid[i][j].vsum /
249 <                                                eval_rbfrep(newnode, odir);
250 <                                dsum += 1. - corr;
251 <                                dsum2 += (1.-corr)*(1.-corr);
252 <                        }
253 <                memcpy(newnode->rbfa, itera, sizeof(RBFVAL)*newnode->nrbf);
254 <                lastVar = thisVar;
255 <                thisVar = dsum2/(double)nn;
288 >                                /* compute sum for normalization */
289 >        while (nn-- > 0)
290 >                newnode->vtotal += rbf_volume(&newnode->rbfa[nn]);
291   #ifdef DEBUG
292 <                fprintf(stderr, "Avg., RMS error: %.1f%%  %.1f%%\n",
258 <                                        100.*dsum/(double)nn,
259 <                                        100.*sqrt(thisVar));
260 < #endif
261 <        } while (--niter > 0 && lastVar-thisVar > 0.02*lastVar);
262 <
263 <        free(itera);
264 <        nn = 0;                 /* compute sum for normalization */
265 <        while (nn < newnode->nrbf)
266 <                newnode->vtotal += rbf_volume(&newnode->rbfa[nn++]);
267 < #ifdef DEBUG
292 >        fprintf(stderr, "Built RBF with %d lobes\n", newnode->nrbf);
293          fprintf(stderr, "Integrated DSF at (%.1f,%.1f) deg. is %.2f\n",
294                          get_theta180(newnode->invec), get_phi360(newnode->invec),
295                          newnode->vtotal);

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines