ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/m_bsdf.c
Revision: 2.4
Committed: Sat Feb 19 23:42:09 2011 UTC (13 years, 2 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.3: +53 -19 lines
Log Message:
Fixes to BSDF including blurring of angle boundaries

File Contents

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