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); }
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); }
int m_ashikhmin( /* shade ray that hit something anisotropic */ OBJREC *m, RAY *r ) { ASHIKDAT nd; COLOR ctmp; double fres; int i; /* easy shadow test */ if (r->crtype & SHADOW) return(1); if (m->oargs.nfargs != 8) 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]); setcolor(nd.scolor, m->oargs.farg[3], m->oargs.farg[4], m->oargs.farg[5]); /* get specular power */ nd.specfl = 0; nd.u_power = m->oargs.farg[6]; nd.v_power = m->oargs.farg[7]; nd.pdot = raynormal(nd.pnorm, r); /* perturb normal */ if (nd.pdot < .001) nd.pdot = .001; /* non-zero for dirashik() */ multcolor(nd.mcolor, r->pcol); /* modify diffuse color */ if (bright(nd.scolor) > FTINY) { /* adjust specular color */ nd.specfl |= SPA_REFL; /* check threshold */ if (specthresh >= bright(nd.scolor)-FTINY) nd.specfl |= SPA_RBLT; fres = schlick_fres(nd.pdot); /* Schick's Fresnel approx */ for (i = 0; i < 3; i++) colval(nd.scolor,i) += (1.-colval(nd.scolor,i))*fres; } if (r->ro != NULL && isflat(r->ro->otype)) nd.specfl |= SPA_FLAT; /* set up coordinates */ getacoords_as(&nd); /* specular sampling? */ if ((nd.specfl & (SPA_REFL|SPA_RBLT)) == SPA_REFL) ashiksamp(&nd); /* diffuse interreflection */ if (bright(nd.mcolor) > FTINY) { copycolor(ctmp, nd.mcolor); /* modified by material color */ if (nd.specfl & SPA_RBLT) /* add in specular as well? */ addcolor(ctmp, nd.scolor); multambient(ctmp, r, nd.pnorm); addcolor(r->rcol, ctmp); /* add to returned color */ } direct(r, dirashik, &nd); /* add direct component */ return(1); }
static int redirect( /* compute n'th ray redirection */ OBJREC *m, RAY *r, int n ) { MFUNC *mf; EPNODE **va; FVECT nsdir; RAY nr; double coef; int j; /* set up function */ mf = getdfunc(m); setfunc(m, r); /* assign direction variable */ if (r->rsrc >= 0) { SRCREC *sp = source + source[r->rsrc].sa.sv.sn; if (sp->sflags & SDISTANT) VCOPY(nsdir, sp->sloc); else { for (j = 0; j < 3; j++) nsdir[j] = sp->sloc[j] - r->rop[j]; normalize(nsdir); } multv3(nsdir, nsdir, funcxf.xfm); varset("DxA", '=', nsdir[0]/funcxf.sca); varset("DyA", '=', nsdir[1]/funcxf.sca); varset("DzA", '=', nsdir[2]/funcxf.sca); } else { varset("DxA", '=', 0.0); varset("DyA", '=', 0.0); varset("DzA", '=', 0.0); } /* compute coefficient */ errno = 0; va = mf->ep + 4*n; coef = evalue(va[0]); if ((errno == EDOM) | (errno == ERANGE)) goto computerr; setcolor(nr.rcoef, coef, coef, coef); if (rayorigin(&nr, TRANS, r, nr.rcoef) < 0) return(0); va++; /* compute direction */ for (j = 0; j < 3; j++) { nr.rdir[j] = evalue(va[j]); if (errno == EDOM || errno == ERANGE) goto computerr; } if (mf->fxp != &unitxf) multv3(nr.rdir, nr.rdir, mf->fxp->xfm); if (r->rox != NULL) multv3(nr.rdir, nr.rdir, r->rox->f.xfm); if (normalize(nr.rdir) == 0.0) goto computerr; /* compute value */ if (r->rsrc >= 0) nr.rsrc = source[r->rsrc].sa.sv.sn; rayvalue(&nr); multcolor(nr.rcol, nr.rcoef); addcolor(r->rcol, nr.rcol); if (r->ro != NULL && isflat(r->ro->otype)) r->rt = r->rot + nr.rt; return(1); computerr: objerror(m, WARNING, "compute error"); return(-1); }
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); }