--- ray/src/rt/normal.c 1998/12/16 18:14:58 2.37 +++ ray/src/rt/normal.c 2004/09/20 17:32:04 2.48 @@ -1,9 +1,6 @@ -/* Copyright (c) 1998 Silicon Graphics, Inc. */ - #ifndef lint -static char SCCSid[] = "$SunId$ SGI"; +static const char RCSid[] = "$Id: normal.c,v 2.48 2004/09/20 17:32:04 greg Exp $"; #endif - /* * normal.c - shading function for normal materials. * @@ -14,22 +11,21 @@ static char SCCSid[] = "$SunId$ SGI"; * Later changes described in delta comments. */ -#include "ray.h" +#include "copyright.h" +#include "ray.h" +#include "ambient.h" +#include "source.h" #include "otypes.h" - +#include "rtotypes.h" #include "random.h" -extern double specthresh; /* specular sampling threshold */ -extern double specjitter; /* specular sampling jitter */ - -extern int backvis; /* back faces visible? */ - #ifndef MAXITER #define MAXITER 10 /* maximum # specular ray attempts */ #endif + /* estimate of Fresnel function */ +#define FRESNE(ci) (exp(-5.85*(ci)) - 0.00287989916) -static gaussamp(); /* * This routine implements the isotropic Gaussian @@ -68,14 +64,21 @@ typedef struct { double pdot; /* perturbed dot product */ } NORMDAT; /* normal material data */ +static srcdirf_t dirnorm; +static void gaussamp(RAY *r, NORMDAT *np); -dirnorm(cval, np, ldir, omega) /* compute source contribution */ -COLOR cval; /* returned coefficient */ -register NORMDAT *np; /* material data */ -FVECT ldir; /* light source direction */ -double omega; /* light source size */ + +static void +dirnorm( /* compute source contribution */ + COLOR cval, /* returned coefficient */ + void *nnp, /* material data */ + FVECT ldir, /* light source direction */ + double omega /* light source size */ +) { + register NORMDAT *np = nnp; double ldot; + double ldiff; double dtmp, d2; FVECT vtmp; COLOR ctmp; @@ -87,14 +90,19 @@ double omega; /* light source size */ if (ldot < 0.0 ? np->trans <= FTINY : np->trans >= 1.0-FTINY) return; /* wrong side */ - if (ldot > FTINY && np->rdiff > FTINY) { + /* Fresnel estimate */ + ldiff = np->rdiff; + if (np->specfl & SP_PURE && (np->rspec > FTINY) & (ldiff > FTINY)) + ldiff *= 1. - FRESNE(fabs(ldot)); + + if (ldot > FTINY && ldiff > FTINY) { /* * Compute and add diffuse reflected component to returned * color. The diffuse reflected component will always be * modified by the color of the material. */ copycolor(ctmp, np->mcolor); - dtmp = ldot * omega * np->rdiff / PI; + dtmp = ldot * omega * ldiff * (1.0/PI); scalecolor(ctmp, dtmp); addcolor(cval, ctmp); } @@ -107,7 +115,7 @@ double omega; /* light source size */ dtmp = np->alpha2; /* + source if flat */ if (np->specfl & SP_FLAT) - dtmp += omega/(4.0*PI); + dtmp += omega * (0.25/PI); /* half vector */ vtmp[0] = ldir[0] - np->rp->rdir[0]; vtmp[1] = ldir[1] - np->rp->rdir[1]; @@ -116,11 +124,11 @@ double omega; /* light source size */ d2 *= d2; d2 = (DOT(vtmp,vtmp) - d2) / d2; /* gaussian */ - dtmp = exp(-d2/dtmp)/(4.*PI*dtmp); + dtmp = exp(-d2/dtmp)/(4.*PI * np->pdot * dtmp); /* worth using? */ if (dtmp > FTINY) { copycolor(ctmp, np->scolor); - dtmp *= omega * sqrt(ldot/np->pdot); + dtmp *= omega; scalecolor(ctmp, dtmp); addcolor(cval, ctmp); } @@ -130,7 +138,7 @@ double omega; /* light source size */ * Compute diffuse transmission. */ copycolor(ctmp, np->mcolor); - dtmp = -ldot * omega * np->tdiff / PI; + dtmp = -ldot * omega * np->tdiff * (1.0/PI); scalecolor(ctmp, dtmp); addcolor(cval, ctmp); } @@ -140,13 +148,14 @@ double omega; /* light source size */ * is always modified by material color. */ /* roughness + source */ - dtmp = np->alpha2 + omega/PI; + dtmp = np->alpha2 + omega*(1.0/PI); /* gaussian */ - dtmp = exp((2.*DOT(np->prdir,ldir)-2.)/dtmp)/(PI*dtmp); + dtmp = exp((2.*DOT(np->prdir,ldir)-2.)/dtmp) / + (PI*np->pdot*dtmp); /* worth using? */ if (dtmp > FTINY) { copycolor(ctmp, np->mcolor); - dtmp *= np->tspec * omega * sqrt(-ldot/np->pdot); + dtmp *= np->tspec * omega; scalecolor(ctmp, dtmp); addcolor(cval, ctmp); } @@ -154,11 +163,14 @@ double omega; /* light source size */ } -m_normal(m, r) /* color a ray that hit something normal */ -register OBJREC *m; -register RAY *r; +extern int +m_normal( /* color a ray that hit something normal */ + register OBJREC *m, + register RAY *r +) { NORMDAT nd; + double fest; double transtest, transdist; double mirtest, mirdist; int hastexture; @@ -177,8 +189,10 @@ register RAY *r; raytrans(r); return(1); } + raytexture(r, m->omod); flipsurface(r); /* reorient if backvis */ - } + } else + raytexture(r, m->omod); nd.mp = m; nd.rp = r; /* get material color */ @@ -190,22 +204,27 @@ register RAY *r; nd.alpha2 = m->oargs.farg[4]; if ((nd.alpha2 *= nd.alpha2) <= FTINY) nd.specfl |= SP_PURE; - if (r->ro != NULL && isflat(r->ro->otype)) - nd.specfl |= SP_FLAT; - /* get modifiers */ - raytexture(r, m->omod); - if (hastexture = DOT(r->pert,r->pert) > FTINY*FTINY) + + if ( (hastexture = (DOT(r->pert,r->pert) > FTINY*FTINY)) ) { nd.pdot = raynormal(nd.pnorm, r); /* perturb normal */ - else { + } else { VCOPY(nd.pnorm, r->ron); nd.pdot = r->rod; } + if (r->ro != NULL && isflat(r->ro->otype)) + nd.specfl |= SP_FLAT; if (nd.pdot < .001) nd.pdot = .001; /* non-zero for dirnorm() */ multcolor(nd.mcolor, r->pcol); /* modify material color */ mirtest = transtest = 0; mirdist = transdist = r->rot; nd.rspec = m->oargs.farg[3]; + /* compute Fresnel approx. */ + if (nd.specfl & SP_PURE && nd.rspec > FTINY) { + fest = FRESNE(r->rod); + nd.rspec += fest*(1. - nd.rspec); + } else + fest = 0.; /* compute transmission */ if (m->otype == MAT_TRANS) { nd.trans = m->oargs.farg[5]*(1.0 - nd.rspec); @@ -254,11 +273,16 @@ register RAY *r; if (nd.rspec > FTINY) { nd.specfl |= SP_REFL; /* compute specular color */ - if (m->otype == MAT_METAL) + if (m->otype != MAT_METAL) { + setcolor(nd.scolor, nd.rspec, nd.rspec, nd.rspec); + } else if (fest > FTINY) { + d = nd.rspec*(1. - fest); + for (i = 0; i < 3; i++) + nd.scolor[i] = fest + nd.mcolor[i]*d; + } else { copycolor(nd.scolor, nd.mcolor); - else - setcolor(nd.scolor, 1.0, 1.0, 1.0); - scalecolor(nd.scolor, nd.rspec); + scalecolor(nd.scolor, nd.rspec); + } /* check threshold */ if (!(nd.specfl & SP_PURE) && specthresh >= nd.rspec-FTINY) nd.specfl |= SP_RBLT; @@ -333,10 +357,11 @@ register RAY *r; } -static -gaussamp(r, np) /* sample gaussian specular */ -RAY *r; -register NORMDAT *np; +static void +gaussamp( /* sample gaussian specular */ + RAY *r, + register NORMDAT *np +) { RAY sr; FVECT u, v, h;