home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 8 / CDASC08.ISO / NEWS / RADIANCE / SRC / RT / M_BRDF.C < prev    next >
C/C++ Source or Header  |  1993-10-07  |  10KB  |  346 lines

  1. /* Copyright (c) 1991 Regents of the University of California */
  2.  
  3. #ifndef lint
  4. static char SCCSid[] = "@(#)m_brdf.c 2.3 6/30/92 LBL";
  5. #endif
  6.  
  7. /*
  8.  *  Shading for materials with arbitrary BRDF's
  9.  */
  10.  
  11. #include  "ray.h"
  12.  
  13. #include  "data.h"
  14.  
  15. #include  "otypes.h"
  16.  
  17. #include  "func.h"
  18.  
  19. /*
  20.  *    Arguments to this material include the color and specularity.
  21.  *  String arguments include the reflection function and files.
  22.  *  The BRDF is currently used just for the specular component to light
  23.  *  sources.  Reflectance values or data coordinates are functions
  24.  *  of the direction to the light source.
  25.  *    We orient the surface towards the incoming ray, so a single
  26.  *  surface can be used to represent an infinitely thin object.
  27.  *
  28.  *  Arguments for MAT_PFUNC and MAT_MFUNC are:
  29.  *    2+    func    funcfile    transform
  30.  *    0
  31.  *    4+    red    grn    blu    specularity    A5 ..
  32.  *
  33.  *  Arguments for MAT_PDATA and MAT_MDATA are:
  34.  *    4+    func    datafile    funcfile    v0 ..    transform
  35.  *    0
  36.  *    4+    red    grn    blu    specularity    A5 ..
  37.  *
  38.  *  Arguments for MAT_TFUNC are:
  39.  *    2+    func    funcfile    transform
  40.  *    0
  41.  *    4+    red    grn    blu    rspec    trans    tspec    A7 ..
  42.  *
  43.  *  Arguments for MAT_TDATA are:
  44.  *    4+    func    datafile    funcfile    v0 ..    transform
  45.  *    0
  46.  *    4+    red    grn    blu    rspec    trans    tspec    A7 ..
  47.  *
  48.  *  Arguments for the more general MAT_BRTDF are:
  49.  *    10+    rrefl    grefl    brefl
  50.  *        rtrns    gtrns    btrns
  51.  *        rbrtd    gbrtd    bbrtd
  52.  *        funcfile    transform
  53.  *    0
  54.  *    6+    red    grn    blu    rspec    trans    tspec    A7 ..
  55.  *
  56.  *    In addition to the normal variables available to functions,
  57.  *  we define the following:
  58.  *        NxP, NyP, NzP -        perturbed surface normal
  59.  *        RdotP -            perturbed ray dot product
  60.  *        CrP, CgP, CbP -        perturbed material color
  61.  */
  62.  
  63. typedef struct {
  64.     OBJREC  *mp;        /* material pointer */
  65.     RAY  *pr;        /* intersected ray */
  66.     DATARRAY  *dp;        /* data array for PDATA, MDATA or TDATA */
  67.     COLOR  mcolor;        /* color of this material */
  68.     double  rspec;        /* specular reflection */
  69.     double    rdiff;        /* diffuse reflection */
  70.     double  trans;        /* transmissivity */
  71.     double  tspec;        /* specular transmission */
  72.     double  tdiff;        /* diffuse transmission */
  73.     FVECT  pnorm;        /* perturbed surface normal */
  74.     double  pdot;        /* perturbed dot product */
  75. }  BRDFDAT;        /* BRDF material data */
  76.  
  77.  
  78. dirbrdf(cval, np, ldir, omega)        /* compute source contribution */
  79. COLOR  cval;            /* returned coefficient */
  80. register BRDFDAT  *np;        /* material data */
  81. FVECT  ldir;            /* light source direction */
  82. double  omega;            /* light source size */
  83. {
  84.     double  ldot;
  85.     double  dtmp;
  86.     COLOR  ctmp;
  87.     FVECT  ldx;
  88.     double  lddx[3], pt[MAXDIM];
  89.     register char    **sa;
  90.     register int    i;
  91.  
  92.     setcolor(cval, 0.0, 0.0, 0.0);
  93.     
  94.     ldot = DOT(np->pnorm, ldir);
  95.  
  96.     if (ldot <= FTINY && ldot >= -FTINY)
  97.         return;        /* too close to grazing */
  98.     if (ldot < 0.0 ? np->trans <= FTINY : np->trans >= 1.0-FTINY)
  99.         return;        /* wrong side */
  100.  
  101.     if (ldot > 0.0 && np->rdiff > FTINY) {
  102.         /*
  103.          *  Compute and add diffuse reflected component to returned
  104.          *  color.  The diffuse reflected component will always be
  105.          *  modified by the color of the material.
  106.          */
  107.         copycolor(ctmp, np->mcolor);
  108.         dtmp = ldot * omega * np->rdiff / PI;
  109.         scalecolor(ctmp, dtmp);
  110.         addcolor(cval, ctmp);
  111.     }
  112.     if (ldot < 0.0 && np->tdiff > FTINY) {
  113.         /*
  114.          *  Diffuse transmitted component.
  115.          */
  116.         copycolor(ctmp, np->mcolor);
  117.         dtmp = -ldot * omega * np->tdiff / PI;
  118.         scalecolor(ctmp, dtmp);
  119.         addcolor(cval, ctmp);
  120.     }
  121.     if (ldot > 0.0 ? np->rspec <= FTINY : np->tspec <= FTINY)
  122.         return;        /* no specular component */
  123.                     /* set up function */
  124.     setbrdfunc(np);
  125.     sa = np->mp->oargs.sarg;
  126.     errno = 0;
  127.                     /* transform light vector */
  128.     multv3(ldx, ldir, funcxf.xfm);
  129.     for (i = 0; i < 3; i++)
  130.         lddx[i] = ldx[i]/funcxf.sca;
  131.                     /* compute BRTDF */
  132.     if (np->mp->otype == MAT_BRTDF) {
  133.         colval(ctmp,RED) = funvalue(sa[6], 3, lddx);
  134.         if (!strcmp(sa[7],sa[6]))
  135.             colval(ctmp,GRN) = colval(ctmp,RED);
  136.         else
  137.             colval(ctmp,GRN) = funvalue(sa[7], 3, lddx);
  138.         if (!strcmp(sa[8],sa[6]))
  139.             colval(ctmp,BLU) = colval(ctmp,RED);
  140.         else if (!strcmp(sa[8],sa[7]))
  141.             colval(ctmp,BLU) = colval(ctmp,GRN);
  142.         else
  143.             colval(ctmp,BLU) = funvalue(sa[8], 3, lddx);
  144.         dtmp = bright(ctmp);
  145.     } else if (np->dp == NULL) {
  146.         dtmp = funvalue(sa[0], 3, lddx);
  147.         setcolor(ctmp, dtmp, dtmp, dtmp);
  148.     } else {
  149.         for (i = 0; i < np->dp->nd; i++)
  150.             pt[i] = funvalue(sa[3+i], 3, lddx);
  151.         dtmp = datavalue(np->dp, pt);
  152.         dtmp = funvalue(sa[0], 1, &dtmp);
  153.         setcolor(ctmp, dtmp, dtmp, dtmp);
  154.     }
  155.     if (errno) {
  156.         objerror(np->mp, WARNING, "compute error");
  157.         return;
  158.     }
  159.     if (dtmp <= FTINY)
  160.         return;
  161.     if (ldot > 0.0) {
  162.         /*
  163.          *  Compute reflected non-diffuse component.
  164.          */
  165.         if (np->mp->otype == MAT_MFUNC || np->mp->otype == MAT_MDATA)
  166.             multcolor(ctmp, np->mcolor);
  167.         dtmp = ldot * omega * np->rspec;
  168.         scalecolor(ctmp, dtmp);
  169.         addcolor(cval, ctmp);
  170.     } else {
  171.         /*
  172.          *  Compute transmitted non-diffuse component.
  173.          */
  174.         if (np->mp->otype == MAT_TFUNC || np->mp->otype == MAT_TDATA)
  175.             multcolor(ctmp, np->mcolor);
  176.         dtmp = -ldot * omega * np->tspec;
  177.         scalecolor(ctmp, dtmp);
  178.         addcolor(cval, ctmp);
  179.     }
  180. }
  181.  
  182.  
  183. m_brdf(m, r)            /* color a ray which hit a BRDF material */
  184. register OBJREC  *m;
  185. register RAY  *r;
  186. {
  187.     int  minsa, minfa;
  188.     BRDFDAT  nd;
  189.     double  transtest, transdist;
  190.     COLOR  ctmp;
  191.     double  dtmp, tspect, rspecr;
  192.     MFUNC  *mf;
  193.     register int  i;
  194.                         /* check arguments */
  195.     switch (m->otype) {
  196.     case MAT_PFUNC: case MAT_MFUNC:
  197.         minsa = 2; minfa = 4; break;
  198.     case MAT_PDATA: case MAT_MDATA:
  199.         minsa = 4; minfa = 4; break;
  200.     case MAT_TFUNC:
  201.         minsa = 2; minfa = 6; break;
  202.     case MAT_TDATA:
  203.         minsa = 4; minfa = 6; break;
  204.     case MAT_BRTDF:
  205.         minsa = 10; minfa = 6; break;
  206.     }
  207.     if (m->oargs.nsargs < minsa || m->oargs.nfargs < minfa)
  208.         objerror(m, USER, "bad # arguments");
  209.     nd.mp = m;
  210.     nd.pr = r;
  211.                         /* get specular component */
  212.     nd.rspec = m->oargs.farg[3];
  213.                         /* compute transmission */
  214.     if (m->otype == MAT_TFUNC || m->otype == MAT_TDATA
  215.             || m->otype == MAT_BRTDF) {
  216.         nd.trans = m->oargs.farg[4]*(1.0 - nd.rspec);
  217.         nd.tspec = nd.trans * m->oargs.farg[5];
  218.         nd.tdiff = nd.trans - nd.tspec;
  219.     } else
  220.         nd.tdiff = nd.tspec = nd.trans = 0.0;
  221.                         /* early shadow check */
  222.     if (r->crtype & SHADOW && (m->otype != MAT_BRTDF || nd.tspec <= FTINY))
  223.         return;
  224.                         /* diffuse reflection */
  225.     nd.rdiff = 1.0 - nd.trans - nd.rspec;
  226.                         /* get material color */
  227.     setcolor(nd.mcolor, m->oargs.farg[0],
  228.                m->oargs.farg[1],
  229.                m->oargs.farg[2]);
  230.                         /* fix orientation */
  231.     if (r->rod < 0.0)
  232.         flipsurface(r);
  233.                         /* get modifiers */
  234.     raytexture(r, m->omod);
  235.     nd.pdot = raynormal(nd.pnorm, r);    /* perturb normal */
  236.     multcolor(nd.mcolor, r->pcol);        /* modify material color */
  237.     transtest = 0;
  238.                         /* load auxiliary files */
  239.     if (hasdata(m->otype)) {
  240.         nd.dp = getdata(m->oargs.sarg[1]);
  241.         i = (1 << nd.dp->nd) - 1;
  242.         mf = getfunc(m, 2, i<<3, 0);
  243.     } else if (m->otype == MAT_BRTDF) {
  244.         nd.dp = NULL;
  245.         mf = getfunc(m, 9, 0x3f, 0);
  246.     } else {
  247.         nd.dp = NULL;
  248.         mf = getfunc(m, 1, 0, 0);
  249.     }
  250.                         /* set special variables */
  251.     setbrdfunc(&nd);
  252.                         /* compute transmitted ray */
  253.     tspect = 0.;
  254.     if (m->otype == MAT_BRTDF && nd.tspec > FTINY) {
  255.         RAY  sr;
  256.         errno = 0;
  257.         setcolor(ctmp, evalue(mf->ep[3]),
  258.                 evalue(mf->ep[4]),
  259.                 evalue(mf->ep[5]));
  260.         scalecolor(ctmp, nd.trans);
  261.         if (errno)
  262.             objerror(m, WARNING, "compute error");
  263.         else if ((tspect = bright(ctmp)) > FTINY &&
  264.                 rayorigin(&sr, r, TRANS, tspect) == 0) {
  265.             if (!(r->crtype & SHADOW) &&
  266.                     DOT(r->pert,r->pert) > FTINY*FTINY) {
  267.                 for (i = 0; i < 3; i++)    /* perturb direction */
  268.                     sr.rdir[i] = r->rdir[i] -
  269.                             .75*r->pert[i];
  270.                 normalize(sr.rdir);
  271.             } else {
  272.                 VCOPY(sr.rdir, r->rdir);
  273.                 transtest = 2;
  274.             }
  275.             rayvalue(&sr);
  276.             multcolor(sr.rcol, ctmp);
  277.             addcolor(r->rcol, sr.rcol);
  278.             transtest *= bright(sr.rcol);
  279.             transdist = r->rot + sr.rt;
  280.         }
  281.     }
  282.     if (r->crtype & SHADOW)            /* the rest is shadow */
  283.         return;
  284.                         /* compute reflected ray */
  285.     rspecr = 0.;
  286.     if (m->otype == MAT_BRTDF && nd.rspec > FTINY) {
  287.         RAY  sr;
  288.         errno = 0;
  289.         setcolor(ctmp, evalue(mf->ep[0]),
  290.                 evalue(mf->ep[1]),
  291.                 evalue(mf->ep[2]));
  292.         if (errno)
  293.             objerror(m, WARNING, "compute error");
  294.         else if ((rspecr = bright(ctmp)) > FTINY &&
  295.                 rayorigin(&sr, r, REFLECTED, rspecr) == 0) {
  296.             for (i = 0; i < 3; i++)
  297.                 sr.rdir[i] = r->rdir[i] +
  298.                         2.0*nd.pdot*nd.pnorm[i];
  299.             rayvalue(&sr);
  300.             multcolor(sr.rcol, ctmp);
  301.             addcolor(r->rcol, sr.rcol);
  302.         }
  303.     }
  304.                         /* compute ambient */
  305.     if ((dtmp = 1.0-nd.trans-rspecr) > FTINY) {
  306.         ambient(ctmp, r);
  307.         scalecolor(ctmp, dtmp);
  308.         multcolor(ctmp, nd.mcolor);    /* modified by material color */
  309.         addcolor(r->rcol, ctmp);    /* add to returned color */
  310.     }
  311.     if ((dtmp = nd.trans-tspect) > FTINY) {    /* from other side */
  312.         flipsurface(r);
  313.         ambient(ctmp, r);
  314.         scalecolor(ctmp, dtmp);
  315.         multcolor(ctmp, nd.mcolor);
  316.         addcolor(r->rcol, ctmp);
  317.         flipsurface(r);
  318.     }
  319.                         /* add direct component */
  320.     direct(r, dirbrdf, &nd);
  321.                         /* check distance */
  322.     if (transtest > bright(r->rcol))
  323.         r->rt = transdist;
  324. }
  325.  
  326.  
  327. setbrdfunc(np)            /* set up brdf function and variables */
  328. register BRDFDAT  *np;
  329. {
  330.     FVECT  vec;
  331.  
  332.     if (setfunc(np->mp, np->pr) == 0)
  333.         return(0);    /* it's OK, setfunc says we're done */
  334.                 /* else (re)assign special variables */
  335.     multv3(vec, np->pnorm, funcxf.xfm);
  336.     varset("NxP", '=', vec[0]/funcxf.sca);
  337.     varset("NyP", '=', vec[1]/funcxf.sca);
  338.     varset("NzP", '=', vec[2]/funcxf.sca);
  339.     varset("RdotP", '=', np->pdot <= -1.0 ? -1.0 :
  340.             np->pdot >= 1.0 ? 1.0 : np->pdot);
  341.     varset("CrP", '=', colval(np->mcolor,RED));
  342.     varset("CgP", '=', colval(np->mcolor,GRN));
  343.     varset("CbP", '=', colval(np->mcolor,BLU));
  344.     return(1);
  345. }
  346.