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

# User Rev Content
1 greg 2.1 #ifndef lint
2 greg 2.4 static const char RCSid[] = "$Id: m_bsdf.c,v 2.3 2011/02/19 01:48:59 greg Exp $";
3 greg 2.1 #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 greg 2.4 /*
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 greg 2.1 typedef struct {
58     OBJREC *mp; /* material pointer */
59     RAY *pr; /* intersected ray */
60     FVECT pnorm; /* perturbed surface normal */
61 greg 2.4 FVECT vray; /* local outgoing (return) vector */
62     double sr_vpsa; /* sqrt of BSDF projected solid angle */
63 greg 2.1 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 greg 2.4 /* 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 greg 2.1 /* 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 greg 2.3 BSDFDAT *np = (BSDFDAT *)nnp;
101 greg 2.1 SDError ec;
102     SDValue sv;
103 greg 2.4 FVECT vsrc;
104     FVECT vjit;
105 greg 2.1 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 greg 2.4 if (SDmapDir(vsrc, np->toloc, ldir) != SDEnone)
137 greg 2.1 return;
138 greg 2.4 bsdf_jitter(vjit, np);
139     ec = SDevalBSDF(&sv, vjit, vsrc, np->sd);
140 greg 2.1 if (ec)
141 greg 2.2 objerror(np->mp, USER, transSDError(ec));
142 greg 2.1
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 greg 2.3 multcolor(ctmp, ctmp1); /* apply derated pattern */
156 greg 2.1 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 greg 2.4 FVECT vjit, vsmp;
175 greg 2.1 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 greg 2.4 bsdf_jitter(vjit, ndp);
188     ec = SDsampComponent(&bsv, vsmp, vjit, ntrials ? frandom()
189     : urand(ilhash(dimlist,ndims)+samplendx), dcp);
190 greg 2.1 if (ec)
191 greg 2.2 objerror(ndp->mp, USER, transSDError(ec));
192 greg 2.1 /* zero component? */
193     if (bsv.cieY <= FTINY)
194     break;
195     /* map vector to world */
196 greg 2.4 if (SDmapDir(sr.rdir, ndp->fromloc, vsmp) != SDEnone)
197 greg 2.1 break;
198     /* unintentional penetration? */
199 greg 2.4 if (DOT(sr.rdir, ndp->pr->ron) > .0 ^ vsmp[2] > .0)
200 greg 2.1 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 greg 2.3 if (ndp->thick > FTINY) { /* need to move origin? */
214     sthick = (ndp->pr->rod > .0) ? -ndp->thick : ndp->thick;
215 greg 2.4 if (sthick < .0 ^ vsmp[2] > .0)
216 greg 2.3 VSUM(sr.rorg, sr.rorg, ndp->pr->ron, sthick);
217     }
218 greg 2.1 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 greg 2.3 if (dfp->maxHemi > FTINY) { /* XXX no color from BSDF */
254 greg 2.4 FVECT vjit;
255     double d;
256 greg 2.1 COLOR ctmp;
257 greg 2.4 bsdf_jitter(vjit, ndp);
258     d = SDdirectHemi(vjit, sflags, ndp->sd);
259 greg 2.1 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 greg 2.2 /* get BSDF data */
294     nd.sd = loadBSDF(m->oargs.sarg[1]);
295 greg 2.1 /* 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 greg 2.3 if ((nd.thick > FTINY) & (nd.sd->tf != NULL))
304     raytrans(r); /* pass-through */
305 greg 2.1 SDfreeCache(nd.sd);
306     return(1); /* else shadow */
307     }
308     /* check unscattered ray */
309 greg 2.3 if (!(r->crtype & (SPECULAR|AMBIENT)) &&
310     (nd.thick > FTINY) & (nd.sd->tf != NULL)) {
311 greg 2.1 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 greg 2.3 if (!backvis && (nd.sd->rb == NULL) &
326     (nd.sd->tf == NULL)) {
327 greg 2.1 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 greg 2.4 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 greg 2.1 }
373     if (!ec)
374     ec = SDinvXform(nd.fromloc, nd.toloc);
375 greg 2.4 /* 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 greg 2.2 objerror(m, WARNING, transSDError(ec));
382 greg 2.1 SDfreeCache(nd.sd);
383     return(1);
384     }
385 greg 2.4
386 greg 2.1 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     }