Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F91120160
normal.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
Fri, Nov 8, 03:04
Size
13 KB
Mime Type
text/x-c
Expires
Sun, Nov 10, 03:04 (1 d, 23 h)
Engine
blob
Format
Raw Data
Handle
22146667
Attached To
R10977 RADIANCE Photon Map
normal.c
View Options
#ifndef lint
static const char RCSid[] = "$Id: normal.c,v 2.80 2019/04/19 19:01:32 greg Exp $";
#endif
/*
* normal.c - shading function for normal materials.
*
* 8/19/85
* 12/19/85 - added stuff for metals.
* 6/26/87 - improved specular model.
* 9/28/87 - added model for translucent materials.
* Later changes described in delta comments.
*/
#include "copyright.h"
#include "ray.h"
#include "ambient.h"
#include "source.h"
#include "otypes.h"
#include "rtotypes.h"
#include "random.h"
#include "pmapmat.h"
#ifndef MAXITER
#define MAXITER 10 /* maximum # specular ray attempts */
#endif
/* estimate of Fresnel function */
#define FRESNE(ci) (exp(-5.85*(ci)) - 0.00287989916)
#define FRESTHRESH 0.017999 /* minimum specularity for approx. */
/*
* This routine implements the isotropic 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.
*
* Arguments for MAT_PLASTIC and MAT_METAL are:
* red grn blu specular-frac. facet-slope
*
* Arguments for MAT_TRANS are:
* red grn blu rspec rough trans tspec
*/
/* specularity flags */
#define SP_REFL 01 /* has reflected specular component */
#define SP_TRAN 02 /* has transmitted specular */
#define SP_PURE 04 /* purely specular (zero roughness) */
#define SP_FLAT 010 /* flat reflecting surface */
#define SP_RBLT 020 /* reflection below sample threshold */
#define SP_TBLT 040 /* 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 direction of reflected ray */
FVECT prdir; /* vector in transmitted direction */
double alpha2; /* roughness squared */
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 */
} NORMDAT; /* normal material data */
static void gaussamp(NORMDAT *np);
static void
dirnorm( /* compute source contribution */
COLOR cval, /* returned coefficient */
void *nnp, /* material data */
FVECT ldir, /* light source direction */
double omega /* light source size */
)
{
NORMDAT *np = nnp;
double ldot;
double lrdiff, ltdiff;
double dtmp, d2, d3, d4;
FVECT vtmp;
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 */
/* Fresnel estimate */
lrdiff = np->rdiff;
ltdiff = np->tdiff;
if (np->specfl & SP_PURE && np->rspec >= FRESTHRESH &&
(lrdiff > FTINY) | (ltdiff > FTINY)) {
dtmp = 1. - FRESNE(fabs(ldot));
lrdiff *= dtmp;
ltdiff *= dtmp;
}
if (ldot > FTINY && lrdiff > 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 * lrdiff * (1.0/PI);
scalecolor(ctmp, dtmp);
addcolor(cval, ctmp);
}
if (ldot < -FTINY && ltdiff > FTINY) {
/*
* Compute diffuse transmission.
*/
copycolor(ctmp, np->mcolor);
dtmp = -ldot * omega * ltdiff * (1.0/PI);
scalecolor(ctmp, dtmp);
addcolor(cval, ctmp);
}
if (ambRayInPmap(np->rp))
return; /* specular already in photon map */
if (ldot > FTINY && (np->specfl&(SP_REFL|SP_PURE)) == SP_REFL) {
/*
* Compute specular reflection coefficient using
* Gaussian distribution model.
*/
/* roughness */
dtmp = np->alpha2;
/* + source if flat */
if (np->specfl & SP_FLAT)
dtmp += omega * (0.25/PI);
/* half vector */
VSUB(vtmp, ldir, np->rp->rdir);
d2 = DOT(vtmp, np->pnorm);
d2 *= d2;
d3 = DOT(vtmp,vtmp);
d4 = (d3 - d2) / d2;
/* new W-G-M-D model */
dtmp = exp(-d4/dtmp) * d3 / (PI * d2*d2 * dtmp);
/* 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|SP_PURE)) == SP_TRAN) {
/*
* Compute specular transmission. Specular transmission
* is always modified by material color.
*/
/* roughness + source */
dtmp = np->alpha2 + omega*(1.0/PI);
/* Gaussian */
dtmp = exp((2.*DOT(np->prdir,ldir)-2.)/dtmp)/(PI*dtmp);
/* worth using? */
if (dtmp > FTINY) {
copycolor(ctmp, np->mcolor);
dtmp *= np->tspec * omega * sqrt(-ldot/np->pdot);
scalecolor(ctmp, dtmp);
addcolor(cval, ctmp);
}
}
}
int
m_normal( /* color a ray that hit something normal */
OBJREC *m,
RAY *r
)
{
NORMDAT nd;
double fest;
int hastexture;
double d;
COLOR ctmp;
int i;
/* PMAP: skip transmitted shadow ray if accounted for in photon map */
/* No longer needed?
if (shadowRayInPmap(r) || ambRayInPmap(r))
return(1); */
/* easy shadow test */
if (r->crtype & SHADOW && m->otype != MAT_TRANS)
return(1);
if (m->oargs.nfargs != (m->otype == MAT_TRANS ? 7 : 5))
objerror(m, USER, "bad number of 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);
nd.mp = m;
nd.rp = r;
/* get material color */
setcolor(nd.mcolor, m->oargs.farg[0],
m->oargs.farg[1],
m->oargs.farg[2]);
/* get roughness */
nd.specfl = 0;
nd.alpha2 = m->oargs.farg[4];
if ((nd.alpha2 *= nd.alpha2) <= FTINY)
nd.specfl |= SP_PURE;
if ( (hastexture = (DOT(r->pert,r->pert) > FTINY*FTINY)) ) {
nd.pdot = raynormal(nd.pnorm, r); /* perturb normal */
} 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 */
nd.rspec = m->oargs.farg[3];
/* compute Fresnel approx. */
if (nd.specfl & SP_PURE && nd.rspec >= FRESTHRESH) {
fest = FRESNE(nd.pdot);
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);
nd.tspec = nd.trans * m->oargs.farg[6];
nd.tdiff = nd.trans - nd.tspec;
if (nd.tspec > FTINY) {
nd.specfl |= SP_TRAN;
/* check threshold */
if (!(nd.specfl & SP_PURE) &&
specthresh >= nd.tspec-FTINY)
nd.specfl |= SP_TBLT;
if (!hastexture || r->crtype & (SHADOW|AMBIENT)) {
VCOPY(nd.prdir, r->rdir);
} else {
/* perturb */
VSUB(nd.prdir, r->rdir, r->pert);
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;
/* transmitted ray */
if ((nd.specfl&(SP_TRAN|SP_PURE|SP_TBLT)) == (SP_TRAN|SP_PURE)) {
RAY lr;
copycolor(lr.rcoef, nd.mcolor); /* modified by color */
scalecolor(lr.rcoef, nd.tspec);
if (rayorigin(&lr, TRANS, r, lr.rcoef) == 0) {
VCOPY(lr.rdir, nd.prdir);
rayvalue(&lr);
multcolor(lr.rcol, lr.rcoef);
addcolor(r->rcol, lr.rcol);
if (nd.tspec >= 1.0-FTINY) {
/* completely transparent */
multcolor(lr.mcol, lr.rcoef);
copycolor(r->mcol, lr.mcol);
r->rmt = r->rot + lr.rmt;
r->rxt = r->rot + lr.rxt;
} else if (nd.tspec > nd.tdiff + nd.rdiff)
r->rxt = r->rot + raydistance(&lr);
}
}
if (r->crtype & SHADOW) /* the rest is shadow */
return(1);
/* get specular reflection */
if (nd.rspec > FTINY) {
nd.specfl |= SP_REFL;
/* compute specular color */
if (m->otype != MAT_METAL) {
setcolor(nd.scolor, nd.rspec, nd.rspec, nd.rspec);
} else if (fest > FTINY) {
d = m->oargs.farg[3]*(1. - fest);
for (i = 0; i < 3; i++)
colval(nd.scolor,i) = fest +
colval(nd.mcolor,i)*d;
} else {
copycolor(nd.scolor, nd.mcolor);
scalecolor(nd.scolor, nd.rspec);
}
/* check threshold */
if (!(nd.specfl & SP_PURE) && specthresh >= nd.rspec-FTINY)
nd.specfl |= SP_RBLT;
/* compute reflected ray */
VSUM(nd.vrefl, r->rdir, nd.pnorm, 2.*nd.pdot);
/* penetration? */
if (hastexture && DOT(nd.vrefl, r->ron) <= FTINY)
VSUM(nd.vrefl, r->rdir, r->ron, 2.*r->rod);
checknorm(nd.vrefl);
}
/* reflected ray */
if ((nd.specfl&(SP_REFL|SP_PURE|SP_RBLT)) == (SP_REFL|SP_PURE)) {
RAY lr;
if (rayorigin(&lr, REFLECTED, r, nd.scolor) == 0) {
VCOPY(lr.rdir, nd.vrefl);
rayvalue(&lr);
multcolor(lr.rcol, lr.rcoef);
copycolor(r->mcol, lr.rcol);
addcolor(r->rcol, lr.rcol);
r->rmt = r->rot;
if (nd.specfl & SP_FLAT &&
!hastexture | (r->crtype & AMBIENT))
r->rmt += raydistance(&lr);
}
}
if (nd.specfl & SP_PURE && nd.rdiff <= FTINY && nd.tdiff <= FTINY)
return(1); /* 100% pure specular */
if (!(nd.specfl & SP_PURE))
gaussamp(&nd); /* checks *BLT flags */
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, hastexture ? nd.pnorm : r->ron);
addcolor(r->rcol, ctmp); /* add to returned color */
}
if (nd.tdiff > FTINY) { /* ambient from other side */
copycolor(ctmp, nd.mcolor); /* modified by color */
if (nd.specfl & SP_TBLT)
scalecolor(ctmp, nd.trans);
else
scalecolor(ctmp, nd.tdiff);
flipsurface(r);
if (hastexture) {
FVECT bnorm;
bnorm[0] = -nd.pnorm[0];
bnorm[1] = -nd.pnorm[1];
bnorm[2] = -nd.pnorm[2];
multambient(ctmp, r, bnorm);
} else
multambient(ctmp, r, r->ron);
addcolor(r->rcol, ctmp);
flipsurface(r);
}
/* add direct component */
direct(r, dirnorm, &nd);
return(1);
}
static void
gaussamp( /* sample Gaussian specular */
NORMDAT *np
)
{
RAY sr;
FVECT u, v, h;
double rv[2];
double d, sinp, cosp;
COLOR scol;
int maxiter, ntrials, nstarget, nstaken;
int i;
/* quick test */
if ((np->specfl & (SP_REFL|SP_RBLT)) != SP_REFL &&
(np->specfl & (SP_TRAN|SP_TBLT)) != SP_TRAN)
return;
/* set up sample coordinates */
getperpendicular(u, np->pnorm, rand_samp);
fcross(v, np->pnorm, u);
/* 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);
sinp = tsin(d);
if ((0. <= specjitter) & (specjitter < 1.))
rv[1] = 1.0 - specjitter*rv[1];
if (rv[1] <= FTINY)
d = 1.0;
else
d = sqrt( np->alpha2 * -log(rv[1]) );
for (i = 0; i < 3; i++)
h[i] = np->pnorm[i] + d*(cosp*u[i] + sinp*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); /* modified by 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)+samplendx);
multisamp(rv, 2, d);
d = 2.0*PI * rv[0];
cosp = tcos(d);
sinp = tsin(d);
if ((0. <= specjitter) & (specjitter < 1.))
rv[1] = 1.0 - specjitter*rv[1];
if (rv[1] <= FTINY)
d = 1.0;
else
d = sqrt( np->alpha2 * -log(rv[1]) );
for (i = 0; i < 3; i++)
sr.rdir[i] = np->prdir[i] + d*(cosp*u[i] + sinp*v[i]);
/* sample rejection test */
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