--- ray/src/rt/dielectric.c 1995/12/05 11:46:00 2.8 +++ ray/src/rt/dielectric.c 2005/04/19 01:15:06 2.20 @@ -1,25 +1,25 @@ -/* Copyright (c) 1986 Regents of the University of California */ - #ifndef lint -static char SCCSid[] = "$SunId$ LBL"; +static const char RCSid[] = "$Id: dielectric.c,v 2.20 2005/04/19 01:15:06 greg Exp $"; #endif - /* * dielectric.c - shading function for transparent materials. - * - * 9/6/85 */ -#include "ray.h" +#include "copyright.h" +#include "ray.h" #include "otypes.h" +#include "rtotypes.h" #ifdef DISPERSE #include "source.h" -static disperse(); -static int lambda(); +static int disperse(OBJREC *m,RAY *r,FVECT vt,double tr,COLOR cet,COLOR abt); +static int lambda(OBJREC *m, FVECT v2, FVECT dv, FVECT lr); #endif +static double mylog(double x); + + /* * Explicit calculations for Fresnel's equation are performed, * but only one square root computation is necessary. @@ -51,13 +51,32 @@ static int lambda(); #define MINCOS 0.997 /* minimum dot product for dispersion */ -m_dielectric(m, r) /* color a ray which hit something transparent */ -OBJREC *m; -register RAY *r; +static double +mylog( /* special log for extinction coefficients */ + double x +) { + if (x < 1e-40) + return(-100.); + if (x >= 1.) + return(0.); + return(log(x)); +} + + +extern int +m_dielectric( /* color a ray which hit a dielectric interface */ + OBJREC *m, + register RAY *r +) +{ double cos1, cos2, nratio; - COLOR mcolor; - double mabsorp; + COLOR ctrans; + COLOR talb; + int hastexture; + double transdist, transtest=0; + double mirdist, mirtest=0; + int flatsurface; double refl, trans; FVECT dnorm; double d1, d2; @@ -69,7 +88,14 @@ register RAY *r; raytexture(r, m->omod); /* get modifiers */ - cos1 = raynormal(dnorm, r); /* cosine of theta1 */ + if ( (hastexture = DOT(r->pert,r->pert) > FTINY*FTINY) ) + cos1 = raynormal(dnorm, r); /* perturb normal */ + else { + VCOPY(dnorm, r->ron); + cos1 = r->rod; + } + flatsurface = !hastexture && r->ro != NULL && isflat(r->ro->otype); + /* index of refraction */ if (m->otype == MAT_DIELECTRIC) nratio = m->oargs.farg[3] + m->oargs.farg[4]/MLAMBDA; @@ -77,24 +103,42 @@ register RAY *r; nratio = m->oargs.farg[3] / m->oargs.farg[7]; if (cos1 < 0.0) { /* inside */ + hastexture = -hastexture; cos1 = -cos1; dnorm[0] = -dnorm[0]; dnorm[1] = -dnorm[1]; dnorm[2] = -dnorm[2]; - setcolor(mcolor, pow(m->oargs.farg[0], r->rot), - pow(m->oargs.farg[1], r->rot), - pow(m->oargs.farg[2], r->rot)); - multcolor(mcolor, r->pcol); /* modify */ + setcolor(r->cext, -mylog(m->oargs.farg[0]*colval(r->pcol,RED)), + -mylog(m->oargs.farg[1]*colval(r->pcol,GRN)), + -mylog(m->oargs.farg[2]*colval(r->pcol,BLU))); + setcolor(r->albedo, 0., 0., 0.); + r->gecc = 0.; + if (m->otype == MAT_INTERFACE) { + setcolor(ctrans, + -mylog(m->oargs.farg[4]*colval(r->pcol,RED)), + -mylog(m->oargs.farg[5]*colval(r->pcol,GRN)), + -mylog(m->oargs.farg[6]*colval(r->pcol,BLU))); + setcolor(talb, 0., 0., 0.); + } else { + copycolor(ctrans, cextinction); + copycolor(talb, salbedo); + } } else { /* outside */ nratio = 1.0 / nratio; - if (m->otype == MAT_INTERFACE) - setcolor(mcolor, pow(m->oargs.farg[4], r->rot), - pow(m->oargs.farg[5], r->rot), - pow(m->oargs.farg[6], r->rot)); - else - setcolor(mcolor, 1.0, 1.0, 1.0); + + setcolor(ctrans, -mylog(m->oargs.farg[0]*colval(r->pcol,RED)), + -mylog(m->oargs.farg[1]*colval(r->pcol,GRN)), + -mylog(m->oargs.farg[2]*colval(r->pcol,BLU))); + setcolor(talb, 0., 0., 0.); + if (m->otype == MAT_INTERFACE) { + setcolor(r->cext, + -mylog(m->oargs.farg[4]*colval(r->pcol,RED)), + -mylog(m->oargs.farg[5]*colval(r->pcol,GRN)), + -mylog(m->oargs.farg[6]*colval(r->pcol,BLU))); + setcolor(r->albedo, 0., 0., 0.); + r->gecc = 0.; + } } - mabsorp = bright(mcolor); d2 = 1.0 - nratio*nratio*(1.0 - cos1*cos1); /* compute cos theta2 */ @@ -115,63 +159,101 @@ register RAY *r; d1 = (d1 - d2) / (d1 + d2); refl += d1 * d1; - refl /= 2.0; + refl *= 0.5; trans = 1.0 - refl; - if (rayorigin(&p, r, REFRACTED, mabsorp*trans) == 0) { + trans *= nratio*nratio; /* solid angle ratio */ + setcolor(p.rcoef, trans, trans, trans); + + if (rayorigin(&p, REFRACTED, r, p.rcoef) == 0) { + /* compute refracted ray */ d1 = nratio*cos1 - cos2; for (i = 0; i < 3; i++) p.rdir[i] = nratio*r->rdir[i] + d1*dnorm[i]; - + /* accidental reflection? */ + if (hastexture && + DOT(p.rdir,r->ron)*hastexture >= -FTINY) { + d1 *= (double)hastexture; + for (i = 0; i < 3; i++) /* ignore texture */ + p.rdir[i] = nratio*r->rdir[i] + + d1*r->ron[i]; + normalize(p.rdir); /* not exact */ + } #ifdef DISPERSE if (m->otype != MAT_DIELECTRIC || r->rod > 0.0 || r->crtype & SHADOW || !directvis || m->oargs.farg[4] == 0.0 - || !disperse(m, r, p.rdir, trans)) + || !disperse(m, r, p.rdir, + trans, ctrans, talb)) #endif { + copycolor(p.cext, ctrans); + copycolor(p.albedo, talb); rayvalue(&p); - scalecolor(p.rcol, trans); + multcolor(p.rcol, p.rcoef); addcolor(r->rcol, p.rcol); - if (nratio >= 1.0-FTINY && nratio <= 1.0+FTINY) - r->rt = r->rot + p.rt; + /* virtual distance */ + if (flatsurface || + (1.-FTINY <= nratio && + nratio <= 1.+FTINY)) { + transtest = 2*bright(p.rcol); + transdist = r->rot + p.rt; + } } } } - + setcolor(p.rcoef, refl, refl, refl); + if (!(r->crtype & SHADOW) && - rayorigin(&p, r, REFLECTED, mabsorp*refl) == 0) { + rayorigin(&p, REFLECTED, r, p.rcoef) == 0) { /* compute reflected ray */ for (i = 0; i < 3; i++) p.rdir[i] = r->rdir[i] + 2.0*cos1*dnorm[i]; + /* accidental penetration? */ + if (hastexture && DOT(p.rdir,r->ron)*hastexture <= FTINY) + for (i = 0; i < 3; i++) /* ignore texture */ + p.rdir[i] = r->rdir[i] + 2.0*r->rod*r->ron[i]; rayvalue(&p); /* reflected ray value */ - scalecolor(p.rcol, refl); /* color contribution */ + multcolor(p.rcol, p.rcoef); /* color contribution */ addcolor(r->rcol, p.rcol); + /* virtual distance */ + if (flatsurface) { + mirtest = 2*bright(p.rcol); + mirdist = r->rot + p.rt; + } } - - multcolor(r->rcol, mcolor); /* multiply by transmittance */ - + /* check distance to return */ + d1 = bright(r->rcol); + if (transtest > d1) + r->rt = transdist; + else if (mirtest > d1) + r->rt = mirdist; + /* rayvalue() computes absorption */ return(1); } #ifdef DISPERSE -static -disperse(m, r, vt, tr) /* check light sources for dispersion */ -OBJREC *m; -RAY *r; -FVECT vt; -double tr; +static int +disperse( /* check light sources for dispersion */ + OBJREC *m, + RAY *r, + FVECT vt, + double tr, + COLOR cet, + COLOR abt +) { - RAY sray, *entray; + RAY sray; + const RAY *entray; FVECT v1, v2, n1, n2; FVECT dv, v2Xdv; double v2Xdvv2Xdv; @@ -255,6 +337,8 @@ double tr; if (l1 > MAXLAMBDA || l1 < MINLAMBDA) /* not visible */ continue; /* trace source ray */ + copycolor(sray.cext, cet); + copycolor(sray.albedo, abt); normalize(sray.rdir); rayvalue(&sray); if (bright(sray.rcol) <= FTINY) /* missed it */ @@ -298,9 +382,12 @@ double tr; static int -lambda(m, v2, dv, lr) /* compute lambda for material */ -register OBJREC *m; -FVECT v2, dv, lr; +lambda( /* compute lambda for material */ + register OBJREC *m, + FVECT v2, + FVECT dv, + FVECT lr +) { FVECT lrXdv, v2Xlr; double dtmp, denom;