static int ambsample( /* initial ambient division sample */ AMBHEMI *hp, int i, int j, int n ) { AMBSAMP *ap = &ambsam(hp,i,j); RAY ar; int hlist[3], ii; double spt[2], zd; /* generate hemispherical sample */ /* ambient coefficient for weight */ if (ambacc > FTINY) setcolor(ar.rcoef, AVGREFL, AVGREFL, AVGREFL); else copycolor(ar.rcoef, hp->acoef); if (rayorigin(&ar, AMBIENT, hp->rp, ar.rcoef) < 0) return(0); if (ambacc > FTINY) { multcolor(ar.rcoef, hp->acoef); scalecolor(ar.rcoef, 1./AVGREFL); } hlist[0] = hp->rp->rno; hlist[1] = j; hlist[2] = i; multisamp(spt, 2, urand(ilhash(hlist,3)+n)); resample: SDsquare2disk(spt, (j+spt[1])/hp->ns, (i+spt[0])/hp->ns); zd = sqrt(1. - spt[0]*spt[0] - spt[1]*spt[1]); for (ii = 3; ii--; ) ar.rdir[ii] = spt[0]*hp->ux[ii] + spt[1]*hp->uy[ii] + zd*hp->rp->ron[ii]; checknorm(ar.rdir); /* avoid coincident samples */ if (!n && ambcollision(hp, i, j, ar.rdir)) { spt[0] = frandom(); spt[1] = frandom(); goto resample; /* reject this sample */ } dimlist[ndims++] = AI(hp,i,j) + 90171; rayvalue(&ar); /* evaluate ray */ ndims--; zd = raydistance(&ar); if (zd <= FTINY) return(0); /* should never happen */ multcolor(ar.rcol, ar.rcoef); /* apply coefficient */ if (zd*ap->d < 1.0) /* new/closer distance? */ ap->d = 1.0/zd; if (!n) { /* record first vertex & value */ if (zd > 10.0*thescene.cusize + 1000.) zd = 10.0*thescene.cusize + 1000.; VSUM(ap->p, ar.rorg, ar.rdir, zd); copycolor(ap->v, ar.rcol); } else { /* else update recorded value */ hp->acol[RED] -= colval(ap->v,RED); hp->acol[GRN] -= colval(ap->v,GRN); hp->acol[BLU] -= colval(ap->v,BLU); zd = 1.0/(double)(n+1); scalecolor(ar.rcol, zd); zd *= (double)n; scalecolor(ap->v, zd); addcolor(ap->v, ar.rcol); } addcolor(hp->acol, ap->v); /* add to our sum */ return(1); }
int m_dielectric( /* color a ray which hit a dielectric interface */ OBJREC *m, RAY *r ) { double cos1, cos2, nratio; COLOR ctrans; COLOR talb; int hastexture; int flatsurface; double refl, trans; FVECT dnorm; double d1, d2; RAY p; int i; /* PMAP: skip refracted shadow or ambient ray if accounted for in photon map */ if (shadowRayInPmap(r) || ambRayInPmap(r)) return(1); if (m->oargs.nfargs != (m->otype==MAT_DIELECTRIC ? 5 : 8)) objerror(m, USER, "bad arguments"); raytexture(r, m->omod); /* get modifiers */ if ( (hastexture = DOT(r->pert,r->pert) > FTINY*FTINY) ) cos1 = raynormal(dnorm, r); /* perturb normal */ else { VCOPY(dnorm, r->ron); cos1 = r->rod; } flatsurface = r->ro != NULL && isflat(r->ro->otype) && !hastexture | (r->crtype & AMBIENT); /* index of refraction */ if (m->otype == MAT_DIELECTRIC) nratio = m->oargs.farg[3] + m->oargs.farg[4]/MLAMBDA; else nratio = m->oargs.farg[3] / m->oargs.farg[7]; if (cos1 < 0.0) { /* inside */ hastexture = -hastexture; cos1 = -cos1; dnorm[0] = -dnorm[0]; dnorm[1] = -dnorm[1]; dnorm[2] = -dnorm[2]; setcolor(r->cext, -mylog(m->oargs.farg[0]*colval(r->pcol,RED)), -mylog(m->oargs.farg[1]*colval(r->pcol,GRN)), -mylog(m->oargs.farg[2]*colval(r->pcol,BLU))); setcolor(r->albedo, 0., 0., 0.); r->gecc = 0.; if (m->otype == MAT_INTERFACE) { setcolor(ctrans, -mylog(m->oargs.farg[4]*colval(r->pcol,RED)), -mylog(m->oargs.farg[5]*colval(r->pcol,GRN)), -mylog(m->oargs.farg[6]*colval(r->pcol,BLU))); setcolor(talb, 0., 0., 0.); } else { copycolor(ctrans, cextinction); copycolor(talb, salbedo); } } else { /* outside */ nratio = 1.0 / nratio; setcolor(ctrans, -mylog(m->oargs.farg[0]*colval(r->pcol,RED)), -mylog(m->oargs.farg[1]*colval(r->pcol,GRN)), -mylog(m->oargs.farg[2]*colval(r->pcol,BLU))); setcolor(talb, 0., 0., 0.); if (m->otype == MAT_INTERFACE) { setcolor(r->cext, -mylog(m->oargs.farg[4]*colval(r->pcol,RED)), -mylog(m->oargs.farg[5]*colval(r->pcol,GRN)), -mylog(m->oargs.farg[6]*colval(r->pcol,BLU))); setcolor(r->albedo, 0., 0., 0.); r->gecc = 0.; } } d2 = 1.0 - nratio*nratio*(1.0 - cos1*cos1); /* compute cos theta2 */ if (d2 < FTINY) /* total reflection */ refl = 1.0; else { /* refraction occurs */ /* compute Fresnel's equations */ cos2 = sqrt(d2); d1 = cos1; d2 = nratio*cos2; d1 = (d1 - d2) / (d1 + d2); refl = d1 * d1; d1 = 1.0 / cos1; d2 = nratio / cos2; d1 = (d1 - d2) / (d1 + d2); refl += d1 * d1; refl *= 0.5; trans = 1.0 - refl; trans *= nratio*nratio; /* solid angle ratio */ setcolor(p.rcoef, trans, trans, trans); if (rayorigin(&p, REFRACTED, r, p.rcoef) == 0) { /* compute refracted ray */ d1 = nratio*cos1 - cos2; for (i = 0; i < 3; i++) p.rdir[i] = nratio*r->rdir[i] + d1*dnorm[i]; /* accidental reflection? */ if (hastexture && DOT(p.rdir,r->ron)*hastexture >= -FTINY) { d1 *= (double)hastexture; for (i = 0; i < 3; i++) /* ignore texture */ p.rdir[i] = nratio*r->rdir[i] + d1*r->ron[i]; normalize(p.rdir); /* not exact */ } else checknorm(p.rdir); #ifdef DISPERSE if (m->otype != MAT_DIELECTRIC || r->rod > 0.0 || r->crtype & SHADOW || !directvis || m->oargs.farg[4] == 0.0 || !disperse(m, r, p.rdir, trans, ctrans, talb)) #endif { copycolor(p.cext, ctrans); copycolor(p.albedo, talb); rayvalue(&p); multcolor(p.rcol, p.rcoef); addcolor(r->rcol, p.rcol); /* virtual distance */ if (flatsurface || (1.-FTINY <= nratio) & (nratio <= 1.+FTINY)) r->rxt = r->rot + raydistance(&p); } } } setcolor(p.rcoef, refl, refl, refl); if (!(r->crtype & SHADOW) && rayorigin(&p, REFLECTED, r, p.rcoef) == 0) { /* compute reflected ray */ VSUM(p.rdir, r->rdir, dnorm, 2.*cos1); /* accidental penetration? */ if (hastexture && DOT(p.rdir,r->ron)*hastexture <= FTINY) VSUM(p.rdir, r->rdir, r->ron, 2.*r->rod); checknorm(p.rdir); rayvalue(&p); /* reflected ray value */ multcolor(p.rcol, p.rcoef); /* color contribution */ copycolor(r->mcol, p.rcol); addcolor(r->rcol, p.rcol); /* virtual distance */ r->rmt = r->rot; if (flatsurface) r->rmt += raydistance(&p); } /* rayvalue() computes absorption */ return(1); }
static void ashiksamp( /* sample anisotropic Ashikhmin-Shirley specular */ ASHIKDAT *np ) { RAY sr; FVECT h; double rv[2], dtmp; double cosph, sinph, costh, sinth; int maxiter, ntrials, nstarget, nstaken; int i; if (np->specfl & SPA_BADU || rayorigin(&sr, SPECULAR, np->rp, np->scolor) < 0) return; 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) { dtmp = 1./nstarget; scalecolor(sr.rcoef, dtmp); sr.rweight *= dtmp; } else nstarget = 1; } dimlist[ndims++] = (int)(size_t)np->mp; maxiter = MAXITER*nstarget; for (nstaken = ntrials = 0; nstaken < nstarget && ntrials < maxiter; ntrials++) { if (ntrials) dtmp = frandom(); else dtmp = urand(ilhash(dimlist,ndims)+647+samplendx); multisamp(rv, 2, dtmp); dtmp = 2.*PI * rv[0]; cosph = sqrt(np->v_power + 1.) * tcos(dtmp); sinph = sqrt(np->u_power + 1.) * tsin(dtmp); dtmp = 1./sqrt(cosph*cosph + sinph*sinph); cosph *= dtmp; sinph *= dtmp; costh = pow(rv[1], 1./(np->u_power*cosph*cosph+np->v_power*sinph*sinph+1.)); if (costh <= FTINY) continue; sinth = sqrt(1. - costh*costh); for (i = 0; i < 3; i++) h[i] = cosph*sinth*np->u[i] + sinph*sinth*np->v[i] + costh*np->pnorm[i]; if (nstaken) rayclear(&sr); dtmp = -2.*DOT(h, np->rp->rdir); VSUM(sr.rdir, np->rp->rdir, h, dtmp); /* sample rejection test */ if (DOT(sr.rdir, np->rp->ron) <= FTINY) continue; checknorm(sr.rdir); rayvalue(&sr); multcolor(sr.rcol, sr.rcoef); addcolor(np->rp->rcol, sr.rcol); ++nstaken; } ndims--; }
int m_brdf( /* color a ray that hit a BRDTfunc material */ OBJREC *m, RAY *r ) { int hitfront = 1; BRDFDAT nd; RAY sr; double mirtest=0, mirdist=0; double transtest=0, transdist=0; int hasrefl, hastrans; int hastexture; COLOR ctmp; FVECT vtmp; double d; MFUNC *mf; int i; /* check arguments */ if ((m->oargs.nsargs < 10) | (m->oargs.nfargs < 9)) objerror(m, USER, "bad # arguments"); nd.mp = m; nd.pr = r; /* dummy values */ nd.rspec = nd.tspec = 1.0; nd.trans = 0.5; /* diffuse reflectance */ if (r->rod > 0.0) setcolor(nd.rdiff, m->oargs.farg[0], m->oargs.farg[1], m->oargs.farg[2]); else setcolor(nd.rdiff, m->oargs.farg[3], m->oargs.farg[4], m->oargs.farg[5]); /* diffuse transmittance */ setcolor(nd.tdiff, m->oargs.farg[6], m->oargs.farg[7], m->oargs.farg[8]); /* get modifiers */ raytexture(r, m->omod); hastexture = DOT(r->pert,r->pert) > FTINY*FTINY; if (hastexture) { /* perturb normal */ nd.pdot = raynormal(nd.pnorm, r); } else { VCOPY(nd.pnorm, r->ron); nd.pdot = r->rod; } if (r->rod < 0.0) { /* orient perturbed values */ nd.pdot = -nd.pdot; for (i = 0; i < 3; i++) { nd.pnorm[i] = -nd.pnorm[i]; r->pert[i] = -r->pert[i]; } hitfront = 0; } copycolor(nd.mcolor, r->pcol); /* get pattern color */ multcolor(nd.rdiff, nd.mcolor); /* modify diffuse values */ multcolor(nd.tdiff, nd.mcolor); hasrefl = bright(nd.rdiff) > FTINY; hastrans = bright(nd.tdiff) > FTINY; /* load cal file */ nd.dp = NULL; mf = getfunc(m, 9, 0x3f, 0); /* compute transmitted ray */ setbrdfunc(&nd); errno = 0; setcolor(ctmp, evalue(mf->ep[3]), evalue(mf->ep[4]), evalue(mf->ep[5])); if ((errno == EDOM) | (errno == ERANGE)) objerror(m, WARNING, "compute error"); else if (rayorigin(&sr, TRANS, r, ctmp) == 0) { if (!(r->crtype & SHADOW) && hastexture) { /* perturb direction */ VSUM(sr.rdir, r->rdir, r->pert, -.75); if (normalize(sr.rdir) == 0.0) { objerror(m, WARNING, "illegal perturbation"); VCOPY(sr.rdir, r->rdir); } } else { VCOPY(sr.rdir, r->rdir); } rayvalue(&sr); multcolor(sr.rcol, sr.rcoef); addcolor(r->rcol, sr.rcol); if (!hastexture) { transtest = 2.0*bright(sr.rcol); transdist = r->rot + sr.rt; } } if (r->crtype & SHADOW) /* the rest is shadow */ return(1); /* compute reflected ray */ setbrdfunc(&nd); errno = 0; setcolor(ctmp, evalue(mf->ep[0]), evalue(mf->ep[1]), evalue(mf->ep[2])); if ((errno == EDOM) | (errno == ERANGE)) objerror(m, WARNING, "compute error"); else if (rayorigin(&sr, REFLECTED, r, ctmp) == 0) { VSUM(sr.rdir, r->rdir, nd.pnorm, 2.*nd.pdot); checknorm(sr.rdir); rayvalue(&sr); multcolor(sr.rcol, sr.rcoef); addcolor(r->rcol, sr.rcol); if (!hastexture && r->ro != NULL && isflat(r->ro->otype)) { mirtest = 2.0*bright(sr.rcol); mirdist = r->rot + sr.rt; } } /* compute ambient */ if (hasrefl) { if (!hitfront) flipsurface(r); copycolor(ctmp, nd.rdiff); multambient(ctmp, r, nd.pnorm); addcolor(r->rcol, ctmp); /* add to returned color */ if (!hitfront) flipsurface(r); } if (hastrans) { /* from other side */ if (hitfront) flipsurface(r); vtmp[0] = -nd.pnorm[0]; vtmp[1] = -nd.pnorm[1]; vtmp[2] = -nd.pnorm[2]; copycolor(ctmp, nd.tdiff); multambient(ctmp, r, vtmp); addcolor(r->rcol, ctmp); if (hitfront) flipsurface(r); } if (hasrefl | hastrans || m->oargs.sarg[6][0] != '0') direct(r, dirbrdf, &nd); /* add direct component */ d = bright(r->rcol); /* set effective distance */ if (transtest > d) r->rt = transdist; else if (mirtest > d) r->rt = mirdist; return(1); }
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--; } }