--- ray/src/rt/m_bsdf.c 2011/06/08 15:37:46 2.11 +++ ray/src/rt/m_bsdf.c 2013/04/09 16:55:15 2.23 @@ -1,5 +1,5 @@ #ifndef lint -static const char RCSid[] = "$Id: m_bsdf.c,v 2.11 2011/06/08 15:37:46 greg Exp $"; +static const char RCSid[] = "$Id: m_bsdf.c,v 2.23 2013/04/09 16:55:15 greg Exp $"; #endif /* * Shading for materials with BSDFs taken from XML data files @@ -68,7 +68,6 @@ typedef struct { FVECT pnorm; /* perturbed surface normal */ FVECT vray; /* local outgoing (return) vector */ double sr_vpsa[2]; /* sqrt of BSDF projected solid angle extrema */ - double thru_psa; /* through direction projected solid angle */ RREAL toloc[3][3]; /* world to local BSDF coords */ RREAL fromloc[3][3]; /* local BSDF coords to world */ double thick; /* surface thickness */ @@ -83,10 +82,8 @@ typedef struct { /* Jitter ray sample according to projected solid angle and specjitter */ static void -bsdf_jitter(FVECT vres, BSDFDAT *ndp, int domax) +bsdf_jitter(FVECT vres, BSDFDAT *ndp, double sr_psa) { - double sr_psa = ndp->sr_vpsa[domax]; - VCOPY(vres, ndp->vray); if (specjitter < 1.) sr_psa *= specjitter; @@ -99,33 +96,68 @@ bsdf_jitter(FVECT vres, BSDFDAT *ndp, int domax) /* 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, 0); - /* 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->thru_psa) + /* assign number of samples */ + ec = SDsizeBSDF(&tomega, ndp->vray, vsrc, SDqueryMin, ndp->sd); + if (ec) + goto baderror; + /* 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+tomega) return(0); } - ec = SDevalBSDF(&sv, vjit, vsrc, 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); + 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)); + return(0); /* gratis return */ } /* Compute source contribution for BSDF (reflected & transmitted) */ @@ -169,7 +201,7 @@ 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 */ COLOR ctmp1, ctmp2; @@ -224,7 +256,7 @@ 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 @@ -273,7 +305,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); @@ -296,17 +328,19 @@ sample_sdcomp(BSDFDAT *ndp, SDComponent *dcp, int usep /* multiple samples? */ if (specjitter > 1.5) { nstarget = specjitter*ndp->pr->rweight + .5; - if (nstarget < 1) - nstarget = 1; + nstarget += !nstarget; } /* run through our samples */ for (nsent = 0; nsent < nstarget; nsent++) { - if (nstarget == 1) /* stratify random variable */ + if (nstarget == 1) { /* stratify random variable */ xrand = urand(ilhash(dimlist,ndims)+samplendx); - else + if (specjitter < 1.) + xrand = .5 + specjitter*(xrand-.5); + } else { xrand = (nsent + frandom())/(double)nstarget; + } SDerrorDetail[0] = '\0'; /* sample direction & coef. */ - bsdf_jitter(vsmp, ndp, 0); + bsdf_jitter(vsmp, ndp, ndp->sr_vpsa[0]); ec = SDsampComponent(&bsv, vsmp, xrand, dcp); if (ec) objerror(ndp->mp, USER, transSDError(ec)); @@ -346,7 +380,10 @@ sample_sdf(BSDFDAT *ndp, int sflags) if (sflags == SDsampSpT) { unsc = ndp->tunsamp; - dfp = ndp->sd->tf; + if (ndp->pr->rod > 0) + dfp = (ndp->sd->tf != NULL) ? ndp->sd->tf : ndp->sd->tb; + else + dfp = (ndp->sd->tb != NULL) ? ndp->sd->tb : ndp->sd->tf; cvt_sdcolor(unsc, &ndp->sd->tLamb); } else /* sflags == SDsampSpR */ { unsc = ndp->runsamp; @@ -367,7 +404,7 @@ sample_sdf(BSDFDAT *ndp, int sflags) FVECT vjit; double d; COLOR ctmp; - bsdf_jitter(vjit, ndp, 1); + bsdf_jitter(vjit, ndp, ndp->sr_vpsa[1]); d = SDdirectHemi(vjit, sflags, ndp->sd); if (sflags == SDsampSpT) { copycolor(ctmp, ndp->pr->pcol); @@ -436,7 +473,7 @@ m_bsdf(OBJREC *m, RAY *r) } else { if (m->oargs.nfargs < 6) { /* check invisible backside */ if (!backvis && (nd.sd->rb == NULL) & - (nd.sd->tf == NULL)) { + (nd.sd->tb == NULL)) { SDfreeCache(nd.sd); raytrans(r); return(1); @@ -466,10 +503,14 @@ m_bsdf(OBJREC *m, RAY *r) upvec[1] = evalue(mf->ep[2]); upvec[2] = evalue(mf->ep[3]); /* return to world coords */ - if (mf->f != &unitxf) { - multv3(upvec, upvec, mf->f->xfm); - nd.thick *= mf->f->sca; + if (mf->fxp != &unitxf) { + multv3(upvec, upvec, mf->fxp->xfm); + nd.thick *= mf->fxp->sca; } + if (r->rox != NULL) { + multv3(upvec, upvec, r->rox->f.xfm); + nd.thick *= r->rox->f.sca; + } raynormal(nd.pnorm, r); /* compute local BSDF xform */ ec = SDcompXform(nd.toloc, nd.pnorm, upvec); @@ -481,24 +522,15 @@ m_bsdf(OBJREC *m, RAY *r) } if (!ec) ec = SDinvXform(nd.fromloc, nd.toloc); - /* determine BSDF resolution */ - if (!ec) - ec = SDsizeBSDF(nd.sr_vpsa, nd.vray, NULL, - SDqueryMin+SDqueryMax, nd.sd); - nd.thru_psa = .0; - if (!ec && nd.thick != 0 && r->crtype & (SPECULAR|AMBIENT)) { - FVECT vthru; - vthru[0] = -nd.vray[0]; - vthru[1] = -nd.vray[1]; - vthru[2] = -nd.vray[2]; - ec = SDsizeBSDF(&nd.thru_psa, nd.vray, vthru, - SDqueryMin, nd.sd); - } if (ec) { - objerror(m, WARNING, transSDError(ec)); - SDfreeCache(nd.sd); + objerror(m, WARNING, "Illegal orientation vector"); return(1); } + /* determine BSDF resolution */ + ec = SDsizeBSDF(nd.sr_vpsa, nd.vray, NULL, SDqueryMin+SDqueryMax, nd.sd); + if (ec) + objerror(m, USER, transSDError(ec)); + nd.sr_vpsa[0] = sqrt(nd.sr_vpsa[0]); nd.sr_vpsa[1] = sqrt(nd.sr_vpsa[1]); if (!hitfront) { /* perturb normal towards hit */ @@ -532,7 +564,7 @@ m_bsdf(OBJREC *m, RAY *r) bnorm[2] = -nd.pnorm[2]; if (nd.thick != 0) { /* proxy with offset? */ VCOPY(vtmp, r->rop); - VSUM(r->rop, vtmp, r->ron, -nd.thick); + VSUM(r->rop, vtmp, r->ron, nd.thick); multambient(ctmp, r, bnorm); VCOPY(r->rop, vtmp); } else @@ -542,7 +574,8 @@ m_bsdf(OBJREC *m, RAY *r) flipsurface(r); } /* add direct component */ - if ((bright(nd.tdiff) <= FTINY) & (nd.sd->tf == NULL)) { + if ((bright(nd.tdiff) <= FTINY) & (nd.sd->tf == NULL) & + (nd.sd->tb == NULL)) { direct(r, dir_brdf, &nd); /* reflection only */ } else if (nd.thick == 0) { direct(r, dir_bsdf, &nd); /* thin surface scattering */