ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/m_bsdf.c
Revision: 2.1
Committed: Fri Feb 18 00:40:25 2011 UTC (13 years, 3 months ago) by greg
Content type: text/plain
Branch: MAIN
Log Message:
Major code reorg, moving mgflib to common and introducing BSDF material

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id$";
3 #endif
4 /*
5 * Shading for materials with BSDFs taken from XML data files
6 */
7
8 #include "copyright.h"
9
10 #include "ray.h"
11 #include "paths.h"
12 #include "ambient.h"
13 #include "source.h"
14 #include "func.h"
15 #include "bsdf.h"
16 #include "random.h"
17
18 /*
19 * Arguments to this material include optional diffuse colors.
20 * String arguments include the BSDF and function files.
21 * A thickness variable causes the strange but useful behavior
22 * of translating transmitted rays this distance past the surface
23 * intersection in the normal direction to bypass intervening geometry.
24 * This only affects scattered, non-source directed samples. Thus,
25 * thickness is relevant only if there is a transmitted component.
26 * A positive thickness has the further side-effect that an unscattered
27 * (view) ray will pass right through our material if it has any
28 * non-diffuse transmission, making our BSDF invisible. This allows the
29 * underlying geometry to become visible. A matching surface should be
30 * placed on the other side, less than the thickness away, if the backside
31 * reflectance is non-zero.
32 * The "up" vector for the BSDF is given by three variables, defined
33 * (along with the thickness) by the named function file, or '.' if none.
34 * Together with the surface normal, this defines the local coordinate
35 * system for the BSDF.
36 * We do not reorient the surface, so if the BSDF has no back-side
37 * reflectance and none is given in the real arguments, the surface will
38 * appear as black when viewed from behind (unless backvis is false).
39 * The diffuse compnent arguments are added to components in the BSDF file,
40 * not multiplied. However, patterns affect this material as a multiplier
41 * on everything except non-diffuse reflection.
42 *
43 * Arguments for MAT_BSDF are:
44 * 6+ thick BSDFfile ux uy uz funcfile transform
45 * 0
46 * 0|3|9 rdf gdf bdf
47 * rdb gdb bdb
48 * rdt gdt bdt
49 */
50
51 typedef struct {
52 OBJREC *mp; /* material pointer */
53 RAY *pr; /* intersected ray */
54 FVECT pnorm; /* perturbed surface normal */
55 FVECT vinc; /* local incident vector */
56 RREAL toloc[3][3]; /* world to local BSDF coords */
57 RREAL fromloc[3][3]; /* local BSDF coords to world */
58 double thick; /* surface thickness */
59 SDData *sd; /* loaded BSDF data */
60 COLOR runsamp; /* BSDF hemispherical reflection */
61 COLOR rdiff; /* added diffuse reflection */
62 COLOR tunsamp; /* BSDF hemispherical transmission */
63 COLOR tdiff; /* added diffuse transmission */
64 } BSDFDAT; /* BSDF material data */
65
66 #define cvt_sdcolor(cv, svp) ccy2rgb(&(svp)->spec, (svp)->cieY, cv)
67
68 /* Convert error from BSDF library */
69 static char *
70 cvt_sderr(SDError ec)
71 {
72 if (!SDerrorDetail[0])
73 return(strcpy(errmsg, SDerrorEnglish[ec]));
74 sprintf(errmsg, "%s: %s", SDerrorEnglish[ec], SDerrorDetail);
75 return(errmsg);
76 }
77
78 /* Compute source contribution for BSDF */
79 static void
80 dirbsdf(
81 COLOR cval, /* returned coefficient */
82 void *nnp, /* material data */
83 FVECT ldir, /* light source direction */
84 double omega /* light source size */
85 )
86 {
87 BSDFDAT *np = nnp;
88 SDError ec;
89 SDValue sv;
90 FVECT vout;
91 double ldot;
92 double dtmp;
93 COLOR ctmp;
94
95 setcolor(cval, .0, .0, .0);
96
97 ldot = DOT(np->pnorm, ldir);
98 if ((-FTINY <= ldot) & (ldot <= FTINY))
99 return;
100
101 if (ldot > .0 && bright(np->rdiff) > FTINY) {
102 /*
103 * Compute added diffuse reflected component.
104 */
105 copycolor(ctmp, np->rdiff);
106 dtmp = ldot * omega * (1./PI);
107 scalecolor(ctmp, dtmp);
108 addcolor(cval, ctmp);
109 }
110 if (ldot < .0 && bright(np->tdiff) > FTINY) {
111 /*
112 * Compute added diffuse transmission.
113 */
114 copycolor(ctmp, np->tdiff);
115 dtmp = -ldot * omega * (1.0/PI);
116 scalecolor(ctmp, dtmp);
117 addcolor(cval, ctmp);
118 }
119 /*
120 * Compute scattering coefficient using BSDF.
121 */
122 if (SDmapDir(vout, np->toloc, ldir) != SDEnone)
123 return;
124 ec = SDevalBSDF(&sv, vout, np->vinc, np->sd);
125 if (ec)
126 objerror(np->mp, USER, cvt_sderr(ec));
127
128 if (sv.cieY <= FTINY) /* not worth using? */
129 return;
130 cvt_sdcolor(ctmp, &sv);
131 if (ldot > .0) { /* pattern only diffuse reflection */
132 COLOR ctmp1, ctmp2;
133 dtmp = (np->pr->rod > .0) ? np->sd->rLambFront.cieY
134 : np->sd->rLambBack.cieY;
135 dtmp /= PI * sv.cieY; /* diffuse fraction */
136 copycolor(ctmp2, np->pr->pcol);
137 scalecolor(ctmp2, dtmp);
138 setcolor(ctmp1, 1.-dtmp, 1.-dtmp, 1.-dtmp);
139 addcolor(ctmp1, ctmp2);
140 multcolor(ctmp, ctmp1); /* apply desaturated pattern */
141 dtmp = ldot * omega;
142 } else { /* full pattern on transmission */
143 multcolor(ctmp, np->pr->pcol);
144 dtmp = -ldot * omega;
145 }
146 scalecolor(ctmp, dtmp);
147 addcolor(cval, ctmp);
148 }
149
150 /* Sample separate BSDF component */
151 static int
152 sample_sdcomp(BSDFDAT *ndp, SDComponent *dcp, int usepat)
153 {
154 int nstarget = 1;
155 int nsent = 0;
156 SDError ec;
157 SDValue bsv;
158 double sthick;
159 FVECT vout;
160 RAY sr;
161 int ntrials;
162 /* multiple samples? */
163 if (specjitter > 1.5) {
164 nstarget = specjitter*ndp->pr->rweight + .5;
165 if (nstarget < 1)
166 nstarget = 1;
167 }
168 /* run through our trials */
169 for (ntrials = 0; nsent < nstarget && ntrials < 9*nstarget; ntrials++) {
170 SDerrorDetail[0] = '\0';
171 /* sample direction & coef. */
172 ec = SDsampComponent(&bsv, vout, ndp->vinc,
173 ntrials ? frandom()
174 : urand(ilhash(dimlist,ndims)+samplendx),
175 dcp);
176 if (ec)
177 objerror(ndp->mp, USER, cvt_sderr(ec));
178 /* zero component? */
179 if (bsv.cieY <= FTINY)
180 break;
181 /* map vector to world */
182 if (SDmapDir(sr.rdir, ndp->fromloc, vout) != SDEnone)
183 break;
184 /* unintentional penetration? */
185 if (DOT(sr.rdir, ndp->pr->ron) > .0 ^ vout[2] > .0)
186 continue;
187 /* spawn a specular ray */
188 if (nstarget > 1)
189 bsv.cieY /= (double)nstarget;
190 cvt_sdcolor(sr.rcoef, &bsv); /* use color */
191 if (usepat) /* pattern on transmission */
192 multcolor(sr.rcoef, ndp->pr->pcol);
193 if (rayorigin(&sr, SPECULAR, ndp->pr, sr.rcoef) < 0) {
194 if (maxdepth > 0)
195 break;
196 ++nsent; /* Russian roulette victim */
197 continue;
198 }
199 /* need to move origin? */
200 sthick = (ndp->pr->rod > .0) ? -ndp->thick : ndp->thick;
201 if (sthick < .0 ^ vout[2] > .0)
202 VSUM(sr.rorg, sr.rorg, ndp->pr->ron, sthick);
203
204 rayvalue(&sr); /* send & evaluate sample */
205 multcolor(sr.rcol, sr.rcoef);
206 addcolor(ndp->pr->rcol, sr.rcol);
207 ++nsent;
208 }
209 return(nsent);
210 }
211
212 /* Sample non-diffuse components of BSDF */
213 static int
214 sample_sdf(BSDFDAT *ndp, int sflags)
215 {
216 int n, ntotal = 0;
217 SDSpectralDF *dfp;
218 COLORV *unsc;
219
220 if (sflags == SDsampSpT) {
221 unsc = ndp->tunsamp;
222 dfp = ndp->sd->tf;
223 cvt_sdcolor(unsc, &ndp->sd->tLamb);
224 } else /* sflags == SDsampSpR */ {
225 unsc = ndp->runsamp;
226 if (ndp->pr->rod > .0) {
227 dfp = ndp->sd->rf;
228 cvt_sdcolor(unsc, &ndp->sd->rLambFront);
229 } else {
230 dfp = ndp->sd->rb;
231 cvt_sdcolor(unsc, &ndp->sd->rLambBack);
232 }
233 }
234 multcolor(unsc, ndp->pr->pcol);
235 if (dfp == NULL) /* no specular component? */
236 return(0);
237 /* below sampling threshold? */
238 if (dfp->maxHemi <= specthresh+FTINY) {
239 if (dfp->maxHemi > FTINY) { /* XXX no color from BSDF! */
240 double d = SDdirectHemi(ndp->vinc, sflags, ndp->sd);
241 COLOR ctmp;
242 if (sflags == SDsampSpT) {
243 copycolor(ctmp, ndp->pr->pcol);
244 scalecolor(ctmp, d);
245 } else /* no pattern on reflection */
246 setcolor(ctmp, d, d, d);
247 addcolor(unsc, ctmp);
248 }
249 return(0);
250 }
251 /* else need to sample */
252 dimlist[ndims++] = (int)(size_t)ndp->mp;
253 ndims++;
254 for (n = dfp->ncomp; n--; ) { /* loop over components */
255 dimlist[ndims-1] = n + 9438;
256 ntotal += sample_sdcomp(ndp, &dfp->comp[n], sflags==SDsampSpT);
257 }
258 ndims -= 2;
259 return(ntotal);
260 }
261
262 /* Color a ray that hit a BSDF material */
263 int
264 m_bsdf(OBJREC *m, RAY *r)
265 {
266 COLOR ctmp;
267 SDError ec;
268 FVECT upvec, outVec;
269 MFUNC *mf;
270 BSDFDAT nd;
271 /* check arguments */
272 if ((m->oargs.nsargs < 6) | (m->oargs.nfargs > 9) |
273 (m->oargs.nfargs % 3))
274 objerror(m, USER, "bad # arguments");
275
276 SDerrorDetail[0] = '\0'; /* get BSDF data */
277 nd.sd = SDgetCache(m->oargs.sarg[1]);
278 if (nd.sd == NULL)
279 error(SYSTEM, "out of memory in m_bsdf");
280 if (!SDisLoaded(nd.sd)) {
281 char *pname = getpath(m->oargs.sarg[1], getrlibpath(), R_OK);
282 if (pname == NULL) {
283 sprintf(errmsg, "cannot find BSDF file \"%s\"",
284 m->oargs.sarg[1]);
285 objerror(m, USER, errmsg);
286 }
287 ec = SDloadFile(nd.sd, pname);
288 if (ec)
289 objerror(m, USER, cvt_sderr(ec));
290 SDretainSet = SDretainAll;
291 }
292 /* load cal file */
293 mf = getfunc(m, 5, 0x1d, 1);
294 /* get thickness */
295 nd.thick = evalue(mf->ep[0]);
296 if (nd.thick < .0)
297 nd.thick = .0;
298 /* check shadow */
299 if (r->crtype & SHADOW) {
300 SDfreeCache(nd.sd);
301 if (nd.thick > FTINY && nd.sd->tf != NULL &&
302 nd.sd->tf->maxHemi > FTINY)
303 raytrans(r); /* pass-through */
304 return(1); /* else shadow */
305 }
306 /* check unscattered ray */
307 if (!(r->crtype & (SPECULAR|AMBIENT)) && nd.thick > FTINY &&
308 nd.sd->tf != NULL && nd.sd->tf->maxHemi > FTINY) {
309 SDfreeCache(nd.sd);
310 raytrans(r); /* pass-through */
311 return(1);
312 }
313 /* diffuse reflectance */
314 if (r->rod > .0) {
315 if (m->oargs.nfargs < 3)
316 setcolor(nd.rdiff, .0, .0, .0);
317 else
318 setcolor(nd.rdiff, m->oargs.farg[0],
319 m->oargs.farg[1],
320 m->oargs.farg[2]);
321 } else {
322 if (m->oargs.nfargs < 6) { /* check invisible backside */
323 if (!backvis && (nd.sd->rb == NULL ||
324 nd.sd->rb->maxHemi <= FTINY) &&
325 (nd.sd->tf == NULL ||
326 nd.sd->tf->maxHemi <= FTINY)) {
327 SDfreeCache(nd.sd);
328 raytrans(r);
329 return(1);
330 }
331 setcolor(nd.rdiff, .0, .0, .0);
332 } else
333 setcolor(nd.rdiff, m->oargs.farg[3],
334 m->oargs.farg[4],
335 m->oargs.farg[5]);
336 }
337 /* diffuse transmittance */
338 if (m->oargs.nfargs < 9)
339 setcolor(nd.tdiff, .0, .0, .0);
340 else
341 setcolor(nd.tdiff, m->oargs.farg[6],
342 m->oargs.farg[7],
343 m->oargs.farg[8]);
344 nd.mp = m;
345 nd.pr = r;
346 /* get modifiers */
347 raytexture(r, m->omod);
348 if (bright(r->pcol) <= FTINY) { /* black pattern?! */
349 SDfreeCache(nd.sd);
350 return(1);
351 }
352 /* modify diffuse values */
353 multcolor(nd.rdiff, r->pcol);
354 multcolor(nd.tdiff, r->pcol);
355 /* get up vector */
356 upvec[0] = evalue(mf->ep[1]);
357 upvec[1] = evalue(mf->ep[2]);
358 upvec[2] = evalue(mf->ep[3]);
359 /* return to world coords */
360 if (mf->f != &unitxf) {
361 multv3(upvec, upvec, mf->f->xfm);
362 nd.thick *= mf->f->sca;
363 }
364 raynormal(nd.pnorm, r);
365 /* compute local BSDF xform */
366 ec = SDcompXform(nd.toloc, nd.pnorm, upvec);
367 if (!ec) {
368 nd.vinc[0] = -r->rdir[0];
369 nd.vinc[1] = -r->rdir[1];
370 nd.vinc[2] = -r->rdir[2];
371 ec = SDmapDir(nd.vinc, nd.toloc, nd.vinc);
372 }
373 if (!ec)
374 ec = SDinvXform(nd.fromloc, nd.toloc);
375 if (ec) {
376 objerror(m, WARNING, cvt_sderr(ec));
377 SDfreeCache(nd.sd);
378 return(1);
379 }
380 if (r->rod < .0) { /* perturb normal towards hit */
381 nd.pnorm[0] = -nd.pnorm[0];
382 nd.pnorm[1] = -nd.pnorm[1];
383 nd.pnorm[2] = -nd.pnorm[2];
384 }
385 /* sample reflection */
386 sample_sdf(&nd, SDsampSpR);
387 /* sample transmission */
388 sample_sdf(&nd, SDsampSpT);
389 /* compute indirect diffuse */
390 copycolor(ctmp, nd.rdiff);
391 addcolor(ctmp, nd.runsamp);
392 if (bright(ctmp) > FTINY) { /* ambient from this side */
393 if (r->rod < .0)
394 flipsurface(r);
395 multambient(ctmp, r, nd.pnorm);
396 addcolor(r->rcol, ctmp);
397 if (r->rod < .0)
398 flipsurface(r);
399 }
400 copycolor(ctmp, nd.tdiff);
401 addcolor(ctmp, nd.tunsamp);
402 if (bright(ctmp) > FTINY) { /* ambient from other side */
403 FVECT bnorm;
404 if (r->rod > .0)
405 flipsurface(r);
406 bnorm[0] = -nd.pnorm[0];
407 bnorm[1] = -nd.pnorm[1];
408 bnorm[2] = -nd.pnorm[2];
409 multambient(ctmp, r, bnorm);
410 addcolor(r->rcol, ctmp);
411 if (r->rod > .0)
412 flipsurface(r);
413 }
414 /* add direct component */
415 direct(r, dirbsdf, &nd);
416 /* clean up */
417 SDfreeCache(nd.sd);
418 return(1);
419 }