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

# User Rev Content
1 greg 2.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     }