--- ray/src/rt/m_bsdf.c 2011/02/22 05:41:02 2.7 +++ ray/src/rt/m_bsdf.c 2011/08/22 16:00:47 2.15 @@ -1,5 +1,5 @@ #ifndef lint -static const char RCSid[] = "$Id: m_bsdf.c,v 2.7 2011/02/22 05:41:02 greg Exp $"; +static const char RCSid[] = "$Id: m_bsdf.c,v 2.15 2011/08/22 16:00:47 greg Exp $"; #endif /* * Shading for materials with BSDFs taken from XML data files @@ -50,7 +50,7 @@ static const char RCSid[] = "$Id: m_bsdf.c,v 2.7 2011/ * Arguments for MAT_BSDF are: * 6+ thick BSDFfile ux uy uz funcfile transform * 0 - * 0|3|9 rdf gdf bdf + * 0|3|6|9 rdf gdf bdf * rdb gdb bdb * rdt gdt bdt */ @@ -67,7 +67,7 @@ typedef struct { RAY *pr; /* intersected ray */ FVECT pnorm; /* perturbed surface normal */ FVECT vray; /* local outgoing (return) vector */ - double sr_vpsa; /* sqrt of BSDF projected solid angle */ + double sr_vpsa[2]; /* sqrt of BSDF projected solid angle extrema */ RREAL toloc[3][3]; /* world to local BSDF coords */ RREAL fromloc[3][3]; /* local BSDF coords to world */ double thick; /* surface thickness */ @@ -82,10 +82,8 @@ typedef struct { /* Jitter ray sample according to projected solid angle and specjitter */ static void -bsdf_jitter(FVECT vres, BSDFDAT *ndp) +bsdf_jitter(FVECT vres, BSDFDAT *ndp, double sr_psa) { - double sr_psa = ndp->sr_vpsa; - VCOPY(vres, ndp->vray); if (specjitter < 1.) sr_psa *= specjitter; @@ -98,33 +96,67 @@ bsdf_jitter(FVECT vres, BSDFDAT *ndp) /* Evaluate BSDF for direct component, returning true if OK to proceed */ static int -direct_bsdf_OK(COLOR cval, FVECT ldir, BSDFDAT *ndp) +direct_bsdf_OK(COLOR cval, FVECT ldir, double omega, BSDFDAT *ndp) { - FVECT vsrc, vjit; + int nsamp, ok = 0; + FVECT vsrc, vsmp, vjit; + double tomega; + double sf, tsr, sd[2]; + COLOR csmp; SDValue sv; SDError ec; + int i; /* transform source direction */ if (SDmapDir(vsrc, ndp->toloc, ldir) != SDEnone) return(0); - /* jitter query direction */ - bsdf_jitter(vjit, ndp); - /* avoid indirect over-counting */ - if (ndp->thick != .0 && ndp->pr->crtype & (SPECULAR|AMBIENT) && - vsrc[2] > .0 ^ vjit[2] > .0) { - double dx = vsrc[0] + vjit[0]; - double dy = vsrc[1] + vjit[1]; - if (dx*dx + dy*dy <= ndp->sr_vpsa*ndp->sr_vpsa) + /* check indirect over-counting */ + if (ndp->thick != 0 && ndp->pr->crtype & (SPECULAR|AMBIENT) + && vsrc[2] > 0 ^ ndp->vray[2] > 0) { + double dx = vsrc[0] + ndp->vray[0]; + double dy = vsrc[1] + ndp->vray[1]; + if (dx*dx + dy*dy <= omega*(1./PI)) return(0); } - ec = SDevalBSDF(&sv, vjit, vsrc, ndp->sd); + /* assign number of samples */ + ec = SDsizeBSDF(&tomega, ndp->vray, vsrc, SDqueryMin, ndp->sd); if (ec) - objerror(ndp->mp, USER, transSDError(ec)); - - if (sv.cieY <= FTINY) /* not worth using? */ - return(0); - /* else we're good to go */ - cvt_sdcolor(cval, &sv); - return(1); + goto baderror; + sf = specjitter * ndp->pr->rweight; + if (25.*tomega <= omega) + nsamp = 100.*sf + .5; + else + nsamp = 4.*sf*omega/tomega + .5; + nsamp += !nsamp; + setcolor(cval, .0, .0, .0); /* sample our source area */ + sf = sqrt(omega); + tsr = sqrt(tomega); + for (i = nsamp; i--; ) { + VCOPY(vsmp, vsrc); /* jitter query directions */ + if (nsamp > 1) { + multisamp(sd, 2, (i + frandom())/(double)nsamp); + vsmp[0] += (sd[0] - .5)*sf; + vsmp[1] += (sd[1] - .5)*sf; + if (normalize(vsmp) == 0) { + --nsamp; + continue; + } + } + bsdf_jitter(vjit, ndp, tsr); + /* compute BSDF */ + ec = SDevalBSDF(&sv, vjit, vsmp, ndp->sd); + if (ec) + goto baderror; + if (sv.cieY <= FTINY) /* worth using? */ + continue; + cvt_sdcolor(csmp, &sv); + addcolor(cval, csmp); /* average it in */ + ++ok; + } + sf = 1./(double)nsamp; + scalecolor(cval, sf); + return(ok); +baderror: + objerror(ndp->mp, USER, transSDError(ec)); } /* Compute source contribution for BSDF (reflected & transmitted) */ @@ -147,7 +179,7 @@ dir_bsdf( if ((-FTINY <= ldot) & (ldot <= FTINY)) return; - if (ldot > .0 && bright(np->rdiff) > FTINY) { + if (ldot > 0 && bright(np->rdiff) > FTINY) { /* * Compute added diffuse reflected component. */ @@ -156,7 +188,7 @@ dir_bsdf( scalecolor(ctmp, dtmp); addcolor(cval, ctmp); } - if (ldot < .0 && bright(np->tdiff) > FTINY) { + if (ldot < 0 && bright(np->tdiff) > FTINY) { /* * Compute added diffuse transmission. */ @@ -168,11 +200,11 @@ dir_bsdf( /* * Compute scattering coefficient using BSDF. */ - if (!direct_bsdf_OK(ctmp, ldir, np)) + if (!direct_bsdf_OK(ctmp, ldir, omega, np)) return; - if (ldot > .0) { /* pattern only diffuse reflection */ + if (ldot > 0) { /* pattern only diffuse reflection */ COLOR ctmp1, ctmp2; - dtmp = (np->pr->rod > .0) ? np->sd->rLambFront.cieY + dtmp = (np->pr->rod > 0) ? np->sd->rLambFront.cieY : np->sd->rLambBack.cieY; /* diffuse fraction */ dtmp /= PI * bright(ctmp); @@ -223,10 +255,10 @@ dir_brdf( /* * Compute reflection coefficient using BSDF. */ - if (!direct_bsdf_OK(ctmp, ldir, np)) + if (!direct_bsdf_OK(ctmp, ldir, omega, np)) return; /* pattern only diffuse reflection */ - dtmp = (np->pr->rod > .0) ? np->sd->rLambFront.cieY + dtmp = (np->pr->rod > 0) ? np->sd->rLambFront.cieY : np->sd->rLambBack.cieY; dtmp /= PI * bright(ctmp); /* diffuse fraction */ copycolor(ctmp2, np->pr->pcol); @@ -272,7 +304,7 @@ dir_btdf( /* * Compute scattering coefficient using BSDF. */ - if (!direct_bsdf_OK(ctmp, ldir, np)) + if (!direct_bsdf_OK(ctmp, ldir, omega, np)) return; /* full pattern on transmission */ multcolor(ctmp, np->pr->pcol); @@ -286,56 +318,53 @@ static int sample_sdcomp(BSDFDAT *ndp, SDComponent *dcp, int usepat) { int nstarget = 1; - int nsent = 0; + int nsent; SDError ec; SDValue bsv; - double sthick; - FVECT vjit, vsmp; + double xrand; + FVECT vsmp; RAY sr; - int ntrials; /* multiple samples? */ if (specjitter > 1.5) { nstarget = specjitter*ndp->pr->rweight + .5; - if (nstarget < 1) - nstarget = 1; + nstarget += !nstarget; } - /* run through our trials */ - for (ntrials = 0; nsent < nstarget && ntrials < 9*nstarget; ntrials++) { - SDerrorDetail[0] = '\0'; - /* sample direction & coef. */ - bsdf_jitter(vjit, ndp); - ec = SDsampComponent(&bsv, vsmp, vjit, ntrials ? frandom() - : urand(ilhash(dimlist,ndims)+samplendx), dcp); + /* run through our samples */ + for (nsent = 0; nsent < nstarget; nsent++) { + if (nstarget == 1) { /* stratify random variable */ + xrand = urand(ilhash(dimlist,ndims)+samplendx); + if (specjitter < 1.) + xrand = .5 + specjitter*(xrand-.5); + } else { + xrand = (nsent + frandom())/(double)nstarget; + } + SDerrorDetail[0] = '\0'; /* sample direction & coef. */ + bsdf_jitter(vsmp, ndp, ndp->sr_vpsa[0]); + ec = SDsampComponent(&bsv, vsmp, xrand, dcp); if (ec) objerror(ndp->mp, USER, transSDError(ec)); - /* zero component? */ - if (bsv.cieY <= FTINY) + if (bsv.cieY <= FTINY) /* zero component? */ break; /* map vector to world */ if (SDmapDir(sr.rdir, ndp->fromloc, vsmp) != SDEnone) break; - /* unintentional penetration? */ - if (DOT(sr.rdir, ndp->pr->ron) > .0 ^ vsmp[2] > .0) - continue; /* spawn a specular ray */ if (nstarget > 1) bsv.cieY /= (double)nstarget; - cvt_sdcolor(sr.rcoef, &bsv); /* use color */ - if (usepat) /* pattern on transmission */ + cvt_sdcolor(sr.rcoef, &bsv); /* use sample color */ + if (usepat) /* apply pattern? */ multcolor(sr.rcoef, ndp->pr->pcol); if (rayorigin(&sr, SPECULAR, ndp->pr, sr.rcoef) < 0) { - if (maxdepth > 0) + if (maxdepth > 0) break; - ++nsent; /* Russian roulette victim */ - continue; + continue; /* Russian roulette victim */ } /* need to offset origin? */ - if (ndp->thick != .0 && ndp->pr->rod > .0 ^ vsmp[2] > .0) + if (ndp->thick != 0 && ndp->pr->rod > 0 ^ vsmp[2] > 0) VSUM(sr.rorg, sr.rorg, ndp->pr->ron, -ndp->thick); rayvalue(&sr); /* send & evaluate sample */ multcolor(sr.rcol, sr.rcoef); addcolor(ndp->pr->rcol, sr.rcol); - ++nsent; } return(nsent); } @@ -354,7 +383,7 @@ sample_sdf(BSDFDAT *ndp, int sflags) cvt_sdcolor(unsc, &ndp->sd->tLamb); } else /* sflags == SDsampSpR */ { unsc = ndp->runsamp; - if (ndp->pr->rod > .0) { + if (ndp->pr->rod > 0) { dfp = ndp->sd->rf; cvt_sdcolor(unsc, &ndp->sd->rLambFront); } else { @@ -371,7 +400,7 @@ sample_sdf(BSDFDAT *ndp, int sflags) FVECT vjit; double d; COLOR ctmp; - bsdf_jitter(vjit, ndp); + bsdf_jitter(vjit, ndp, ndp->sr_vpsa[1]); d = SDdirectHemi(vjit, sflags, ndp->sd); if (sflags == SDsampSpT) { copycolor(ctmp, ndp->pr->pcol); @@ -408,7 +437,7 @@ m_bsdf(OBJREC *m, RAY *r) (m->oargs.nfargs % 3)) objerror(m, USER, "bad # arguments"); /* record surface struck */ - hitfront = (r->rod > .0); + hitfront = (r->rod > 0); /* load cal file */ mf = getfunc(m, 5, 0x1d, 1); /* get thickness */ @@ -417,13 +446,13 @@ m_bsdf(OBJREC *m, RAY *r) nd.thick = .0; /* check shadow */ if (r->crtype & SHADOW) { - if (nd.thick != .0) + if (nd.thick != 0) raytrans(r); /* pass-through */ return(1); /* or shadow */ } /* check other rays to pass */ - if (nd.thick != .0 && (!(r->crtype & (SPECULAR|AMBIENT)) || - nd.thick > .0 ^ hitfront)) { + if (nd.thick != 0 && (!(r->crtype & (SPECULAR|AMBIENT)) || + nd.thick > 0 ^ hitfront)) { raytrans(r); /* hide our proxy */ return(1); } @@ -487,14 +516,15 @@ m_bsdf(OBJREC *m, RAY *r) ec = SDinvXform(nd.fromloc, nd.toloc); /* determine BSDF resolution */ if (!ec) - ec = SDsizeBSDF(&nd.sr_vpsa, nd.vray, SDqueryMin, nd.sd); - if (!ec) - nd.sr_vpsa = sqrt(nd.sr_vpsa); - else { + ec = SDsizeBSDF(nd.sr_vpsa, nd.vray, NULL, + SDqueryMin+SDqueryMax, nd.sd); + if (ec) { objerror(m, WARNING, transSDError(ec)); SDfreeCache(nd.sd); return(1); } + nd.sr_vpsa[0] = sqrt(nd.sr_vpsa[0]); + nd.sr_vpsa[1] = sqrt(nd.sr_vpsa[1]); if (!hitfront) { /* perturb normal towards hit */ nd.pnorm[0] = -nd.pnorm[0]; nd.pnorm[1] = -nd.pnorm[1]; @@ -524,7 +554,7 @@ m_bsdf(OBJREC *m, RAY *r) bnorm[0] = -nd.pnorm[0]; bnorm[1] = -nd.pnorm[1]; bnorm[2] = -nd.pnorm[2]; - if (nd.thick != .0) { /* proxy with offset? */ + if (nd.thick != 0) { /* proxy with offset? */ VCOPY(vtmp, r->rop); VSUM(r->rop, vtmp, r->ron, -nd.thick); multambient(ctmp, r, bnorm); @@ -538,7 +568,7 @@ m_bsdf(OBJREC *m, RAY *r) /* add direct component */ if ((bright(nd.tdiff) <= FTINY) & (nd.sd->tf == NULL)) { direct(r, dir_brdf, &nd); /* reflection only */ - } else if (nd.thick == .0) { + } else if (nd.thick == 0) { direct(r, dir_bsdf, &nd); /* thin surface scattering */ } else { direct(r, dir_brdf, &nd); /* reflection first */