ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cv/bsdfrbf.c
Revision: 2.1
Committed: Fri Oct 19 04:14:29 2012 UTC (11 years, 6 months ago) by greg
Content type: text/plain
Branch: MAIN
Log Message:
Broke pabopto2xml into pabopto2bsdf and bsdf2ttree

File Contents

# User Rev Content
1 greg 2.1 #ifndef lint
2     static const char RCSid[] = "$Id$";
3     #endif
4     /*
5     * Radial basis function representation for BSDF data.
6     *
7     * G. Ward
8     */
9    
10     #define _USE_MATH_DEFINES
11     #include <stdio.h>
12     #include <stdlib.h>
13     #include <string.h>
14     #include <math.h>
15     #include "bsdfrep.h"
16    
17     #ifndef RSCA
18     #define RSCA 2.7 /* radius scaling factor (empirical) */
19     #endif
20     /* our loaded grid for this incident angle */
21     GRIDVAL dsf_grid[GRIDRES][GRIDRES];
22    
23     /* Start new DSF input grid */
24     void
25     new_bsdf_data(double new_theta, double new_phi)
26     {
27     if (!new_input_direction(new_theta, new_phi))
28     exit(1);
29     memset(dsf_grid, 0, sizeof(dsf_grid));
30     }
31    
32     /* Add BSDF data point */
33     void
34     add_bsdf_data(double theta_out, double phi_out, double val, int isDSF)
35     {
36     FVECT ovec;
37     int pos[2];
38    
39     if (!output_orient) /* check output orientation */
40     output_orient = 1 - 2*(theta_out > 90.);
41     else if (output_orient > 0 ^ theta_out < 90.) {
42     fputs("Cannot handle output angles on both sides of surface\n",
43     stderr);
44     exit(1);
45     }
46     ovec[2] = sin((M_PI/180.)*theta_out);
47     ovec[0] = cos((M_PI/180.)*phi_out) * ovec[2];
48     ovec[1] = sin((M_PI/180.)*phi_out) * ovec[2];
49     ovec[2] = sqrt(1. - ovec[2]*ovec[2]);
50    
51     if (!isDSF)
52     val *= ovec[2]; /* convert from BSDF to DSF */
53    
54     pos_from_vec(pos, ovec);
55    
56     dsf_grid[pos[0]][pos[1]].vsum += val;
57     dsf_grid[pos[0]][pos[1]].nval++;
58     }
59    
60     /* Compute radii for non-empty bins */
61     /* (distance to furthest empty bin for which non-empty bin is the closest) */
62     static void
63     compute_radii(void)
64     {
65     unsigned int fill_grid[GRIDRES][GRIDRES];
66     unsigned short fill_cnt[GRIDRES][GRIDRES];
67     FVECT ovec0, ovec1;
68     double ang2, lastang2;
69     int r, i, j, jn, ii, jj, inear, jnear;
70    
71     r = GRIDRES/2; /* proceed in zig-zag */
72     for (i = 0; i < GRIDRES; i++)
73     for (jn = 0; jn < GRIDRES; jn++) {
74     j = (i&1) ? jn : GRIDRES-1-jn;
75     if (dsf_grid[i][j].nval) /* find empty grid pos. */
76     continue;
77     ovec_from_pos(ovec0, i, j);
78     inear = jnear = -1; /* find nearest non-empty */
79     lastang2 = M_PI*M_PI;
80     for (ii = i-r; ii <= i+r; ii++) {
81     if (ii < 0) continue;
82     if (ii >= GRIDRES) break;
83     for (jj = j-r; jj <= j+r; jj++) {
84     if (jj < 0) continue;
85     if (jj >= GRIDRES) break;
86     if (!dsf_grid[ii][jj].nval)
87     continue;
88     ovec_from_pos(ovec1, ii, jj);
89     ang2 = 2. - 2.*DOT(ovec0,ovec1);
90     if (ang2 >= lastang2)
91     continue;
92     lastang2 = ang2;
93     inear = ii; jnear = jj;
94     }
95     }
96     if (inear < 0) {
97     fprintf(stderr,
98     "%s: Could not find non-empty neighbor!\n",
99     progname);
100     exit(1);
101     }
102     ang2 = sqrt(lastang2);
103     r = ANG2R(ang2); /* record if > previous */
104     if (r > dsf_grid[inear][jnear].crad)
105     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];
135     }
136    
137     /* Cull points for more uniform distribution, leave all nval 0 or 1 */
138     static void
139     cull_values(void)
140     {
141     FVECT ovec0, ovec1;
142     double maxang, maxang2;
143     int i, j, ii, jj, r;
144     /* simple greedy algorithm */
145     for (i = 0; i < GRIDRES; i++)
146     for (j = 0; j < GRIDRES; j++) {
147     if (!dsf_grid[i][j].nval)
148     continue;
149     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     }
178     }
179     /* final averaging pass */
180     for (i = 0; i < GRIDRES; i++)
181     for (j = 0; j < GRIDRES; j++)
182     if (dsf_grid[i][j].nval > 1) {
183     dsf_grid[i][j].vsum /= (float)dsf_grid[i][j].nval;
184     dsf_grid[i][j].nval = 1;
185     }
186     }
187    
188     /* Count up filled nodes and build RBF representation from current grid */
189     RBFNODE *
190     make_rbfrep(void)
191     {
192     int niter = 16;
193     double lastVar, thisVar = 100.;
194     int nn;
195     RBFNODE *newnode;
196     int i, j;
197     /* compute RBF radii */
198     compute_radii();
199     /* coagulate lobes */
200     cull_values();
201     nn = 0; /* count selected bins */
202     for (i = 0; i < GRIDRES; i++)
203     for (j = 0; j < GRIDRES; j++)
204     nn += dsf_grid[i][j].nval;
205     /* allocate RBF array */
206     newnode = (RBFNODE *)malloc(sizeof(RBFNODE) + sizeof(RBFVAL)*(nn-1));
207     if (newnode == NULL) {
208     fprintf(stderr, "%s: Out of memory in make_rbfrep()\n", progname);
209     exit(1);
210     }
211     newnode->ord = -1;
212     newnode->next = NULL;
213     newnode->ejl = NULL;
214     newnode->invec[2] = sin((M_PI/180.)*theta_in_deg);
215     newnode->invec[0] = cos((M_PI/180.)*phi_in_deg)*newnode->invec[2];
216     newnode->invec[1] = sin((M_PI/180.)*phi_in_deg)*newnode->invec[2];
217     newnode->invec[2] = input_orient*sqrt(1. - newnode->invec[2]*newnode->invec[2]);
218     newnode->vtotal = 0;
219     newnode->nrbf = nn;
220     nn = 0; /* fill RBF array */
221     for (i = 0; i < GRIDRES; i++)
222     for (j = 0; j < GRIDRES; j++)
223     if (dsf_grid[i][j].nval) {
224     newnode->rbfa[nn].peak = dsf_grid[i][j].vsum;
225     newnode->rbfa[nn].crad = RSCA*dsf_grid[i][j].crad + .5;
226     newnode->rbfa[nn].gx = i;
227     newnode->rbfa[nn].gy = j;
228     ++nn;
229     }
230     /* iterate to improve interpolation accuracy */
231     do {
232     double dsum = 0, dsum2 = 0;
233     nn = 0;
234     for (i = 0; i < GRIDRES; i++)
235     for (j = 0; j < GRIDRES; j++)
236     if (dsf_grid[i][j].nval) {
237     FVECT odir;
238     double corr;
239     ovec_from_pos(odir, i, j);
240     newnode->rbfa[nn++].peak *= corr =
241     dsf_grid[i][j].vsum /
242     eval_rbfrep(newnode, odir);
243     dsum += corr - 1.;
244     dsum2 += (corr-1.)*(corr-1.);
245     }
246     lastVar = thisVar;
247     thisVar = dsum2/(double)nn;
248     #ifdef DEBUG
249     fprintf(stderr, "Avg., RMS error: %.1f%% %.1f%%\n",
250     100.*dsum/(double)nn,
251     100.*sqrt(thisVar));
252     #endif
253     } while (--niter > 0 && lastVar-thisVar > 0.02*lastVar);
254    
255     nn = 0; /* compute sum for normalization */
256     while (nn < newnode->nrbf)
257     newnode->vtotal += rbf_volume(&newnode->rbfa[nn++]);
258    
259     insert_dsf(newnode);
260    
261     return(newnode);
262     }