ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cv/checkBSDF.c
Revision: 2.8
Committed: Tue Feb 1 18:31:28 2022 UTC (2 years, 3 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.7: +2 -2 lines
Log Message:
feat(checkBSDF): Minor change in output header

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: checkBSDF.c,v 2.7 2022/01/28 02:25:28 greg Exp $";
3 #endif
4 /*
5 * checkBSDF.c
6 *
7 * Load BSDF XML file and check Helmholtz reciprocity
8 */
9
10 #define _USE_MATH_DEFINES
11 #include <math.h>
12 #include "rtio.h"
13 #include "random.h"
14 #include "bsdf.h"
15 #include "bsdf_m.h"
16 #include "bsdf_t.h"
17
18 #define F_IN_COLOR 0x1
19 #define F_ISOTROPIC 0x2
20 #define F_MATRIX 0x4
21 #define F_TTREE 0x8
22
23 typedef struct {
24 double vmin, vmax; /* extrema */
25 double vsum; /* straight sum */
26 long nvals; /* number of values */
27 } SimpleStats;
28
29 const SimpleStats SSinit = {FHUGE, -FHUGE, .0, 0};
30
31 /* relative difference formula */
32 #define rdiff(a,b) ((a)>(b) ? ((a)-(b))/((a)+FTINY) : ((b)-(a))/((b)+FTINY))
33
34 /* Figure out BSDF type (and optionally determine if in color) */
35 const char *
36 getBSDFtype(const SDData *bsdf, int *flags)
37 {
38 const SDSpectralDF *df = bsdf->tb;
39
40 if (flags) *flags = 0;
41 if (!df) df = bsdf->tf;
42 if (!df) df = bsdf->rf;
43 if (!df) df = bsdf->rb;
44 if (!df) return "Pure_Lambertian";
45 if (df->comp[0].func == &SDhandleMtx) {
46 const SDMat *m = (const SDMat *)df->comp[0].dist;
47 if (flags) {
48 *flags |= F_MATRIX;
49 *flags |= F_IN_COLOR*(m->chroma != NULL);
50 }
51 switch (m->ninc) {
52 case 145:
53 return "Klems_Full";
54 case 73:
55 return "Klems_Half";
56 case 41:
57 return "Klems_Quarter";
58 }
59 return "Unknown_Matrix";
60 }
61 if (df->comp[0].func == &SDhandleTre) {
62 const SDTre *t = (const SDTre *)df->comp[0].dist;
63 if (flags) {
64 *flags |= F_TTREE;
65 *flags |= F_IN_COLOR*(t->stc[1] != NULL);
66 }
67 switch (t->stc[0]->ndim) {
68 case 4:
69 return "Anisotropic_Tensor_Tree";
70 case 3:
71 if (flags) *flags |= F_ISOTROPIC;
72 return "Isotropic_Tensor_Tree";
73 }
74 return "Unknown_Tensor_Tree";
75 }
76 return "Unknown";
77 }
78
79 /* Report details related to one hemisphere distribution */
80 void
81 detailComponent(const char *nm, const SDValue *lamb, const SDSpectralDF *df)
82 {
83 fputs(nm, stdout);
84 if (lamb->spec.flags)
85 printf("\t%4.1f %4.1f %4.1f\t\t",
86 100.*lamb->cieY*lamb->spec.cx/lamb->spec.cy,
87 100.*lamb->cieY,
88 100.*lamb->cieY*(1.f - lamb->spec.cx - lamb->spec.cy)/lamb->spec.cy);
89 else
90 fputs("\t 0 0 0\t\t", stdout);
91 if (df)
92 printf("%5.1f%%\t\t%.2f deg\n", 100.*df->maxHemi,
93 sqrt(df->minProjSA/M_PI)*(360./M_PI));
94 else
95 puts(" 0%\t\t180 deg");
96 }
97
98 /* Add a value to stats */
99 void
100 addStat(SimpleStats *ssp, double v)
101 {
102 if (v < ssp->vmin) ssp->vmin = v;
103 if (v > ssp->vmax) ssp->vmax = v;
104 ssp->vsum += v;
105 ssp->nvals++;
106 }
107
108 /* Sample a BSDF hemisphere with callback (quadtree recursion) */
109 int
110 qtSampBSDF(double xleft, double ytop, double siz,
111 const SDData *bsdf, const int side, const RREAL *v0,
112 int (*cf)(const SDData *b, const FVECT v1, const RREAL *v0, void *p),
113 void *cdata)
114 {
115 if (siz < 0.124) { /* make sure we subdivide, first */
116 FVECT vsmp;
117 double sa;
118 square2disk(vsmp, xleft + frandom()*siz, ytop + frandom()*siz);
119 vsmp[2] = 1. - vsmp[0]*vsmp[0] - vsmp[1]*vsmp[1];
120 if (vsmp[2] <= 0) return 0;
121 vsmp[2] = side * sqrt(vsmp[2]);
122 if (SDreportError( SDsizeBSDF(&sa, vsmp, v0, SDqueryMin, bsdf), stderr))
123 return 0;
124 if (sa >= M_PI*siz*siz - FTINY) /* no further division needed */
125 return (*cf)(bsdf, vsmp, v0, cdata);
126 }
127 siz *= .5; /* 4-branch recursion */
128 return( qtSampBSDF(xleft, ytop, siz, bsdf, side, v0, cf, cdata) &&
129 qtSampBSDF(xleft+siz, ytop, siz, bsdf, side, v0, cf, cdata) &&
130 qtSampBSDF(xleft, ytop+siz, siz, bsdf, side, v0, cf, cdata) &&
131 qtSampBSDF(xleft+siz, ytop+siz, siz, bsdf, side, v0, cf, cdata) );
132 }
133
134 #define sampBSDFhemi(b,s,v0,cf,cd) qtSampBSDF(0,0,1,b,s,v0,cf,cd)
135
136 /* Call-back to compute reciprocity difference */
137 int
138 diffRecip(const SDData *bsdf, const FVECT v1, const RREAL *v0, void *p)
139 {
140 SDValue sdv;
141 double otherY;
142
143 if (SDreportError( SDevalBSDF(&sdv, v0, v1, bsdf), stderr))
144 return 0;
145 otherY = sdv.cieY;
146 if (SDreportError( SDevalBSDF(&sdv, v1, v0, bsdf), stderr))
147 return 0;
148
149 addStat((SimpleStats *)p, rdiff(sdv.cieY, otherY));
150 return 1;
151 }
152
153 /* Call-back to compute reciprocity over reflected hemisphere */
154 int
155 reflHemi(const SDData *bsdf, const FVECT v1, const RREAL *v0, void *p)
156 {
157 return sampBSDFhemi(bsdf, 1 - 2*(v1[2]<0), v1, &diffRecip, p);
158 }
159
160 /* Call-back to compute reciprocity over transmitted hemisphere */
161 int
162 transHemi(const SDData *bsdf, const FVECT v1, const RREAL *v0, void *p)
163 {
164 return sampBSDFhemi(bsdf, 1 - 2*(v1[2]>0), v1, &diffRecip, p);
165 }
166
167 /* Report reciprocity errors for the given directions */
168 void
169 checkReciprocity(const char *nm, const int side1, const int side2,
170 const SDData *bsdf, const int fl)
171 {
172 SimpleStats myStats = SSinit;
173 const SDSpectralDF *df = bsdf->tf;
174
175 if (side1 == side2) {
176 df = (side1 > 0) ? bsdf->rf : bsdf->rb;
177 if (!df) goto nothing2do;
178 } else if (!bsdf->tf | !bsdf->tb)
179 goto nothing2do;
180
181 if (fl & F_MATRIX) { /* special case for matrix BSDF */
182 const SDMat *m = (const SDMat *)df->comp[0].dist;
183 int i = m->ninc;
184 double diffuseY;
185 FVECT vin, vout;
186 double fwdY;
187 SDValue rev;
188 if (side1 == side2)
189 diffuseY = (side1 > 0) ? bsdf->rLambFront.cieY : bsdf->rLambBack.cieY;
190 else
191 diffuseY = (side1 > 0) ? bsdf->tLambFront.cieY : bsdf->tLambBack.cieY;
192 diffuseY /= M_PI;
193 while (i--) {
194 int o = m->nout;
195 if (!mBSDF_incvec(vin, m, i+.5))
196 continue;
197 while (o--) {
198 if (!mBSDF_outvec(vout, m, o+.5))
199 continue;
200 fwdY = mBSDF_value(m, o, i) + diffuseY;
201 if (fwdY <= 1e-4)
202 continue;
203 if (SDreportError( SDevalBSDF(&rev, vout, vin, bsdf), stderr))
204 return;
205 if (rev.cieY > 1e-4)
206 addStat(&myStats, rdiff(fwdY, rev.cieY));
207 }
208 }
209 } else if (fl & F_ISOTROPIC) { /* isotropic case */
210 const double stepSize = sqrt(df->minProjSA/M_PI);
211 FVECT vin;
212 vin[1] = 0;
213 for (vin[0] = 0.5*stepSize; vin[0] < 1; vin[0] += stepSize) {
214 vin[2] = side1*sqrt(1. - vin[0]*vin[0]);
215 if (!sampBSDFhemi(bsdf, side2, vin, &diffRecip, &myStats))
216 return;
217 }
218 } else if (!sampBSDFhemi(bsdf, side1, NULL,
219 (side1==side2) ? &reflHemi : &transHemi, &myStats))
220 return;
221 if (myStats.nvals) {
222 printf("%s\t%5.1f\t%5.1f\t%5.1f\n", nm,
223 100.*myStats.vmin,
224 100.*myStats.vsum/(double)myStats.nvals,
225 100.*myStats.vmax);
226 return;
227 }
228 nothing2do:
229 printf("%s\t 0\t 0\t 0\n", nm);
230 }
231
232 /* Report on the given BSDF XML file */
233 int
234 checkXML(char *fname)
235 {
236 int flags;
237 SDData myBSDF;
238 char *pth;
239
240 puts("=====================================================");
241 printf("File: '%s'\n", fname);
242 SDclearBSDF(&myBSDF, fname);
243 pth = getpath(fname, getrlibpath(), 0);
244 if (!pth) {
245 fprintf(stderr, "Cannot find file '%s'\n", fname);
246 return 0;
247 }
248 if (SDreportError( SDloadFile(&myBSDF, pth), stderr))
249 return 0;
250 printf("Manufacturer: '%s'\n", myBSDF.makr);
251 printf("BSDF Name: '%s'\n", myBSDF.matn);
252 printf("Dimensions (W x H x Thickness): %g x %g x %g cm\n", 100.*myBSDF.dim[0],
253 100.*myBSDF.dim[1], 100.*myBSDF.dim[2]);
254 printf("Type: %s\n", getBSDFtype(&myBSDF, &flags));
255 printf("Color: %d\n", (flags & F_IN_COLOR) != 0);
256 printf("Has Geometry: %d\n", (myBSDF.mgf != NULL));
257 puts("Component\tLambertian XYZ (%)\tMax. Dir\tMin. Angle");
258 detailComponent("Interior Refl", &myBSDF.rLambFront, myBSDF.rf);
259 detailComponent("Exterior Refl", &myBSDF.rLambBack, myBSDF.rb);
260 detailComponent("Int->Ext Trans", &myBSDF.tLambFront, myBSDF.tf);
261 detailComponent("Ext->Int Trans", &myBSDF.tLambBack, myBSDF.tb);
262 puts("Component\tReciprocity Error (min avg max %)");
263 checkReciprocity("Interior Refl", 1, 1, &myBSDF, flags);
264 checkReciprocity("Exterior Refl", -1, -1, &myBSDF, flags);
265 checkReciprocity("Transmission", -1, 1, &myBSDF, flags);
266 SDfreeBSDF(&myBSDF);
267 return 1;
268 }
269
270 int
271 main(int argc, char *argv[])
272 {
273 int i;
274
275 if (argc < 2) {
276 fprintf(stderr, "Usage: %s bsdf.xml ..\n", argv[0]);
277 return 1;
278 }
279 for (i = 1; i < argc; i++)
280 if (!checkXML(argv[i]))
281 return 1;
282 return 0;
283 }