Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F63724434
aniso.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Wed, May 22, 02:33
Size
12 KB
Mime Type
text/x-c
Expires
Fri, May 24, 02:33 (2 d)
Engine
blob
Format
Raw Data
Handle
17810939
Attached To
R10977 RADIANCE Photon Map
aniso.c
View Options
#ifndef lint
static const char RCSid[] = "$Id: aniso.c,v 2.61 2015/09/02 18:59:01 greg Exp $";
#endif
/*
* Shading functions for anisotropic materials.
*/
#include "copyright.h"
#include "ray.h"
#include "ambient.h"
#include "otypes.h"
#include "rtotypes.h"
#include "source.h"
#include "func.h"
#include "random.h"
#include "pmapmat.h"
#ifndef MAXITER
#define MAXITER 10 /* maximum # specular ray attempts */
#endif
/*
* This routine implements the anisotropic Gaussian
* model described by Ward in Siggraph `92 article, updated with
* normalization and sampling adjustments due to Geisler-Moroder and Duer.
* We orient the surface towards the incoming ray, so a single
* surface can be used to represent an infinitely thin object.
*
* Arguments for MAT_PLASTIC2 and MAT_METAL2 are:
* 4+ ux uy uz funcfile [transform...]
* 0
* 6 red grn blu specular-frac. u-rough v-rough
*
* Real arguments for MAT_TRANS2 are:
* 8 red grn blu rspec u-rough v-rough trans tspec
*/
/* specularity flags */
#define SP_REFL 01 /* has reflected specular component */
#define SP_TRAN 02 /* has transmitted specular */
#define SP_FLAT 04 /* reflecting surface is flat */
#define SP_RBLT 010 /* reflection below sample threshold */
#define SP_TBLT 020 /* transmission below threshold */
typedef struct {
OBJREC *mp; /* material pointer */
RAY *rp; /* ray pointer */
short specfl; /* specularity flags, defined above */
COLOR mcolor; /* color of this material */
COLOR scolor; /* color of specular component */
FVECT vrefl; /* vector in reflected direction */
FVECT prdir; /* vector in transmitted direction */
FVECT u, v; /* u and v vectors orienting anisotropy */
double u_alpha; /* u roughness */
double v_alpha; /* v roughness */
double rdiff, rspec; /* reflected specular, diffuse */
double trans; /* transmissivity */
double tdiff, tspec; /* transmitted specular, diffuse */
FVECT pnorm; /* perturbed surface normal */
double pdot; /* perturbed dot product */
} ANISODAT; /* anisotropic material data */
static void getacoords(ANISODAT *np);
static void agaussamp(ANISODAT *np);
static void
diraniso( /* compute source contribution */
COLOR cval, /* returned coefficient */
void *nnp, /* material data */
FVECT ldir, /* light source direction */
double omega /* light source size */
)
{
ANISODAT *np = nnp;
double ldot;
double dtmp, dtmp1, dtmp2;
FVECT h;
double au2, av2;
COLOR ctmp;
setcolor(cval, 0.0, 0.0, 0.0);
ldot = DOT(np->pnorm, ldir);
if (ldot < 0.0 ? np->trans <= FTINY : np->trans >= 1.0-FTINY)
return; /* wrong side */
if ((ldot > FTINY) & (np->rdiff > 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 * (1.0/PI);
scalecolor(ctmp, dtmp);
addcolor(cval, ctmp);
}
if ((ldot < -FTINY) & (np->tdiff > FTINY)) {
/*
* Compute diffuse transmission.
*/
copycolor(ctmp, np->mcolor);
dtmp = -ldot * omega * np->tdiff * (1.0/PI);
scalecolor(ctmp, dtmp);
addcolor(cval, ctmp);
}
if (ambRayInPmap(np->rp))
return; /* specular accounted for in photon map */
if (ldot > FTINY && np->specfl&SP_REFL) {
/*
* Compute specular reflection coefficient using
* anisotropic Gaussian distribution model.
*/
/* add source width if flat */
if (np->specfl & SP_FLAT)
au2 = av2 = omega * (0.25/PI);
else
au2 = av2 = 0.0;
au2 += np->u_alpha*np->u_alpha;
av2 += np->v_alpha*np->v_alpha;
/* half vector */
VSUB(h, ldir, np->rp->rdir);
/* ellipse */
dtmp1 = DOT(np->u, h);
dtmp1 *= dtmp1 / au2;
dtmp2 = DOT(np->v, h);
dtmp2 *= dtmp2 / av2;
/* new W-G-M-D model */
dtmp = DOT(np->pnorm, h);
dtmp *= dtmp;
dtmp1 = (dtmp1 + dtmp2) / dtmp;
dtmp = exp(-dtmp1) * DOT(h,h) /
(PI * dtmp*dtmp * sqrt(au2*av2));
/* worth using? */
if (dtmp > FTINY) {
copycolor(ctmp, np->scolor);
dtmp *= ldot * omega;
scalecolor(ctmp, dtmp);
addcolor(cval, ctmp);
}
}
if (ldot < -FTINY && np->specfl&SP_TRAN) {
/*
* Compute specular transmission. Specular transmission
* is always modified by material color.
*/
/* roughness + source */
au2 = av2 = omega * (1.0/PI);
au2 += np->u_alpha*np->u_alpha;
av2 += np->v_alpha*np->v_alpha;
/* "half vector" */
VSUB(h, ldir, np->prdir);
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 / au2;
dtmp2 = DOT(h,np->v);
dtmp2 *= dtmp2 / av2;
dtmp = (dtmp1 + dtmp2) / dtmp;
}
} else
dtmp = 0.0;
/* Gaussian */
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;
scalecolor(ctmp, dtmp);
addcolor(cval, ctmp);
}
}
}
int
m_aniso( /* shade ray that hit something anisotropic */
OBJREC *m,
RAY *r
)
{
ANISODAT nd;
COLOR ctmp;
int i;
/* easy shadow test */
if (r->crtype & SHADOW)
return(1);
if (m->oargs.nfargs != (m->otype == MAT_TRANS2 ? 8 : 6))
objerror(m, USER, "bad number of real arguments");
/* check for back side */
if (r->rod < 0.0) {
if (!backvis) {
raytrans(r);
return(1);
}
raytexture(r, m->omod);
flipsurface(r); /* reorient if backvis */
} else
raytexture(r, m->omod);
/* get material color */
nd.mp = m;
nd.rp = r;
setcolor(nd.mcolor, m->oargs.farg[0],
m->oargs.farg[1],
m->oargs.farg[2]);
/* get roughness */
nd.specfl = 0;
nd.u_alpha = m->oargs.farg[4];
nd.v_alpha = m->oargs.farg[5];
if ((nd.u_alpha <= FTINY) | (nd.v_alpha <= FTINY))
objerror(m, USER, "roughness too small");
nd.pdot = raynormal(nd.pnorm, r); /* perturb normal */
if (nd.pdot < .001)
nd.pdot = .001; /* non-zero for diraniso() */
multcolor(nd.mcolor, r->pcol); /* modify material color */
/* get specular component */
if ((nd.rspec = m->oargs.farg[3]) > FTINY) {
nd.specfl |= SP_REFL;
/* compute specular color */
if (m->otype == MAT_METAL2)
copycolor(nd.scolor, nd.mcolor);
else
setcolor(nd.scolor, 1.0, 1.0, 1.0);
scalecolor(nd.scolor, nd.rspec);
/* check threshold */
if (specthresh >= nd.rspec-FTINY)
nd.specfl |= SP_RBLT;
/* compute refl. direction */
VSUM(nd.vrefl, r->rdir, nd.pnorm, 2.0*nd.pdot);
if (DOT(nd.vrefl, r->ron) <= FTINY) /* penetration? */
VSUM(nd.vrefl, r->rdir, r->ron, 2.0*r->rod);
}
/* compute transmission */
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;
if (nd.tspec > FTINY) {
nd.specfl |= SP_TRAN;
/* check threshold */
if (specthresh >= nd.tspec-FTINY)
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] - r->pert[i];
if (DOT(nd.prdir, r->ron) < -FTINY)
normalize(nd.prdir); /* OK */
else
VCOPY(nd.prdir, r->rdir);
}
}
} else
nd.tdiff = nd.tspec = nd.trans = 0.0;
/* diffuse reflection */
nd.rdiff = 1.0 - nd.trans - nd.rspec;
if (r->ro != NULL && isflat(r->ro->otype))
nd.specfl |= SP_FLAT;
getacoords(&nd); /* set up coordinates */
if (nd.specfl & (SP_REFL|SP_TRAN))
agaussamp(&nd);
if (nd.rdiff > FTINY) { /* ambient from this side */
copycolor(ctmp, nd.mcolor); /* modified by material color */
scalecolor(ctmp, nd.rdiff);
if (nd.specfl & SP_RBLT) /* add in specular as well? */
addcolor(ctmp, nd.scolor);
multambient(ctmp, r, nd.pnorm);
addcolor(r->rcol, ctmp); /* add to returned color */
}
if (nd.tdiff > FTINY) { /* ambient from other side */
FVECT bnorm;
flipsurface(r);
bnorm[0] = -nd.pnorm[0];
bnorm[1] = -nd.pnorm[1];
bnorm[2] = -nd.pnorm[2];
copycolor(ctmp, nd.mcolor); /* modified by color */
if (nd.specfl & SP_TBLT)
scalecolor(ctmp, nd.trans);
else
scalecolor(ctmp, nd.tdiff);
multambient(ctmp, r, bnorm);
addcolor(r->rcol, ctmp);
flipsurface(r);
}
/* add direct component */
direct(r, diraniso, &nd);
return(1);
}
static void
getacoords( /* set up coordinate system */
ANISODAT *np
)
{
MFUNC *mf;
int i;
mf = getfunc(np->mp, 3, 0x7, 1);
setfunc(np->mp, np->rp);
errno = 0;
for (i = 0; i < 3; i++)
np->u[i] = evalue(mf->ep[i]);
if ((errno == EDOM) | (errno == ERANGE))
np->u[0] = np->u[1] = np->u[2] = 0.0;
if (mf->fxp != &unitxf)
multv3(np->u, np->u, mf->fxp->xfm);
fcross(np->v, np->pnorm, np->u);
if (normalize(np->v) == 0.0) {
if (fabs(np->u_alpha - np->v_alpha) > 0.001)
objerror(np->mp, WARNING, "illegal orientation vector");
getperpendicular(np->u, np->pnorm, 1); /* punting */
fcross(np->v, np->pnorm, np->u);
np->u_alpha = np->v_alpha = sqrt( 0.5 *
(np->u_alpha*np->u_alpha + np->v_alpha*np->v_alpha) );
} else
fcross(np->u, np->v, np->pnorm);
}
static void
agaussamp( /* sample anisotropic Gaussian specular */
ANISODAT *np
)
{
RAY sr;
FVECT h;
double rv[2];
double d, sinp, cosp;
COLOR scol;
int maxiter, ntrials, nstarget, nstaken;
int i;
/* compute reflection */
if ((np->specfl & (SP_REFL|SP_RBLT)) == SP_REFL &&
rayorigin(&sr, SPECULAR, np->rp, np->scolor) == 0) {
nstarget = 1;
if (specjitter > 1.5) { /* multiple samples? */
nstarget = specjitter*np->rp->rweight + .5;
if (sr.rweight <= minweight*nstarget)
nstarget = sr.rweight/minweight;
if (nstarget > 1) {
d = 1./nstarget;
scalecolor(sr.rcoef, d);
sr.rweight *= d;
} else
nstarget = 1;
}
setcolor(scol, 0., 0., 0.);
dimlist[ndims++] = (int)(size_t)np->mp;
maxiter = MAXITER*nstarget;
for (nstaken = ntrials = 0; nstaken < nstarget &&
ntrials < maxiter; ntrials++) {
if (ntrials)
d = frandom();
else
d = urand(ilhash(dimlist,ndims)+samplendx);
multisamp(rv, 2, d);
d = 2.0*PI * rv[0];
cosp = tcos(d) * np->u_alpha;
sinp = tsin(d) * np->v_alpha;
d = 1./sqrt(cosp*cosp + sinp*sinp);
cosp *= d;
sinp *= d;
if ((0. <= specjitter) & (specjitter < 1.))
rv[1] = 1.0 - specjitter*rv[1];
if (rv[1] <= FTINY)
d = 1.0;
else
d = sqrt(-log(rv[1]) /
(cosp*cosp/(np->u_alpha*np->u_alpha) +
sinp*sinp/(np->v_alpha*np->v_alpha)));
for (i = 0; i < 3; i++)
h[i] = np->pnorm[i] +
d*(cosp*np->u[i] + sinp*np->v[i]);
d = -2.0 * DOT(h, np->rp->rdir) / (1.0 + d*d);
VSUM(sr.rdir, np->rp->rdir, h, d);
/* sample rejection test */
if ((d = DOT(sr.rdir, np->rp->ron)) <= FTINY)
continue;
checknorm(sr.rdir);
if (nstarget > 1) { /* W-G-M-D adjustment */
if (nstaken) rayclear(&sr);
rayvalue(&sr);
d = 2./(1. + np->rp->rod/d);
scalecolor(sr.rcol, d);
addcolor(scol, sr.rcol);
} else {
rayvalue(&sr);
multcolor(sr.rcol, sr.rcoef);
addcolor(np->rp->rcol, sr.rcol);
}
++nstaken;
}
if (nstarget > 1) { /* final W-G-M-D weighting */
multcolor(scol, sr.rcoef);
d = (double)nstarget/ntrials;
scalecolor(scol, d);
addcolor(np->rp->rcol, scol);
}
ndims--;
}
/* compute transmission */
copycolor(sr.rcoef, np->mcolor); /* modify by material color */
scalecolor(sr.rcoef, np->tspec);
if ((np->specfl & (SP_TRAN|SP_TBLT)) == SP_TRAN &&
rayorigin(&sr, SPECULAR, np->rp, sr.rcoef) == 0) {
nstarget = 1;
if (specjitter > 1.5) { /* multiple samples? */
nstarget = specjitter*np->rp->rweight + .5;
if (sr.rweight <= minweight*nstarget)
nstarget = sr.rweight/minweight;
if (nstarget > 1) {
d = 1./nstarget;
scalecolor(sr.rcoef, d);
sr.rweight *= d;
} else
nstarget = 1;
}
dimlist[ndims++] = (int)(size_t)np->mp;
maxiter = MAXITER*nstarget;
for (nstaken = ntrials = 0; nstaken < nstarget &&
ntrials < maxiter; ntrials++) {
if (ntrials)
d = frandom();
else
d = urand(ilhash(dimlist,ndims)+1823+samplendx);
multisamp(rv, 2, d);
d = 2.0*PI * rv[0];
cosp = tcos(d) * np->u_alpha;
sinp = tsin(d) * np->v_alpha;
d = 1./sqrt(cosp*cosp + sinp*sinp);
cosp *= d;
sinp *= d;
if ((0. <= specjitter) & (specjitter < 1.))
rv[1] = 1.0 - specjitter*rv[1];
if (rv[1] <= FTINY)
d = 1.0;
else
d = sqrt(-log(rv[1]) /
(cosp*cosp/(np->u_alpha*np->u_alpha) +
sinp*sinp/(np->v_alpha*np->v_alpha)));
for (i = 0; i < 3; i++)
sr.rdir[i] = np->prdir[i] +
d*(cosp*np->u[i] + sinp*np->v[i]);
if (DOT(sr.rdir, np->rp->ron) >= -FTINY)
continue;
normalize(sr.rdir); /* OK, normalize */
if (nstaken) /* multi-sampling */
rayclear(&sr);
rayvalue(&sr);
multcolor(sr.rcol, sr.rcoef);
addcolor(np->rp->rcol, sr.rcol);
++nstaken;
}
ndims--;
}
}
Event Timeline
Log In to Comment