--- ray/src/rt/aniso.c 1992/03/03 16:20:00 2.11 +++ ray/src/rt/aniso.c 1992/10/16 10:20:27 2.22 @@ -20,8 +20,8 @@ extern double specthresh; /* specular sampling thres extern double specjitter; /* specular sampling jitter */ /* - * This anisotropic reflection model uses a variant on the - * exponential Gaussian used in normal.c. + * This routine implements the anisotropic Gaussian + * model described by Ward in Siggraph `92 article. * We orient the surface towards the incoming ray, so a single * surface can be used to represent an infinitely thin object. * @@ -70,7 +70,7 @@ FVECT ldir; /* light source direction */ double omega; /* light source size */ { double ldot; - double dtmp, dtmp2; + double dtmp, dtmp1, dtmp2; FVECT h; double au2, av2; COLOR ctmp; @@ -103,25 +103,26 @@ double omega; /* light source size */ au2 = av2 = omega/(4.0*PI); else au2 = av2 = 0.0; - au2 += np->u_alpha * np->u_alpha; - av2 += np->v_alpha * np->v_alpha; + au2 += np->u_alpha*np->u_alpha; + av2 += np->v_alpha*np->v_alpha; /* half vector */ h[0] = ldir[0] - np->rp->rdir[0]; h[1] = ldir[1] - np->rp->rdir[1]; h[2] = ldir[2] - np->rp->rdir[2]; normalize(h); /* ellipse */ - dtmp = DOT(np->u, h); - dtmp *= dtmp / au2; + dtmp1 = DOT(np->u, h); + dtmp1 *= dtmp1 / au2; dtmp2 = DOT(np->v, h); dtmp2 *= dtmp2 / av2; /* gaussian */ - dtmp = (dtmp + dtmp2) / (1.0 + DOT(np->pnorm, h)); - dtmp = exp(-2.0*dtmp) / (4.0*PI * sqrt(au2*av2)); + dtmp = (dtmp1 + dtmp2) / (1.0 + DOT(np->pnorm, h)); + dtmp = exp(-2.0*dtmp) * (1.0/4.0/PI) + * sqrt(ldot/(np->pdot*au2*av2)); /* worth using? */ if (dtmp > FTINY) { copycolor(ctmp, np->scolor); - dtmp *= omega / np->pdot; + dtmp *= omega; scalecolor(ctmp, dtmp); addcolor(cval, ctmp); } @@ -141,12 +142,33 @@ double omega; /* light source size */ * is always modified by material color. */ /* roughness + source */ + au2 = av2 = omega / PI; + au2 += np->u_alpha*np->u_alpha; + av2 += np->v_alpha*np->v_alpha; + /* "half vector" */ + h[0] = ldir[0] - np->prdir[0]; + h[1] = ldir[1] - np->prdir[1]; + h[2] = ldir[2] - np->prdir[2]; + dtmp = DOT(h,h); + if (dtmp > FTINY*FTINY) { + dtmp1 = DOT(h,np->pnorm); + dtmp = 1.0 - dtmp1*dtmp1/dtmp; + if (dtmp > FTINY*FTINY) { + dtmp1 = DOT(h,np->u); + dtmp1 = dtmp1*dtmp1 / au2; + dtmp2 = DOT(h,np->v); + dtmp2 = dtmp2*dtmp2 / av2; + dtmp = (dtmp1 + dtmp2) / dtmp; + } + } else + dtmp = 0.0; /* gaussian */ - dtmp = 0.0; + dtmp = exp(-dtmp) * (1.0/PI) + * sqrt(-ldot/(np->pdot*au2*av2)); /* worth using? */ if (dtmp > FTINY) { copycolor(ctmp, np->mcolor); - dtmp *= np->tspec * omega / np->pdot; + dtmp *= np->tspec * omega; scalecolor(ctmp, dtmp); addcolor(cval, ctmp); } @@ -178,7 +200,7 @@ register RAY *r; nd.specfl = 0; nd.u_alpha = m->oargs.farg[4]; nd.v_alpha = m->oargs.farg[5]; - if (nd.u_alpha < 1e-6 || nd.v_alpha <= 1e-6) + if (nd.u_alpha < FTINY || nd.v_alpha <= FTINY) objerror(m, USER, "roughness too small"); /* reorient if necessary */ if (r->rod < 0.0) @@ -205,8 +227,8 @@ register RAY *r; nd.rspec += (1.0-nd.rspec)*dtmp; /* check threshold */ if (specthresh > FTINY && - ((specthresh >= 1.-FTINY || - specthresh + (.05 - .1*frandom()) > nd.rspec))) + (specthresh >= 1.-FTINY || + specthresh + .05 - .1*frandom() > nd.rspec)) nd.specfl |= SP_RBLT; /* compute refl. direction */ for (i = 0; i < 3; i++) @@ -216,7 +238,7 @@ register RAY *r; nd.vrefl[i] = r->rdir[i] + 2.*r->rod*r->ron[i]; } /* compute transmission */ - if (m->otype == MAT_TRANS) { + if (m->otype == MAT_TRANS2) { nd.trans = m->oargs.farg[6]*(1.0 - nd.rspec); nd.tspec = nd.trans * m->oargs.farg[7]; nd.tdiff = nd.trans - nd.tspec; @@ -224,16 +246,14 @@ register RAY *r; nd.specfl |= SP_TRAN; /* check threshold */ if (specthresh > FTINY && - ((specthresh >= 1.-FTINY || - specthresh + - (.05 - .1*frandom()) > nd.tspec))) + (specthresh >= 1.-FTINY || + specthresh + .05 - .1*frandom() > nd.tspec)) nd.specfl |= SP_TBLT; if (DOT(r->pert,r->pert) <= FTINY*FTINY) { VCOPY(nd.prdir, r->rdir); } else { for (i = 0; i < 3; i++) /* perturb */ - nd.prdir[i] = r->rdir[i] - - 0.5*r->pert[i]; + nd.prdir[i] = r->rdir[i] - r->pert[i]; if (DOT(nd.prdir, r->ron) < -FTINY) normalize(nd.prdir); /* OK */ else @@ -298,7 +318,8 @@ register ANISODAT *np; np->specfl |= SP_BADU; return; } - multv3(np->u, np->u, mf->f->xfm); + if (mf->f != &unitxf) + multv3(np->u, np->u, mf->f->xfm); fcross(np->v, np->pnorm, np->u); if (normalize(np->v) == 0.0) { objerror(np->mp, WARNING, "illegal orientation vector"); @@ -326,8 +347,8 @@ register ANISODAT *np; d = urand(ilhash(dimlist,ndims)+samplendx); multisamp(rv, 2, d); d = 2.0*PI * rv[0]; - cosp = np->u_alpha * cos(d); - sinp = np->v_alpha * sin(d); + cosp = cos(d) * np->u_alpha; + sinp = sin(d) * np->v_alpha; d = sqrt(cosp*cosp + sinp*sinp); cosp /= d; sinp /= d; @@ -358,15 +379,18 @@ register ANISODAT *np; d = urand(ilhash(dimlist,ndims)+1823+samplendx); multisamp(rv, 2, d); d = 2.0*PI * rv[0]; - cosp = cos(d); - sinp = sin(d); + cosp = cos(d) * np->u_alpha; + sinp = sin(d) * np->v_alpha; + d = sqrt(cosp*cosp + sinp*sinp); + cosp /= d; + sinp /= d; rv[1] = 1.0 - specjitter*rv[1]; if (rv[1] <= FTINY) d = 1.0; else d = sqrt(-log(rv[1]) / - (cosp*cosp*4./(np->u_alpha*np->u_alpha) + - sinp*sinp*4./(np->v_alpha*np->v_alpha))); + (cosp*cosp/(np->u_alpha*np->u_alpha) + + sinp*sinp/(np->v_alpha*np->u_alpha))); for (i = 0; i < 3; i++) sr.rdir[i] = np->prdir[i] + d*(cosp*np->u[i] + sinp*np->v[i]);