Back to index

radiance  4R0+20100331
m_brdf.c
Go to the documentation of this file.
00001 #ifndef lint
00002 static const char    RCSid[] = "$Id: m_brdf.c,v 2.25 2007/09/07 15:25:01 greg Exp $";
00003 #endif
00004 /*
00005  *  Shading for materials with arbitrary BRDF's
00006  */
00007 
00008 #include "copyright.h"
00009 
00010 #include  "ray.h"
00011 #include  "ambient.h"
00012 #include  "data.h"
00013 #include  "source.h"
00014 #include  "otypes.h"
00015 #include  "rtotypes.h"
00016 #include  "func.h"
00017 
00018 /*
00019  *     Arguments to this material include the color and specularity.
00020  *  String arguments include the reflection function and files.
00021  *  The BRDF is currently used just for the specular component to light
00022  *  sources.  Reflectance values or data coordinates are functions
00023  *  of the direction to the light source.  (Data modification functions
00024  *  are passed the source direction as args 2-4.)
00025  *     We orient the surface towards the incoming ray, so a single
00026  *  surface can be used to represent an infinitely thin object.
00027  *
00028  *  Arguments for MAT_PFUNC and MAT_MFUNC are:
00029  *     2+     func   funcfile      transform
00030  *     0
00031  *     4+     red    grn    blu    specularity   A5 ..
00032  *
00033  *  Arguments for MAT_PDATA and MAT_MDATA are:
00034  *     4+     func   datafile      funcfile      v0 ..  transform
00035  *     0
00036  *     4+     red    grn    blu    specularity   A5 ..
00037  *
00038  *  Arguments for MAT_TFUNC are:
00039  *     2+     func   funcfile      transform
00040  *     0
00041  *     4+     red    grn    blu    rspec  trans  tspec  A7 ..
00042  *
00043  *  Arguments for MAT_TDATA are:
00044  *     4+     func   datafile      funcfile      v0 ..  transform
00045  *     0
00046  *     4+     red    grn    blu    rspec  trans  tspec  A7 ..
00047  *
00048  *  Arguments for the more general MAT_BRTDF are:
00049  *     10+    rrefl  grefl  brefl
00050  *            rtrns  gtrns  btrns
00051  *            rbrtd  gbrtd  bbrtd
00052  *            funcfile      transform
00053  *     0
00054  *     9+     rdf    gdf    bdf
00055  *            rdb    gdb    bdb
00056  *            rdt    gdt    bdt    A10 ..
00057  *
00058  *     In addition to the normal variables available to functions,
00059  *  we define the following:
00060  *            NxP, NyP, NzP -             perturbed surface normal
00061  *            RdotP -                     perturbed ray dot product
00062  *            CrP, CgP, CbP -             perturbed material color (or pattern)
00063  */
00064 
00065 typedef struct {
00066        OBJREC  *mp;         /* material pointer */
00067        RAY  *pr;            /* intersected ray */
00068        DATARRAY  *dp;              /* data array for PDATA, MDATA or TDATA */
00069        COLOR  mcolor;              /* material (or pattern) color */
00070        COLOR  rdiff;        /* diffuse reflection */
00071        COLOR  tdiff;        /* diffuse transmission */
00072        double  rspec;              /* specular reflectance (1 for BRDTF) */
00073        double  trans;              /* transmissivity (.5 for BRDTF) */
00074        double  tspec;              /* specular transmittance (1 for BRDTF) */
00075        FVECT  pnorm;        /* perturbed surface normal */
00076        double  pdot;        /* perturbed dot product */
00077 }  BRDFDAT;          /* BRDF material data */
00078 
00079 
00080 static srcdirf_t dirbrdf;
00081 static int setbrdfunc(BRDFDAT  *np);
00082 
00083 
00084 static void
00085 dirbrdf(             /* compute source contribution */
00086        COLOR  cval,                /* returned coefficient */
00087        void  *nnp,          /* material data */
00088        FVECT  ldir,                /* light source direction */
00089        double  omega               /* light source size */
00090 )
00091 {
00092        register BRDFDAT *np = nnp;
00093        double  ldot;
00094        double  dtmp;
00095        COLOR  ctmp;
00096        FVECT  ldx;
00097        static double  vldx[5], pt[MAXDIM];
00098        register char **sa;
00099        register int  i;
00100 #define lddx (vldx+1)
00101 
00102        setcolor(cval, 0.0, 0.0, 0.0);
00103        
00104        ldot = DOT(np->pnorm, ldir);
00105 
00106        if (ldot <= FTINY && ldot >= -FTINY)
00107               return;              /* too close to grazing */
00108 
00109        if (ldot < 0.0 ? np->trans <= FTINY : np->trans >= 1.0-FTINY)
00110               return;              /* wrong side */
00111 
00112        if (ldot > 0.0) {
00113               /*
00114                *  Compute and add diffuse reflected component to returned
00115                *  color.  The diffuse reflected component will always be
00116                *  modified by the color of the material.
00117                */
00118               copycolor(ctmp, np->rdiff);
00119               dtmp = ldot * omega / PI;
00120               scalecolor(ctmp, dtmp);
00121               addcolor(cval, ctmp);
00122        } else {
00123               /*
00124                *  Diffuse transmitted component.
00125                */
00126               copycolor(ctmp, np->tdiff);
00127               dtmp = -ldot * omega / PI;
00128               scalecolor(ctmp, dtmp);
00129               addcolor(cval, ctmp);
00130        }
00131        if (ldot > 0.0 ? np->rspec <= FTINY : np->tspec <= FTINY)
00132               return;              /* diffuse only */
00133                                    /* set up function */
00134        setbrdfunc(np);
00135        sa = np->mp->oargs.sarg;
00136        errno = 0;
00137                                    /* transform light vector */
00138        multv3(ldx, ldir, funcxf.xfm);
00139        for (i = 0; i < 3; i++)
00140               lddx[i] = ldx[i]/funcxf.sca;
00141        lddx[3] = omega;
00142                                    /* compute BRTDF */
00143        if (np->mp->otype == MAT_BRTDF) {
00144               if (sa[6][0] == '0')        /* special case */
00145                      colval(ctmp,RED) = 0.0;
00146               else
00147                      colval(ctmp,RED) = funvalue(sa[6], 4, lddx);
00148               if (sa[7][0] == '0')
00149                      colval(ctmp,GRN) = 0.0;
00150               else if (!strcmp(sa[7],sa[6]))
00151                      colval(ctmp,GRN) = colval(ctmp,RED);
00152               else
00153                      colval(ctmp,GRN) = funvalue(sa[7], 4, lddx);
00154               if (!strcmp(sa[8],sa[6]))
00155                      colval(ctmp,BLU) = colval(ctmp,RED);
00156               else if (!strcmp(sa[8],sa[7]))
00157                      colval(ctmp,BLU) = colval(ctmp,GRN);
00158               else
00159                      colval(ctmp,BLU) = funvalue(sa[8], 4, lddx);
00160               dtmp = bright(ctmp);
00161        } else if (np->dp == NULL) {
00162               dtmp = funvalue(sa[0], 4, lddx);
00163               setcolor(ctmp, dtmp, dtmp, dtmp);
00164        } else {
00165               for (i = 0; i < np->dp->nd; i++)
00166                      pt[i] = funvalue(sa[3+i], 4, lddx);
00167               vldx[0] = datavalue(np->dp, pt);
00168               dtmp = funvalue(sa[0], 5, vldx);
00169               setcolor(ctmp, dtmp, dtmp, dtmp);
00170        }
00171        if ((errno == EDOM) | (errno == ERANGE)) {
00172               objerror(np->mp, WARNING, "compute error");
00173               return;
00174        }
00175        if (dtmp <= FTINY)
00176               return;
00177        if (ldot > 0.0) {
00178               /*
00179                *  Compute reflected non-diffuse component.
00180                */
00181               if ((np->mp->otype == MAT_MFUNC) | (np->mp->otype == MAT_MDATA))
00182                      multcolor(ctmp, np->mcolor);
00183               dtmp = ldot * omega * np->rspec;
00184               scalecolor(ctmp, dtmp);
00185               addcolor(cval, ctmp);
00186        } else {
00187               /*
00188                *  Compute transmitted non-diffuse component.
00189                */
00190               if ((np->mp->otype == MAT_TFUNC) | (np->mp->otype == MAT_TDATA))
00191                      multcolor(ctmp, np->mcolor);
00192               dtmp = -ldot * omega * np->tspec;
00193               scalecolor(ctmp, dtmp);
00194               addcolor(cval, ctmp);
00195        }
00196 #undef lddx
00197 }
00198 
00199 
00200 extern int
00201 m_brdf(                     /* color a ray that hit a BRDTfunc material */
00202        register OBJREC  *m,
00203        register RAY  *r
00204 )
00205 {
00206        int  hitfront = 1;
00207        BRDFDAT  nd;
00208        RAY  sr;
00209        double  mirtest=0, mirdist=0;
00210        double  transtest, transdist;
00211        int  hasrefl, hastrans;
00212        int  hastexture;
00213        COLOR  ctmp;
00214        FVECT  vtmp;
00215        double  d;
00216        register MFUNC  *mf;
00217        register int  i;
00218                                           /* check arguments */
00219        if ((m->oargs.nsargs < 10) | (m->oargs.nfargs < 9))
00220               objerror(m, USER, "bad # arguments");
00221        nd.mp = m;
00222        nd.pr = r;
00223                                           /* dummy values */
00224        nd.rspec = nd.tspec = 1.0;
00225        nd.trans = 0.5;
00226                                           /* diffuse reflectance */
00227        if (r->rod > 0.0)
00228               setcolor(nd.rdiff, m->oargs.farg[0],
00229                             m->oargs.farg[1],
00230                             m->oargs.farg[2]);
00231        else
00232               setcolor(nd.rdiff, m->oargs.farg[3],
00233                             m->oargs.farg[4],
00234                             m->oargs.farg[5]);
00235                                           /* diffuse transmittance */
00236        setcolor(nd.tdiff, m->oargs.farg[6],
00237                      m->oargs.farg[7],
00238                      m->oargs.farg[8]);
00239                                           /* get modifiers */
00240        raytexture(r, m->omod);
00241        hastexture = DOT(r->pert,r->pert) > FTINY*FTINY;
00242        if (hastexture) {                  /* perturb normal */
00243               nd.pdot = raynormal(nd.pnorm, r);
00244        } else {
00245               VCOPY(nd.pnorm, r->ron);
00246               nd.pdot = r->rod;
00247        }
00248        if (r->rod < 0.0) {                /* orient perturbed values */
00249               nd.pdot = -nd.pdot;
00250               for (i = 0; i < 3; i++) {
00251                      nd.pnorm[i] = -nd.pnorm[i];
00252                      r->pert[i] = -r->pert[i];
00253               }
00254               hitfront = 0;
00255        }
00256        copycolor(nd.mcolor, r->pcol);            /* get pattern color */
00257        multcolor(nd.rdiff, nd.mcolor);           /* modify diffuse values */
00258        multcolor(nd.tdiff, nd.mcolor);
00259        hasrefl = bright(nd.rdiff) > FTINY;
00260        hastrans = bright(nd.tdiff) > FTINY;
00261                                           /* load cal file */
00262        nd.dp = NULL;
00263        mf = getfunc(m, 9, 0x3f, 0);
00264                                           /* compute transmitted ray */
00265        setbrdfunc(&nd);
00266        errno = 0;
00267        setcolor(ctmp, evalue(mf->ep[3]),
00268                      evalue(mf->ep[4]),
00269                      evalue(mf->ep[5]));
00270        if ((errno == EDOM) | (errno == ERANGE))
00271               objerror(m, WARNING, "compute error");
00272        else if (rayorigin(&sr, TRANS, r, ctmp) == 0) {
00273               if (!(r->crtype & SHADOW) && hastexture) {
00274                      for (i = 0; i < 3; i++)     /* perturb direction */
00275                             sr.rdir[i] = r->rdir[i] - .75*r->pert[i];
00276                      if (normalize(sr.rdir) == 0.0) {
00277                             objerror(m, WARNING, "illegal perturbation");
00278                             VCOPY(sr.rdir, r->rdir);
00279                      }
00280               } else {
00281                      VCOPY(sr.rdir, r->rdir);
00282               }
00283               rayvalue(&sr);
00284               multcolor(sr.rcol, sr.rcoef);
00285               addcolor(r->rcol, sr.rcol);
00286               if (!hastexture) {
00287                      transtest = 2.0*bright(sr.rcol);
00288                      transdist = r->rot + sr.rt;
00289               }
00290        }
00291        if (r->crtype & SHADOW)                   /* the rest is shadow */
00292               return(1);
00293                                           /* compute reflected ray */
00294        setbrdfunc(&nd);
00295        errno = 0;
00296        setcolor(ctmp, evalue(mf->ep[0]),
00297                      evalue(mf->ep[1]),
00298                      evalue(mf->ep[2]));
00299        if ((errno == EDOM) | (errno == ERANGE))
00300               objerror(m, WARNING, "compute error");
00301        else if (rayorigin(&sr, REFLECTED, r, ctmp) == 0) {
00302               for (i = 0; i < 3; i++)
00303                      sr.rdir[i] = r->rdir[i] + 2.0*nd.pdot*nd.pnorm[i];
00304               rayvalue(&sr);
00305               multcolor(sr.rcol, sr.rcoef);
00306               addcolor(r->rcol, sr.rcol);
00307               if (!hastexture && r->ro != NULL && isflat(r->ro->otype)) {
00308                      mirtest = 2.0*bright(sr.rcol);
00309                      mirdist = r->rot + sr.rt;
00310               }
00311        }
00312                                           /* compute ambient */
00313        if (hasrefl) {
00314               if (!hitfront)
00315                      flipsurface(r);
00316               copycolor(ctmp, nd.rdiff);
00317               multambient(ctmp, r, nd.pnorm);
00318               addcolor(r->rcol, ctmp);    /* add to returned color */
00319               if (!hitfront)
00320                      flipsurface(r);
00321        }
00322        if (hastrans) {                           /* from other side */
00323               if (hitfront)
00324                      flipsurface(r);
00325               vtmp[0] = -nd.pnorm[0];
00326               vtmp[1] = -nd.pnorm[1];
00327               vtmp[2] = -nd.pnorm[2];
00328               copycolor(ctmp, nd.tdiff);
00329               multambient(ctmp, r, vtmp);
00330               addcolor(r->rcol, ctmp);
00331               if (hitfront)
00332                      flipsurface(r);
00333        }
00334        if (hasrefl | hastrans || m->oargs.sarg[6][0] != '0')
00335               direct(r, dirbrdf, &nd);    /* add direct component */
00336 
00337        d = bright(r->rcol);               /* set effective distance */
00338        if (transtest > d)
00339               r->rt = transdist;
00340        else if (mirtest > d)
00341               r->rt = mirdist;
00342 
00343        return(1);
00344 }
00345 
00346 
00347 
00348 extern int
00349 m_brdf2(                    /* color a ray that hit a BRDF material */
00350        register OBJREC  *m,
00351        register RAY  *r
00352 )
00353 {
00354        BRDFDAT  nd;
00355        COLOR  ctmp;
00356        FVECT  vtmp;
00357        double  dtmp;
00358                                           /* always a shadow */
00359        if (r->crtype & SHADOW)
00360               return(1);
00361                                           /* check arguments */
00362        if ((m->oargs.nsargs < (hasdata(m->otype)?4:2)) | (m->oargs.nfargs <
00363                      ((m->otype==MAT_TFUNC)|(m->otype==MAT_TDATA)?6:4)))
00364               objerror(m, USER, "bad # arguments");
00365                                           /* check for back side */
00366        if (r->rod < 0.0) {
00367               if (!backvis && m->otype != MAT_TFUNC
00368                             && m->otype != MAT_TDATA) {
00369                      raytrans(r);
00370                      return(1);
00371               }
00372               raytexture(r, m->omod);
00373               flipsurface(r);                    /* reorient if backvis */
00374        } else
00375               raytexture(r, m->omod);
00376 
00377        nd.mp = m;
00378        nd.pr = r;
00379                                           /* get material color */
00380        setcolor(nd.mcolor, m->oargs.farg[0],
00381                      m->oargs.farg[1],
00382                      m->oargs.farg[2]);
00383                                           /* get specular component */
00384        nd.rspec = m->oargs.farg[3];
00385                                           /* compute transmittance */
00386        if ((m->otype == MAT_TFUNC) | (m->otype == MAT_TDATA)) {
00387               nd.trans = m->oargs.farg[4]*(1.0 - nd.rspec);
00388               nd.tspec = nd.trans * m->oargs.farg[5];
00389               dtmp = nd.trans - nd.tspec;
00390               setcolor(nd.tdiff, dtmp, dtmp, dtmp);
00391        } else {
00392               nd.tspec = nd.trans = 0.0;
00393               setcolor(nd.tdiff, 0.0, 0.0, 0.0);
00394        }
00395                                           /* compute reflectance */
00396        dtmp = 1.0 - nd.trans - nd.rspec;
00397        setcolor(nd.rdiff, dtmp, dtmp, dtmp);
00398        nd.pdot = raynormal(nd.pnorm, r);  /* perturb normal */
00399        multcolor(nd.mcolor, r->pcol);            /* modify material color */
00400        multcolor(nd.rdiff, nd.mcolor);
00401        multcolor(nd.tdiff, nd.mcolor);
00402                                           /* load auxiliary files */
00403        if (hasdata(m->otype)) {
00404               nd.dp = getdata(m->oargs.sarg[1]);
00405               getfunc(m, 2, 0, 0);
00406        } else {
00407               nd.dp = NULL;
00408               getfunc(m, 1, 0, 0);
00409        }
00410                                           /* compute ambient */
00411        if (nd.trans < 1.0-FTINY) {
00412               copycolor(ctmp, nd.mcolor); /* modified by material color */
00413               scalecolor(ctmp, 1.0-nd.trans);
00414               multambient(ctmp, r, nd.pnorm);
00415               addcolor(r->rcol, ctmp);    /* add to returned color */
00416        }
00417        if (nd.trans > FTINY) {            /* from other side */
00418               flipsurface(r);
00419               vtmp[0] = -nd.pnorm[0];
00420               vtmp[1] = -nd.pnorm[1];
00421               vtmp[2] = -nd.pnorm[2];
00422               copycolor(ctmp, nd.mcolor);
00423               scalecolor(ctmp, nd.trans);
00424               multambient(ctmp, r, vtmp);
00425               addcolor(r->rcol, ctmp);
00426               flipsurface(r);
00427        }
00428                                           /* add direct component */
00429        direct(r, dirbrdf, &nd);
00430 
00431        return(1);
00432 }
00433 
00434 
00435 static int
00436 setbrdfunc(                 /* set up brdf function and variables */
00437        register BRDFDAT  *np
00438 )
00439 {
00440        FVECT  vec;
00441 
00442        if (setfunc(np->mp, np->pr) == 0)
00443               return(0);    /* it's OK, setfunc says we're done */
00444                             /* else (re)assign special variables */
00445        multv3(vec, np->pnorm, funcxf.xfm);
00446        varset("NxP", '=', vec[0]/funcxf.sca);
00447        varset("NyP", '=', vec[1]/funcxf.sca);
00448        varset("NzP", '=', vec[2]/funcxf.sca);
00449        varset("RdotP", '=', np->pdot <= -1.0 ? -1.0 :
00450                      np->pdot >= 1.0 ? 1.0 : np->pdot);
00451        varset("CrP", '=', colval(np->mcolor,RED));
00452        varset("CgP", '=', colval(np->mcolor,GRN));
00453        varset("CbP", '=', colval(np->mcolor,BLU));
00454        return(1);
00455 }