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

  1. /* Copyright (c) 1992 Regents of the University of California */
  2.  
  3. #ifndef lint
  4. static char SCCSid[] = "@(#)normal.c 2.22 10/16/92 LBL";
  5. #endif
  6.  
  7. /*
  8.  *  normal.c - shading function for normal materials.
  9.  *
  10.  *     8/19/85
  11.  *     12/19/85 - added stuff for metals.
  12.  *     6/26/87 - improved specular model.
  13.  *     9/28/87 - added model for translucent materials.
  14.  *     Later changes described in delta comments.
  15.  */
  16.  
  17. #include  "ray.h"
  18.  
  19. #include  "otypes.h"
  20.  
  21. #include  "random.h"
  22.  
  23. extern double  specthresh;        /* specular sampling threshold */
  24. extern double  specjitter;        /* specular sampling jitter */
  25.  
  26. /*
  27.  *    This routine implements the isotropic Gaussian
  28.  *  model described by Ward in Siggraph `92 article.
  29.  *    We orient the surface towards the incoming ray, so a single
  30.  *  surface can be used to represent an infinitely thin object.
  31.  *
  32.  *  Arguments for MAT_PLASTIC and MAT_METAL are:
  33.  *    red    grn    blu    specular-frac.    facet-slope
  34.  *
  35.  *  Arguments for MAT_TRANS are:
  36.  *    red     grn    blu    rspec    rough    trans    tspec
  37.  */
  38.  
  39. #define  BSPEC(m)    (6.0)        /* specularity parameter b */
  40.  
  41.                 /* specularity flags */
  42. #define  SP_REFL    01        /* has reflected specular component */
  43. #define  SP_TRAN    02        /* has transmitted specular */
  44. #define  SP_PURE    04        /* purely specular (zero roughness) */
  45. #define  SP_FLAT    010        /* flat reflecting surface */
  46. #define  SP_RBLT    020        /* reflection below sample threshold */
  47. #define  SP_TBLT    040        /* transmission below threshold */
  48.  
  49. typedef struct {
  50.     OBJREC  *mp;        /* material pointer */
  51.     RAY  *rp;        /* ray pointer */
  52.     short  specfl;        /* specularity flags, defined above */
  53.     COLOR  mcolor;        /* color of this material */
  54.     COLOR  scolor;        /* color of specular component */
  55.     FVECT  vrefl;        /* vector in direction of reflected ray */
  56.     FVECT  prdir;        /* vector in transmitted direction */
  57.     double  alpha2;        /* roughness squared */
  58.     double  rdiff, rspec;    /* reflected specular, diffuse */
  59.     double  trans;        /* transmissivity */
  60.     double  tdiff, tspec;    /* transmitted specular, diffuse */
  61.     FVECT  pnorm;        /* perturbed surface normal */
  62.     double  pdot;        /* perturbed dot product */
  63. }  NORMDAT;        /* normal material data */
  64.  
  65.  
  66. dirnorm(cval, np, ldir, omega)        /* compute source contribution */
  67. COLOR  cval;            /* returned coefficient */
  68. register NORMDAT  *np;        /* material data */
  69. FVECT  ldir;            /* light source direction */
  70. double  omega;            /* light source size */
  71. {
  72.     double  ldot;
  73.     double  dtmp, d2;
  74.     FVECT  vtmp;
  75.     COLOR  ctmp;
  76.  
  77.     setcolor(cval, 0.0, 0.0, 0.0);
  78.  
  79.     ldot = DOT(np->pnorm, ldir);
  80.  
  81.     if (ldot < 0.0 ? np->trans <= FTINY : np->trans >= 1.0-FTINY)
  82.         return;        /* wrong side */
  83.  
  84.     if (ldot > FTINY && np->rdiff > FTINY) {
  85.         /*
  86.          *  Compute and add diffuse reflected component to returned
  87.          *  color.  The diffuse reflected component will always be
  88.          *  modified by the color of the material.
  89.          */
  90.         copycolor(ctmp, np->mcolor);
  91.         dtmp = ldot * omega * np->rdiff / PI;
  92.         scalecolor(ctmp, dtmp);
  93.         addcolor(cval, ctmp);
  94.     }
  95.     if (ldot > FTINY && (np->specfl&(SP_REFL|SP_PURE)) == SP_REFL) {
  96.         /*
  97.          *  Compute specular reflection coefficient using
  98.          *  gaussian distribution model.
  99.          */
  100.                         /* roughness */
  101.         dtmp = np->alpha2;
  102.                         /* + source if flat */
  103.         if (np->specfl & SP_FLAT)
  104.             dtmp += omega/(4.0*PI);
  105.                         /* delta */
  106.         vtmp[0] = ldir[0] - np->rp->rdir[0];
  107.         vtmp[1] = ldir[1] - np->rp->rdir[1];
  108.         vtmp[2] = ldir[2] - np->rp->rdir[2];
  109.         d2 = DOT(vtmp, np->pnorm);
  110.         d2 = 2.0 - 2.0*d2/sqrt(DOT(vtmp,vtmp));
  111.                         /* gaussian */
  112.         dtmp = exp(-d2/dtmp)/(4.*PI*dtmp);
  113.                         /* worth using? */
  114.         if (dtmp > FTINY) {
  115.             copycolor(ctmp, np->scolor);
  116.             dtmp *= omega * sqrt(ldot/np->pdot);
  117.             scalecolor(ctmp, dtmp);
  118.             addcolor(cval, ctmp);
  119.         }
  120.     }
  121.     if (ldot < -FTINY && np->tdiff > FTINY) {
  122.         /*
  123.          *  Compute diffuse transmission.
  124.          */
  125.         copycolor(ctmp, np->mcolor);
  126.         dtmp = -ldot * omega * np->tdiff / PI;
  127.         scalecolor(ctmp, dtmp);
  128.         addcolor(cval, ctmp);
  129.     }
  130.     if (ldot < -FTINY && (np->specfl&(SP_TRAN|SP_PURE)) == SP_TRAN) {
  131.         /*
  132.          *  Compute specular transmission.  Specular transmission
  133.          *  is always modified by material color.
  134.          */
  135.                         /* roughness + source */
  136.         dtmp = np->alpha2 + omega/PI;
  137.                         /* gaussian */
  138.         dtmp = exp((2.*DOT(np->prdir,ldir)-2.)/dtmp)/(PI*dtmp);
  139.                         /* worth using? */
  140.         if (dtmp > FTINY) {
  141.             copycolor(ctmp, np->mcolor);
  142.             dtmp *= np->tspec * omega * sqrt(-ldot/np->pdot);
  143.             scalecolor(ctmp, dtmp);
  144.             addcolor(cval, ctmp);
  145.         }
  146.     }
  147. }
  148.  
  149.  
  150. m_normal(m, r)            /* color a ray that hit something normal */
  151. register OBJREC  *m;
  152. register RAY  *r;
  153. {
  154.     NORMDAT  nd;
  155.     double  transtest, transdist;
  156.     double  dtmp;
  157.     COLOR  ctmp;
  158.     register int  i;
  159.                         /* easy shadow test */
  160.     if (r->crtype & SHADOW && m->otype != MAT_TRANS)
  161.         return;
  162.  
  163.     if (m->oargs.nfargs != (m->otype == MAT_TRANS ? 7 : 5))
  164.         objerror(m, USER, "bad number of arguments");
  165.     nd.mp = m;
  166.     nd.rp = r;
  167.                         /* get material color */
  168.     setcolor(nd.mcolor, m->oargs.farg[0],
  169.                m->oargs.farg[1],
  170.                m->oargs.farg[2]);
  171.                         /* get roughness */
  172.     nd.specfl = 0;
  173.     nd.alpha2 = m->oargs.farg[4];
  174.     if ((nd.alpha2 *= nd.alpha2) <= FTINY)
  175.         nd.specfl |= SP_PURE;
  176.                         /* reorient if necessary */
  177.     if (r->rod < 0.0)
  178.         flipsurface(r);
  179.                         /* get modifiers */
  180.     raytexture(r, m->omod);
  181.     nd.pdot = raynormal(nd.pnorm, r);    /* perturb normal */
  182.     if (nd.pdot < .001)
  183.         nd.pdot = .001;            /* non-zero for dirnorm() */
  184.     multcolor(nd.mcolor, r->pcol);        /* modify material color */
  185.     transtest = 0;
  186.                         /* get specular component */
  187.     if ((nd.rspec = m->oargs.farg[3]) > FTINY) {
  188.         nd.specfl |= SP_REFL;
  189.                         /* compute specular color */
  190.         if (m->otype == MAT_METAL)
  191.             copycolor(nd.scolor, nd.mcolor);
  192.         else
  193.             setcolor(nd.scolor, 1.0, 1.0, 1.0);
  194.         scalecolor(nd.scolor, nd.rspec);
  195.                         /* improved model */
  196.         dtmp = exp(-BSPEC(m)*nd.pdot);
  197.         for (i = 0; i < 3; i++)
  198.             colval(nd.scolor,i) += (1.0-colval(nd.scolor,i))*dtmp;
  199.         nd.rspec += (1.0-nd.rspec)*dtmp;
  200.                         /* check threshold */
  201.         if (!(nd.specfl & SP_PURE) &&
  202.                 specthresh > FTINY &&
  203.                 (specthresh >= 1.-FTINY ||
  204.                 specthresh + .05 - .1*frandom() > nd.rspec))
  205.             nd.specfl |= SP_RBLT;
  206.                         /* compute reflected ray */
  207.         for (i = 0; i < 3; i++)
  208.             nd.vrefl[i] = r->rdir[i] + 2.0*nd.pdot*nd.pnorm[i];
  209.         if (DOT(nd.vrefl, r->ron) <= FTINY)    /* penetration? */
  210.             for (i = 0; i < 3; i++)        /* safety measure */
  211.                 nd.vrefl[i] = r->rdir[i] + 2.*r->rod*r->ron[i];
  212.  
  213.         if (!(r->crtype & SHADOW) && nd.specfl & SP_PURE) {
  214.             RAY  lr;
  215.             if (rayorigin(&lr, r, REFLECTED, nd.rspec) == 0) {
  216.                 VCOPY(lr.rdir, nd.vrefl);
  217.                 rayvalue(&lr);
  218.                 multcolor(lr.rcol, nd.scolor);
  219.                 addcolor(r->rcol, lr.rcol);
  220.             }
  221.         }
  222.     }
  223.                         /* compute transmission */
  224.     if (m->otype == MAT_TRANS) {
  225.         nd.trans = m->oargs.farg[5]*(1.0 - nd.rspec);
  226.         nd.tspec = nd.trans * m->oargs.farg[6];
  227.         nd.tdiff = nd.trans - nd.tspec;
  228.         if (nd.tspec > FTINY) {
  229.             nd.specfl |= SP_TRAN;
  230.                             /* check threshold */
  231.             if (!(nd.specfl & SP_PURE) && specthresh > FTINY &&
  232.                     (specthresh >= 1.-FTINY ||
  233.                 specthresh + .05 - .1*frandom() > nd.tspec))
  234.                 nd.specfl |= SP_TBLT;
  235.             if (r->crtype & SHADOW ||
  236.                     DOT(r->pert,r->pert) <= FTINY*FTINY) {
  237.                 VCOPY(nd.prdir, r->rdir);
  238.                 transtest = 2;
  239.             } else {
  240.                 for (i = 0; i < 3; i++)        /* perturb */
  241.                     nd.prdir[i] = r->rdir[i] - r->pert[i];
  242.                 if (DOT(nd.prdir, r->ron) < -FTINY)
  243.                     normalize(nd.prdir);    /* OK */
  244.                 else
  245.                     VCOPY(nd.prdir, r->rdir);
  246.             }
  247.         }
  248.     } else
  249.         nd.tdiff = nd.tspec = nd.trans = 0.0;
  250.                         /* transmitted ray */
  251.     if ((nd.specfl&(SP_TRAN|SP_PURE)) == (SP_TRAN|SP_PURE)) {
  252.         RAY  lr;
  253.         if (rayorigin(&lr, r, TRANS, nd.tspec) == 0) {
  254.             VCOPY(lr.rdir, nd.prdir);
  255.             rayvalue(&lr);
  256.             scalecolor(lr.rcol, nd.tspec);
  257.             multcolor(lr.rcol, nd.mcolor);    /* modified by color */
  258.             addcolor(r->rcol, lr.rcol);
  259.             transtest *= bright(lr.rcol);
  260.             transdist = r->rot + lr.rt;
  261.         }
  262.     } else
  263.         transtest = 0;
  264.  
  265.     if (r->crtype & SHADOW)            /* the rest is shadow */
  266.         return;
  267.                         /* diffuse reflection */
  268.     nd.rdiff = 1.0 - nd.trans - nd.rspec;
  269.  
  270.     if (nd.specfl & SP_PURE && nd.rdiff <= FTINY && nd.tdiff <= FTINY)
  271.         return;                /* 100% pure specular */
  272.  
  273.     if (r->ro != NULL && (r->ro->otype == OBJ_FACE ||
  274.             r->ro->otype == OBJ_RING))
  275.         nd.specfl |= SP_FLAT;
  276.  
  277.     if (nd.specfl & (SP_REFL|SP_TRAN) && !(nd.specfl & SP_PURE))
  278.         gaussamp(r, &nd);
  279.  
  280.     if (nd.rdiff > FTINY) {        /* ambient from this side */
  281.         ambient(ctmp, r);
  282.         if (nd.specfl & SP_RBLT)
  283.             scalecolor(ctmp, 1.0-nd.trans);
  284.         else
  285.             scalecolor(ctmp, nd.rdiff);
  286.         multcolor(ctmp, nd.mcolor);    /* modified by material color */
  287.         addcolor(r->rcol, ctmp);    /* add to returned color */
  288.     }
  289.     if (nd.tdiff > FTINY) {        /* ambient from other side */
  290.         flipsurface(r);
  291.         ambient(ctmp, r);
  292.         if (nd.specfl & SP_TBLT)
  293.             scalecolor(ctmp, nd.trans);
  294.         else
  295.             scalecolor(ctmp, nd.tdiff);
  296.         multcolor(ctmp, nd.mcolor);    /* modified by color */
  297.         addcolor(r->rcol, ctmp);
  298.         flipsurface(r);
  299.     }
  300.                     /* add direct component */
  301.     direct(r, dirnorm, &nd);
  302.                     /* check distance */
  303.     if (transtest > bright(r->rcol))
  304.         r->rt = transdist;
  305. }
  306.  
  307.  
  308. static
  309. gaussamp(r, np)            /* sample gaussian specular */
  310. RAY  *r;
  311. register NORMDAT  *np;
  312. {
  313.     RAY  sr;
  314.     FVECT  u, v, h;
  315.     double  rv[2];
  316.     double  d, sinp, cosp;
  317.     register int  i;
  318.                     /* quick test */
  319.     if ((np->specfl & (SP_REFL|SP_RBLT)) != SP_REFL &&
  320.             (np->specfl & (SP_TRAN|SP_TBLT)) != SP_TRAN)
  321.         return;
  322.                     /* set up sample coordinates */
  323.     v[0] = v[1] = v[2] = 0.0;
  324.     for (i = 0; i < 3; i++)
  325.         if (np->pnorm[i] < 0.6 && np->pnorm[i] > -0.6)
  326.             break;
  327.     v[i] = 1.0;
  328.     fcross(u, v, np->pnorm);
  329.     normalize(u);
  330.     fcross(v, np->pnorm, u);
  331.                     /* compute reflection */
  332.     if ((np->specfl & (SP_REFL|SP_RBLT)) == SP_REFL &&
  333.             rayorigin(&sr, r, SPECULAR, np->rspec) == 0) {
  334.         dimlist[ndims++] = (int)np->mp;
  335.         d = urand(ilhash(dimlist,ndims)+samplendx);
  336.         multisamp(rv, 2, d);
  337.         d = 2.0*PI * rv[0];
  338.         cosp = cos(d);
  339.         sinp = sin(d);
  340.         rv[1] = 1.0 - specjitter*rv[1];
  341.         if (rv[1] <= FTINY)
  342.             d = 1.0;
  343.         else
  344.             d = sqrt( np->alpha2 * -log(rv[1]) );
  345.         for (i = 0; i < 3; i++)
  346.             h[i] = np->pnorm[i] + d*(cosp*u[i] + sinp*v[i]);
  347.         d = -2.0 * DOT(h, r->rdir) / (1.0 + d*d);
  348.         for (i = 0; i < 3; i++)
  349.             sr.rdir[i] = r->rdir[i] + d*h[i];
  350.         if (DOT(sr.rdir, r->ron) <= FTINY)
  351.             VCOPY(sr.rdir, np->vrefl);    /* jitter no good */
  352.         rayvalue(&sr);
  353.         multcolor(sr.rcol, np->scolor);
  354.         addcolor(r->rcol, sr.rcol);
  355.         ndims--;
  356.     }
  357.                     /* compute transmission */
  358.     if ((np->specfl & (SP_TRAN|SP_TBLT)) == SP_TRAN &&
  359.             rayorigin(&sr, r, SPECULAR, np->tspec) == 0) {
  360.         dimlist[ndims++] = (int)np->mp;
  361.         d = urand(ilhash(dimlist,ndims)+1823+samplendx);
  362.         multisamp(rv, 2, d);
  363.         d = 2.0*PI * rv[0];
  364.         cosp = cos(d);
  365.         sinp = sin(d);
  366.         rv[1] = 1.0 - specjitter*rv[1];
  367.         if (rv[1] <= FTINY)
  368.             d = 1.0;
  369.         else
  370.             d = sqrt( -log(rv[1]) * np->alpha2 );
  371.         for (i = 0; i < 3; i++)
  372.             sr.rdir[i] = np->prdir[i] + d*(cosp*u[i] + sinp*v[i]);
  373.         if (DOT(sr.rdir, r->ron) < -FTINY)
  374.             normalize(sr.rdir);        /* OK, normalize */
  375.         else
  376.             VCOPY(sr.rdir, np->prdir);    /* else no jitter */
  377.         rayvalue(&sr);
  378.         scalecolor(sr.rcol, np->tspec);
  379.         multcolor(sr.rcol, np->mcolor);        /* modified by color */
  380.         addcolor(r->rcol, sr.rcol);
  381.         ndims--;
  382.     }
  383. }
  384.