20 |
|
#define GRIDRES 200 /* max. grid resolution per side */ |
21 |
|
#endif |
22 |
|
|
23 |
< |
#define RSCA 3. /* radius scaling factor (empirical) */ |
24 |
< |
#define MSCA .2 /* magnitude scaling (empirical) */ |
23 |
> |
#define RSCA 2.7 /* radius scaling factor (empirical) */ |
24 |
|
|
25 |
|
#define R2ANG(c) (((c)+.5)*(M_PI/(1<<16))) |
26 |
|
#define ANG2R(r) (int)((r)*((1<<16)/M_PI)) |
51 |
|
/* processed incident BSDF measurements */ |
52 |
|
static RBFLIST *bsdf_list = NULL; |
53 |
|
|
55 |
– |
/* Count up non-empty nodes and build RBF representation from current grid */ |
56 |
– |
static RBFLIST * |
57 |
– |
make_rbfrep(void) |
58 |
– |
{ |
59 |
– |
int nn = 0; |
60 |
– |
RBFLIST *newnode; |
61 |
– |
int i, j; |
62 |
– |
/* count non-empty bins */ |
63 |
– |
for (i = 0; i < GRIDRES; i++) |
64 |
– |
for (j = 0; j < GRIDRES; j++) |
65 |
– |
nn += (bsdf_grid[i][j].nval > 0); |
66 |
– |
/* allocate RBF array */ |
67 |
– |
newnode = (RBFLIST *)malloc(sizeof(RBFLIST) + sizeof(RBFVAL)*(nn-1)); |
68 |
– |
if (newnode == NULL) { |
69 |
– |
fputs("Out of memory in make_rbfrep\n", stderr); |
70 |
– |
exit(1); |
71 |
– |
} |
72 |
– |
newnode->invec[2] = sin(M_PI/180.*theta_in_deg); |
73 |
– |
newnode->invec[0] = cos(M_PI/180.*phi_in_deg)*newnode->invec[2]; |
74 |
– |
newnode->invec[1] = sin(M_PI/180.*phi_in_deg)*newnode->invec[2]; |
75 |
– |
newnode->invec[2] = sqrt(1. - newnode->invec[2]*newnode->invec[2]); |
76 |
– |
newnode->nrbf = nn; |
77 |
– |
nn = 0; /* fill RBF array */ |
78 |
– |
for (i = 0; i < GRIDRES; i++) |
79 |
– |
for (j = 0; j < GRIDRES; j++) |
80 |
– |
if (bsdf_grid[i][j].nval) { |
81 |
– |
newnode->rbfa[nn].bsdf = MSCA*bsdf_grid[i][j].vsum / |
82 |
– |
(double)bsdf_grid[i][j].nval; |
83 |
– |
newnode->rbfa[nn].crad = RSCA*bsdf_grid[i][j].crad + .5; |
84 |
– |
newnode->rbfa[nn].gx = i; |
85 |
– |
newnode->rbfa[nn].gy = j; |
86 |
– |
++nn; |
87 |
– |
} |
88 |
– |
newnode->next = bsdf_list; |
89 |
– |
return(bsdf_list = newnode); |
90 |
– |
} |
91 |
– |
|
92 |
– |
/* Compute grid position from normalized outgoing vector */ |
93 |
– |
static void |
94 |
– |
pos_from_vec(int pos[2], const FVECT vec) |
95 |
– |
{ |
96 |
– |
double sq[2]; /* uniform hemispherical projection */ |
97 |
– |
double norm = 1./sqrt(1. + vec[2]); |
98 |
– |
|
99 |
– |
SDdisk2square(sq, vec[0]*norm, vec[1]*norm); |
100 |
– |
|
101 |
– |
pos[0] = (int)(sq[0]*GRIDRES); |
102 |
– |
pos[1] = (int)(sq[1]*GRIDRES); |
103 |
– |
} |
104 |
– |
|
54 |
|
/* Compute outgoing vector from grid position */ |
55 |
|
static void |
56 |
|
vec_from_pos(FVECT vec, int xpos, int ypos) |
67 |
|
vec[2] = 1. - r2; |
68 |
|
} |
69 |
|
|
70 |
+ |
/* Compute grid position from normalized outgoing vector */ |
71 |
+ |
static void |
72 |
+ |
pos_from_vec(int pos[2], const FVECT vec) |
73 |
+ |
{ |
74 |
+ |
double sq[2]; /* uniform hemispherical projection */ |
75 |
+ |
double norm = 1./sqrt(1. + vec[2]); |
76 |
+ |
|
77 |
+ |
SDdisk2square(sq, vec[0]*norm, vec[1]*norm); |
78 |
+ |
|
79 |
+ |
pos[0] = (int)(sq[0]*GRIDRES); |
80 |
+ |
pos[1] = (int)(sq[1]*GRIDRES); |
81 |
+ |
} |
82 |
+ |
|
83 |
|
/* Evaluate RBF for BSDF at the given normalized outgoing direction */ |
84 |
|
static double |
85 |
|
eval_rbfrep(const RBFLIST *rp, const FVECT outvec) |
101 |
|
return(res); |
102 |
|
} |
103 |
|
|
104 |
+ |
/* Count up filled nodes and build RBF representation from current grid */ |
105 |
+ |
static RBFLIST * |
106 |
+ |
make_rbfrep(void) |
107 |
+ |
{ |
108 |
+ |
int niter = 4; |
109 |
+ |
int nn; |
110 |
+ |
RBFLIST *newnode; |
111 |
+ |
int i, j; |
112 |
+ |
|
113 |
+ |
nn = 0; /* count selected bins */ |
114 |
+ |
for (i = 0; i < GRIDRES; i++) |
115 |
+ |
for (j = 0; j < GRIDRES; j++) |
116 |
+ |
nn += (bsdf_grid[i][j].nval > 0); |
117 |
+ |
/* allocate RBF array */ |
118 |
+ |
newnode = (RBFLIST *)malloc(sizeof(RBFLIST) + sizeof(RBFVAL)*(nn-1)); |
119 |
+ |
if (newnode == NULL) { |
120 |
+ |
fputs("Out of memory in make_rbfrep\n", stderr); |
121 |
+ |
exit(1); |
122 |
+ |
} |
123 |
+ |
newnode->next = NULL; |
124 |
+ |
newnode->invec[2] = sin(M_PI/180.*theta_in_deg); |
125 |
+ |
newnode->invec[0] = cos(M_PI/180.*phi_in_deg)*newnode->invec[2]; |
126 |
+ |
newnode->invec[1] = sin(M_PI/180.*phi_in_deg)*newnode->invec[2]; |
127 |
+ |
newnode->invec[2] = sqrt(1. - newnode->invec[2]*newnode->invec[2]); |
128 |
+ |
newnode->nrbf = nn; |
129 |
+ |
nn = 0; /* fill RBF array */ |
130 |
+ |
for (i = 0; i < GRIDRES; i++) |
131 |
+ |
for (j = 0; j < GRIDRES; j++) |
132 |
+ |
if (bsdf_grid[i][j].nval) { |
133 |
+ |
newnode->rbfa[nn].bsdf = |
134 |
+ |
bsdf_grid[i][j].vsum /= |
135 |
+ |
(double)bsdf_grid[i][j].nval; |
136 |
+ |
bsdf_grid[i][j].nval = 1; |
137 |
+ |
newnode->rbfa[nn].crad = RSCA*bsdf_grid[i][j].crad + .5; |
138 |
+ |
newnode->rbfa[nn].gx = i; |
139 |
+ |
newnode->rbfa[nn].gy = j; |
140 |
+ |
++nn; |
141 |
+ |
} |
142 |
+ |
/* iterate for better convergence */ |
143 |
+ |
while (niter--) { |
144 |
+ |
nn = 0; |
145 |
+ |
for (i = 0; i < GRIDRES; i++) |
146 |
+ |
for (j = 0; j < GRIDRES; j++) |
147 |
+ |
if (bsdf_grid[i][j].nval) { |
148 |
+ |
FVECT odir; |
149 |
+ |
vec_from_pos(odir, i, j); |
150 |
+ |
newnode->rbfa[nn++].bsdf *= |
151 |
+ |
bsdf_grid[i][j].vsum / |
152 |
+ |
eval_rbfrep(newnode, odir); |
153 |
+ |
} |
154 |
+ |
} |
155 |
+ |
newnode->next = bsdf_list; |
156 |
+ |
return(bsdf_list = newnode); |
157 |
+ |
} |
158 |
+ |
|
159 |
|
/* Load a set of measurements corresponding to a particular incident angle */ |
160 |
|
static int |
161 |
|
load_bsdf_meas(const char *fname) |
374 |
|
} |
375 |
|
if (!load_bsdf_meas(argv[1])) |
376 |
|
return(1); |
360 |
– |
/* produce spheres at meas. */ |
361 |
– |
puts("void plastic orange\n0\n0\n5 .6 .4 .01 .04 .08\n"); |
362 |
– |
n = 0; |
363 |
– |
for (i = 0; i < GRIDRES; i++) |
364 |
– |
for (j = 0; j < GRIDRES; j++) |
365 |
– |
if (bsdf_grid[i][j].nval) { |
366 |
– |
double bsdf = bsdf_grid[i][j].vsum / |
367 |
– |
(double)bsdf_grid[i][j].nval; |
368 |
– |
FVECT dir; |
377 |
|
|
370 |
– |
vec_from_pos(dir, i, j); |
371 |
– |
printf("orange sphere s%04d\n0\n0\n", ++n); |
372 |
– |
printf("4 %.6g %.6g %.6g .0015\n\n", |
373 |
– |
dir[0]*bsdf, dir[1]*bsdf, dir[2]*bsdf); |
374 |
– |
} |
378 |
|
compute_radii(); |
379 |
|
cull_values(); |
380 |
< |
/* highlight chosen values */ |
380 |
> |
make_rbfrep(); |
381 |
> |
/* produce spheres at meas. */ |
382 |
> |
puts("void plastic yellow\n0\n0\n5 .6 .4 .01 .04 .08\n"); |
383 |
|
puts("void plastic pink\n0\n0\n5 .5 .05 .9 .04 .08\n"); |
384 |
|
n = 0; |
385 |
|
for (i = 0; i < GRIDRES; i++) |
386 |
|
for (j = 0; j < GRIDRES; j++) |
387 |
< |
if (bsdf_grid[i][j].nval) { |
388 |
< |
bsdf = bsdf_grid[i][j].vsum / |
384 |
< |
(double)bsdf_grid[i][j].nval; |
387 |
> |
if (bsdf_grid[i][j].vsum > .0f) { |
388 |
> |
bsdf = bsdf_grid[i][j].vsum; |
389 |
|
vec_from_pos(dir, i, j); |
390 |
< |
printf("pink cone c%04d\n0\n0\n8\n", ++n); |
391 |
< |
printf("\t%.6g %.6g %.6g\n", |
390 |
> |
if (bsdf_grid[i][j].nval) { |
391 |
> |
printf("pink cone c%04d\n0\n0\n8\n", ++n); |
392 |
> |
printf("\t%.6g %.6g %.6g\n", |
393 |
|
dir[0]*bsdf, dir[1]*bsdf, dir[2]*bsdf); |
394 |
< |
printf("\t%.6g %.6g %.6g\n", |
394 |
> |
printf("\t%.6g %.6g %.6g\n", |
395 |
|
dir[0]*(bsdf+.005), dir[1]*(bsdf+.005), |
396 |
|
dir[2]*(bsdf+.005)); |
397 |
< |
puts("\t.003\t0\n"); |
397 |
> |
puts("\t.003\t0\n"); |
398 |
> |
} else { |
399 |
> |
vec_from_pos(dir, i, j); |
400 |
> |
printf("yellow sphere s%04d\n0\n0\n", ++n); |
401 |
> |
printf("4 %.6g %.6g %.6g .0015\n\n", |
402 |
> |
dir[0]*bsdf, dir[1]*bsdf, dir[2]*bsdf); |
403 |
> |
} |
404 |
|
} |
405 |
|
/* output continuous surface */ |
395 |
– |
make_rbfrep(); |
406 |
|
puts("void trans tgreen\n0\n0\n7 .7 1 .7 .04 .04 .9 .9\n"); |
407 |
|
fflush(stdout); |
408 |
|
sprintf(buf, "gensurf tgreen bsdf - - - %d %d", GRIDRES, GRIDRES); |