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.2 by greg, Tue Nov 13 04:23:38 2012 UTC vs.
Revision 2.12 by greg, Mon Oct 21 18:33:15 2013 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines