ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/bsdf_t.c
Revision: 3.5
Committed: Tue Apr 19 21:31:22 2011 UTC (13 years ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 3.4: +61 -7 lines
Log Message:
Fixed interface for determining BSDF solid angles

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: bsdf_t.c,v 3.4 2011/02/19 01:48:59 greg Exp $";
3 #endif
4 /*
5 * bsdf_t.c
6 *
7 * Definitions for variable-resolution BSDF trees
8 *
9 * Created by Greg Ward on 2/2/11.
10 *
11 */
12
13 #include "rtio.h"
14 #include <stdlib.h>
15 #include <math.h>
16 #include <ctype.h>
17 #include "ezxml.h"
18 #include "bsdf.h"
19 #include "bsdf_t.h"
20
21 /* Allocate a new scattering distribution node */
22 static SDNode *
23 SDnewNode(int nd, int lg)
24 {
25 SDNode *st;
26
27 if (nd <= 0) {
28 strcpy(SDerrorDetail, "Zero dimension BSDF node request");
29 return NULL;
30 }
31 if (nd > SD_MAXDIM) {
32 sprintf(SDerrorDetail, "Illegal BSDF dimension (%d > %d)",
33 nd, SD_MAXDIM);
34 return NULL;
35 }
36 if (lg < 0) {
37 st = (SDNode *)malloc(sizeof(SDNode) +
38 ((1<<nd) - 1)*sizeof(st->u.t[0]));
39 if (st != NULL)
40 memset(st->u.t, 0, sizeof(st->u.t[0])<<nd);
41 } else
42 st = (SDNode *)malloc(sizeof(SDNode) +
43 ((1 << nd*lg) - 1)*sizeof(st->u.v[0]));
44
45 if (st == NULL) {
46 if (lg < 0)
47 sprintf(SDerrorDetail,
48 "Cannot allocate %d branch BSDF tree", nd);
49 else
50 sprintf(SDerrorDetail,
51 "Cannot allocate %d BSDF leaves", 1 << nd*lg);
52 return NULL;
53 }
54 st->ndim = nd;
55 st->log2GR = lg;
56 return st;
57 }
58
59 /* Free an SD tree */
60 static void
61 SDfreeTre(void *p)
62 {
63 SDNode *st = (SDNode *)p;
64 int i;
65
66 if (st == NULL)
67 return;
68 for (i = (st->log2GR < 0) << st->ndim; i--; )
69 SDfreeTre(st->u.t[i]);
70 free((void *)st);
71 }
72
73 #if 0 /* Unused and untested routines */
74
75 /* Add up N-dimensional hypercube array values over the given box */
76 static double
77 SDiterSum(const float *va, int nd, int siz, const int *imin, const int *imax)
78 {
79 double sum = .0;
80 unsigned skipsiz = 1;
81 int i;
82
83 for (i = nd; --i > 0; )
84 skipsiz *= siz;
85 if (skipsiz == 1)
86 for (i = *imin; i < *imax; i++)
87 sum += va[i];
88 else
89 for (i = *imin; i < *imax; i++)
90 sum += SDiterSum(va + i*skipsiz,
91 nd-1, siz, imin+1, imax+1);
92 return sum;
93 }
94
95 /* Average BSDF leaves over an orthotope defined by the unit hypercube */
96 static double
97 SDavgBox(const SDNode *st, const double *bmin, const double *bmax)
98 {
99 int imin[SD_MAXDIM], imax[SD_MAXDIM];
100 unsigned n;
101 int i;
102
103 if (!st)
104 return .0;
105 /* check box limits */
106 for (i = st->ndim; i--; ) {
107 if (bmin[i] >= 1.)
108 return .0;
109 if (bmax[i] <= .0)
110 return .0;
111 if (bmin[i] >= bmax[i])
112 return .0;
113 }
114 if (st->log2GR < 0) { /* iterate on subtree */
115 double sum = .0, wsum = 1e-20;
116 double sbmin[SD_MAXDIM], sbmax[SD_MAXDIM], w;
117
118 for (n = 1 << st->ndim; n--; ) {
119 w = 1.;
120 for (i = st->ndim; i--; ) {
121 sbmin[i] = 2.*bmin[i];
122 sbmax[i] = 2.*bmax[i];
123 if (n & 1<<i) {
124 sbmin[i] -= 1.;
125 sbmax[i] -= 1.;
126 }
127 if (sbmin[i] < .0) sbmin[i] = .0;
128 if (sbmax[i] > 1.) sbmax[i] = 1.;
129 w *= sbmax[i] - sbmin[i];
130 }
131 if (w > 1e-10) {
132 sum += w * SDavgBox(st->u.t[n], sbmin, sbmax);
133 wsum += w;
134 }
135 }
136 return sum / wsum;
137 }
138 n = 1; /* iterate over leaves */
139 for (i = st->ndim; i--; ) {
140 imin[i] = (bmin[i] <= .0) ? 0
141 : (int)((1 << st->log2GR)*bmin[i]);
142 imax[i] = (bmax[i] >= 1.) ? (1 << st->log2GR)
143 : (int)((1 << st->log2GR)*bmax[i] + .999999);
144 n *= imax[i] - imin[i];
145 }
146 if (!n)
147 return .0;
148
149 return SDiterSum(st->u.v, st->ndim, 1 << st->log2GR, imin, imax) /
150 (double)n;
151 }
152
153 #endif /* 0 */
154
155 /* Look up tree value at the given grid position */
156 static float
157 SDlookupTre(const SDNode *st, const double *pos)
158 {
159 double spos[SD_MAXDIM];
160 int i, n, t;
161 /* climb the tree */
162 while (st->log2GR < 0) {
163 n = 0; /* move to appropriate branch */
164 for (i = st->ndim; i--; ) {
165 spos[i] = 2.*pos[i];
166 t = (spos[i] >= 1.);
167 n |= t<<i;
168 spos[i] -= (double)t;
169 }
170 st = st->u.t[n]; /* avoids tail recursion */
171 pos = spos;
172 }
173 n = t = 0; /* find grid array index */
174 for (i = st->ndim; i--; ) {
175 n += (int)((1<<st->log2GR)*pos[i]) << t;
176 t += st->log2GR;
177 }
178 return st->u.v[n]; /* XXX no interpolation */
179 }
180
181 /* Compute non-diffuse component for variable-resolution BSDF */
182 static int
183 SDgetTreBSDF(float coef[SDmaxCh], const FVECT outVec,
184 const FVECT inVec, const void *dist)
185 {
186 const SDNode *st = (const SDNode *)dist;
187 double gridPos[4];
188 /* convert vector coordinates */
189 if (st->ndim == 3) { /* reduce for isotropic BSDF? */
190 static const FVECT zvec = {.0, .0, 1.};
191 FVECT rOutVec;
192 spinvector(rOutVec, outVec, zvec, -atan2(inVec[1],inVec[0]));
193 SDdisk2square(gridPos, rOutVec[0], rOutVec[1]);
194 gridPos[2] = .5 - .5*sqrt(inVec[0]*inVec[0] + inVec[1]*inVec[1]);
195 } else if (st->ndim == 4) { /* XXX no component identity checks */
196 SDdisk2square(gridPos, outVec[0], outVec[1]);
197 SDdisk2square(gridPos+2, -inVec[0], -inVec[1]);
198 } else
199 return 0; /* should be internal error */
200 /* get nearest BSDF value */
201 coef[0] = SDlookupTre(st, gridPos);
202 return 1; /* monochromatic for now */
203 }
204
205 /* Load a variable-resolution BSDF tree from an open XML file */
206 SDError
207 SDloadTre(SDData *sd, ezxml_t wtl)
208 {
209 return SDEsupport;
210 }
211
212 /* Variable resolution BSDF methods */
213 SDFunc SDhandleTre = {
214 &SDgetTreBSDF,
215 NULL,
216 NULL,
217 NULL,
218 &SDfreeTre,
219 };