static int /* cast source ray to first blocker */ castshadow(int sn, FVECT rorg, FVECT rdir) { RAY rt; VCOPY(rt.rorg, rorg); VCOPY(rt.rdir, rdir); rt.rmax = 0; rayorigin(&rt, PRIMARY, NULL, NULL); /* check for intersection */ while (localhit(&rt, &thescene)) { RAY rt1 = rt; /* pretend we were aimed at source */ rt1.crtype |= rt1.rtype = SHADOW; rt1.rdir[0] = -rt.rdir[0]; rt1.rdir[1] = -rt.rdir[1]; rt1.rdir[2] = -rt.rdir[2]; rt1.rod = -rt.rod; VSUB(rt1.rorg, rt.rop, rt.rdir); rt1.rot = 1.; rt1.rsrc = sn; /* record blocker */ if (srcblocker(&rt1)) return(1); /* move past failed blocker */ VSUM(rt.rorg, rt.rop, rt.rdir, FTINY); rayclear(&rt); /* & try again... */ } return(0); /* found no blockers */ }
/* Find convex hull vertex to complete triangle (oriented call) */ static RBFNODE * find_chull_vert(const RBFNODE *rbf0, const RBFNODE *rbf1) { FVECT vmid, vejn, vp; RBFNODE *rbf, *rbfbest = NULL; double dprod, area2, bestarea2 = FHUGE, bestdprod = -.5; VSUB(vejn, rbf1->invec, rbf0->invec); VADD(vmid, rbf0->invec, rbf1->invec); if (normalize(vejn) == 0 || normalize(vmid) == 0) return(NULL); /* XXX exhaustive search */ /* Find triangle with minimum rotation from perpendicular */ for (rbf = dsf_list; rbf != NULL; rbf = rbf->next) { if ((rbf == rbf0) | (rbf == rbf1)) continue; tri_orient(vp, rbf0->invec, rbf1->invec, rbf->invec); if (DOT(vp, vmid) <= FTINY) continue; /* wrong orientation */ area2 = .25*DOT(vp,vp); VSUB(vp, rbf->invec, vmid); dprod = -DOT(vp, vejn); VSUM(vp, vp, vejn, dprod); /* above guarantees non-zero */ dprod = DOT(vp, vmid) / VLEN(vp); if (dprod <= bestdprod + FTINY*(1 - 2*(area2 < bestarea2))) continue; /* found better already */ if (overlaps_tri(rbf0, rbf1, rbf)) continue; /* overlaps another triangle */ rbfbest = rbf; bestdprod = dprod; /* new one to beat */ bestarea2 = area2; } return(rbfbest); }
static void disp_bundle( /* display a ray bundle */ register PACKHEAD *p ) { GCOORD gc[2]; FVECT ro, rd, wp; double d; register int i; /* get beam coordinates */ if ((p->hd < 0) | (p->hd >= HDMAX) || hdlist[p->hd] == NULL) error(INTERNAL, "bad holodeck number in disp_bundle"); if (!hdbcoord(gc, hdlist[p->hd], p->bi)) error(INTERNAL, "bad beam index in disp_bundle"); /* display each ray */ for (i = p->nr; i--; ) { hdray(ro, rd, hdlist[p->hd], gc, packra(p)[i].r); d = hddepth(hdlist[p->hd], packra(p)[i].d); if (d < .99*FHUGE) { VSUM(wp, ro, rd, d); /* might be behind viewpoint */ dev_value(packra(p)[i].v, rd, wp); } else dev_value(packra(p)[i].v, rd, NULL); } #ifdef DEBUG if (imm_mode) nimmrays += p->nr; else naddrays += p->nr; #endif }
static int addclump( /* transfer the given clump and free */ HOLO *hp, int *bq, int nb ) { GCOORD gc[2]; FVECT ro, rd; double d; int i; register int k; register BEAM *bp; /* sort based on file position */ beamdir = hp->bi; qsort((char *)bq, nb, sizeof(*bq), bpcmp); /* transfer each beam */ for (i = 0; i < nb; i++) { bp = hdgetbeam(hp, bq[i]); hdbcoord(gc, hp, bq[i]); /* add each ray to output */ for (k = bp->nrm; k--; ) { d = hdray(ro, rd, hp, gc, hdbray(bp)[k].r); if (hp->priv == &unobstr) VSUM(ro, ro, rd, d); else d = 0.; d = hddepth(hp, hdbray(bp)[k].d) - d; addray(ro, rd, d, hdbray(bp)[k].v); } hdfreebeam(hp, bq[i]); /* free the beam */ } return(0); }
int t_func( /* compute texture for ray */ OBJREC *m, RAY *r ) { FVECT disp; double d; MFUNC *mf; int i; if (m->oargs.nsargs < 4) objerror(m, USER, "bad # arguments"); mf = getfunc(m, 3, 0x7, 1); setfunc(m, r); errno = 0; for (i = 0; i < 3; i++) { disp[i] = evalue(mf->ep[i]); if (errno == EDOM || errno == ERANGE) { objerror(m, WARNING, "compute error"); return(0); } } if (mf->fxp != &unitxf) multv3(disp, disp, mf->fxp->xfm); if (r->rox != NULL) { multv3(disp, disp, r->rox->f.xfm); d = 1.0 / (mf->fxp->sca * r->rox->f.sca); } else d = 1.0 / mf->fxp->sca; VSUM(r->pert, r->pert, disp, d); return(0); }
void getorigin( /* origin viewpoint */ char *s ) { VIEW nv = ourview; double d; /* get new view origin */ if (sscanf(s, "%lf %lf", &d, &d) == 1) { /* just moving some distance */ VSUM(nv.vp, nv.vp, nv.vdir, d); } else if (!sscanvec(s, nv.vp)) { int x, y; /* need to pick origin */ RAY thisray; if (dev->getcur == NULL) return; (*dev->comout)("Pick point on surface for new origin\n"); if ((*dev->getcur)(&x, &y) == ABORT) return; if ((thisray.rmax = viewray(thisray.rorg, thisray.rdir, &ourview, (x+.5)/hresolu, (y+.5)/vresolu)) < -FTINY) { error(COMMAND, "not on image"); return; } rayorigin(&thisray, PRIMARY, NULL, NULL); if (!localhit(&thisray, &thescene)) { error(COMMAND, "not a local object"); return; } if (thisray.rod < 0.0) /* don't look through other side */ flipsurface(&thisray); VSUM(nv.vp, thisray.rop, thisray.ron, 20.0*FTINY); VCOPY(nv.vdir, thisray.ron); } else if (!sscanvec(sskip2(s,3), nv.vdir) || normalize(nv.vdir) == 0.0) VCOPY(nv.vdir, ourview.vdir); d = DOT(nv.vdir, nv.vup); /* need different up vector? */ if (d*d >= 1.-2.*FTINY) { int i; nv.vup[0] = nv.vup[1] = nv.vup[2] = 0.0; for (i = 3; i--; ) if (nv.vdir[i]*nv.vdir[i] < 0.34) break; nv.vup[i] = 1.; } newview(&nv); }
static void add_holo( /* register a new holodeck section */ HDGRID *hdg, char *gfn, char *pfn ) { VIEW nv; double d; register int hd; for (hd = 0; hd < HDMAX && hdlist[hd] != NULL; hd++) ; if (hd >= HDMAX) error(INTERNAL, "too many holodeck sections in add_holo"); hdlist[hd] = (HOLO *)malloc(sizeof(HOLO)); if (hdlist[hd] == NULL) error(SYSTEM, "out of memory in add_holo"); memcpy((void *)hdlist[hd], (void *)hdg, sizeof(HDGRID)); hdcompgrid(hdlist[hd]); hdgfn[hd] = savestr(gfn); hdpfn[hd] = pfn && *pfn ? savestr(pfn) : (char *)NULL; if (hd) return; /* set initial viewpoint */ nv = odev.v; VSUM(nv.vp, hdlist[0]->orig, hdlist[0]->xv[0], 0.5); VSUM(nv.vp, nv.vp, hdlist[0]->xv[1], 0.5); VSUM(nv.vp, nv.vp, hdlist[0]->xv[2], 0.5); fcross(nv.vdir, hdlist[0]->xv[1], hdlist[0]->xv[2]); VCOPY(nv.vup, hdlist[0]->xv[2]); if (do_outside) { normalize(nv.vdir); d = VLEN(hdlist[0]->xv[1]); d += VLEN(hdlist[0]->xv[2]); VSUM(nv.vp, nv.vp, nv.vdir, -d); } new_view(&nv); }
extern int o_face( /* compute intersection with polygonal face */ OBJREC *o, register RAY *r ) { double rdot; /* direction . normal */ double t; /* distance to intersection */ FVECT pisect; /* intersection point */ register FACE *f; /* face record */ f = getface(o); /* * First, we find the distance to the plane containing the * face. If this distance is less than zero or greater * than a previous intersection, we return. Otherwise, * we determine whether in fact the ray intersects the * face. The ray intersects the face if the * point of intersection with the plane of the face * is inside the face. */ /* compute dist. to plane */ rdot = -DOT(r->rdir, f->norm); if (rdot <= FTINY && rdot >= -FTINY) /* ray parallels plane */ t = FHUGE; else t = (DOT(r->rorg, f->norm) - f->offset) / rdot; if (t <= FTINY || t >= r->rot) /* not good enough */ return(0); /* compute intersection */ VSUM(pisect, r->rorg, r->rdir, t); if (!inface(pisect, f)) /* ray intersects face? */ return(0); r->ro = o; r->rot = t; VCOPY(r->rop, pisect); VCOPY(r->ron, f->norm); r->rod = rdot; r->pert[0] = r->pert[1] = r->pert[2] = 0.0; r->uv[0] = r->uv[1] = 0.0; r->rox = NULL; return(1); /* hit */ }
static int moveview( /* move our view */ int dx, int dy, int mov, int orb ) { VIEW nv; FVECT odir, v1; double d; int li; /* start with old view */ nv = odev.v; /* change view direction */ if (mov | orb) { if ((li = qtFindLeaf(dx, dy)) < 0) return(0); /* not on window */ VSUM(odir, qtL.wp[li], nv.vp, -1.); } else { if (viewray(nv.vp, nv.vdir, &odev.v, (dx+.5)/odev.hres, (dy+.5)/odev.vres) < -FTINY) return(0); /* outside view */ } if (orb && mov) { /* orbit left/right */ spinvector(odir, odir, nv.vup, d=MOVDEG*PI/180.*mov); VSUM(nv.vp, qtL.wp[li], odir, -1.); spinvector(nv.vdir, nv.vdir, nv.vup, d); } else if (orb) { /* orbit up/down */ if (geodesic(odir, odir, nv.vup, d=MOVDEG*PI/180.*orb, GEOD_RAD) == 0.0) return(0); VSUM(nv.vp, qtL.wp[li], odir, -1.); geodesic(nv.vdir, nv.vdir, nv.vup, d, GEOD_RAD); } else if (mov) { /* move forward/backward */ d = MOVPCT/100. * mov; VSUM(nv.vp, nv.vp, odir, d); } if (!mov ^ !orb && headlocked) { /* restore head height */ VSUM(v1, odev.v.vp, nv.vp, -1.); d = DOT(v1, odev.v.vup); VSUM(nv.vp, nv.vp, odev.v.vup, d); } if (setview(&nv) != NULL) return(0); /* illegal view */ dev_view(&nv); inpresflags |= DFL(DC_SETVIEW); return(1); }
static int moveview( /* move our view */ int dx, int dy, int mov, int orb ) { VIEW nv; FVECT odir, v1, wp; double d; /* start with old view */ nv = thisview; /* change view direction */ if ((d = viewray(v1, odir, &thisview, (dx+.5)/hres, (dy+.5)/vres)) < -FTINY) return(0); /* outside view */ if (mov | orb) { if (!getintersect(wp, v1, odir, d)) return(0); VSUM(odir, wp, nv.vp, -1.); } else VCOPY(nv.vdir, odir); if (orb && mov) { /* orbit left/right */ spinvector(odir, odir, nv.vup, d=MOVDEG*PI/180.*mov); VSUM(nv.vp, wp, odir, -1.); spinvector(nv.vdir, nv.vdir, nv.vup, d); } else if (orb) { /* orbit up/down */ if (geodesic(odir, odir, nv.vup, d=MOVDEG*PI/180.*orb, GEOD_RAD) == 0.0) return(0); VSUM(nv.vp, wp, odir, -1.); geodesic(nv.vdir, nv.vdir, nv.vup, d, GEOD_RAD); } else if (mov) { /* move forward/backward */ d = MOVPCT/100. * mov; VSUM(nv.vp, nv.vp, odir, d); } if (!mov ^ !orb && headlocked) { /* restore head height */ VSUM(v1, thisview.vp, nv.vp, -1.); d = DOT(v1, thisview.vup); VSUM(nv.vp, nv.vp, thisview.vup, d); } if (setview(&nv) != NULL) return(0); /* illegal view */ dev_view(&nv); return(1); }
static int disperse( /* check light sources for dispersion */ OBJREC *m, RAY *r, FVECT vt, double tr, COLOR cet, COLOR abt ) { RAY sray; const RAY *entray; FVECT v1, v2, n1, n2; FVECT dv, v2Xdv; double v2Xdvv2Xdv; int success = 0; SRCINDEX si; FVECT vtmp1, vtmp2; double dtmp1, dtmp2; int l1, l2; COLOR ctmp; int i; /* * This routine computes dispersion to the first order using * the following assumptions: * * 1) The dependency of the index of refraction on wavelength * is approximated by Hartmann's equation with lambda0 * equal to zero. * 2) The entry and exit locations are constant with respect * to dispersion. * * The second assumption permits us to model dispersion without * having to sample refracted directions. We assume that the * geometry inside the material is constant, and concern ourselves * only with the relationship between the entering and exiting ray. * We compute the first derivatives of the entering and exiting * refraction with respect to the index of refraction. This * is then used in a first order Taylor series to determine the * index of refraction necessary to send the exiting ray to each * light source. * If an exiting ray hits a light source within the refraction * boundaries, we sum all the frequencies over the disc of the * light source to determine the resulting color. A smaller light * source will therefore exhibit a sharper spectrum. */ if (!(r->crtype & REFRACTED)) { /* ray started in material */ VCOPY(v1, r->rdir); n1[0] = -r->rdir[0]; n1[1] = -r->rdir[1]; n1[2] = -r->rdir[2]; } else { /* find entry point */ for (entray = r; entray->rtype != REFRACTED; entray = entray->parent) ; entray = entray->parent; if (entray->crtype & REFRACTED) /* too difficult */ return(0); VCOPY(v1, entray->rdir); VCOPY(n1, entray->ron); } VCOPY(v2, vt); /* exiting ray */ VCOPY(n2, r->ron); /* first order dispersion approx. */ dtmp1 = 1./DOT(n1, v1); dtmp2 = 1./DOT(n2, v2); for (i = 0; i < 3; i++) dv[i] = v1[i] + v2[i] - n1[i]*dtmp1 - n2[i]*dtmp2; if (DOT(dv, dv) <= FTINY) /* null effect */ return(0); /* compute plane normal */ fcross(v2Xdv, v2, dv); v2Xdvv2Xdv = DOT(v2Xdv, v2Xdv); /* check sources */ initsrcindex(&si); while (srcray(&sray, r, &si)) { if (DOT(sray.rdir, v2) < MINCOS) continue; /* bad source */ /* adjust source ray */ dtmp1 = DOT(v2Xdv, sray.rdir) / v2Xdvv2Xdv; sray.rdir[0] -= dtmp1 * v2Xdv[0]; sray.rdir[1] -= dtmp1 * v2Xdv[1]; sray.rdir[2] -= dtmp1 * v2Xdv[2]; l1 = lambda(m, v2, dv, sray.rdir); /* mean lambda */ if (l1 > MAXLAMBDA || l1 < MINLAMBDA) /* not visible */ continue; /* trace source ray */ copycolor(sray.cext, cet); copycolor(sray.albedo, abt); normalize(sray.rdir); rayvalue(&sray); if (bright(sray.rcol) <= FTINY) /* missed it */ continue; /* * Compute spectral sum over diameter of source. * First find directions for rays going to opposite * sides of source, then compute wavelengths for each. */ fcross(vtmp1, v2Xdv, sray.rdir); dtmp1 = sqrt(si.dom / v2Xdvv2Xdv / PI); /* compute first ray */ VSUM(vtmp2, sray.rdir, vtmp1, dtmp1); l1 = lambda(m, v2, dv, vtmp2); /* first lambda */ if (l1 < 0) continue; /* compute second ray */ VSUM(vtmp2, sray.rdir, vtmp1, -dtmp1); l2 = lambda(m, v2, dv, vtmp2); /* second lambda */ if (l2 < 0) continue; /* compute color from spectrum */ if (l1 < l2) spec_rgb(ctmp, l1, l2); else spec_rgb(ctmp, l2, l1); multcolor(ctmp, sray.rcol); scalecolor(ctmp, tr); addcolor(r->rcol, ctmp); success++; } return(success); }
double viewray( /* compute ray origin and direction */ FVECT orig, FVECT direc, VIEW *v, double x, double y ) { double d, z; x += v->hoff - 0.5; y += v->voff - 0.5; switch(v->type) { case VT_PAR: /* parallel view */ orig[0] = v->vp[0] + v->vfore*v->vdir[0] + x*v->hvec[0] + y*v->vvec[0]; orig[1] = v->vp[1] + v->vfore*v->vdir[1] + x*v->hvec[1] + y*v->vvec[1]; orig[2] = v->vp[2] + v->vfore*v->vdir[2] + x*v->hvec[2] + y*v->vvec[2]; VCOPY(direc, v->vdir); return(v->vaft > FTINY ? v->vaft - v->vfore : 0.0); case VT_PER: /* perspective view */ direc[0] = v->vdir[0] + x*v->hvec[0] + y*v->vvec[0]; direc[1] = v->vdir[1] + x*v->hvec[1] + y*v->vvec[1]; direc[2] = v->vdir[2] + x*v->hvec[2] + y*v->vvec[2]; VSUM(orig, v->vp, direc, v->vfore); d = normalize(direc); return(v->vaft > FTINY ? (v->vaft - v->vfore)*d : 0.0); case VT_HEM: /* hemispherical fisheye */ z = 1.0 - x*x*v->hn2 - y*y*v->vn2; if (z < 0.0) return(-1.0); z = sqrt(z); direc[0] = z*v->vdir[0] + x*v->hvec[0] + y*v->vvec[0]; direc[1] = z*v->vdir[1] + x*v->hvec[1] + y*v->vvec[1]; direc[2] = z*v->vdir[2] + x*v->hvec[2] + y*v->vvec[2]; VSUM(orig, v->vp, direc, v->vfore); return(v->vaft > FTINY ? v->vaft - v->vfore : 0.0); case VT_CYL: /* cylindrical panorama */ d = x * v->horiz * (PI/180.0); z = cos(d); x = sin(d); direc[0] = z*v->vdir[0] + x*v->hvec[0] + y*v->vvec[0]; direc[1] = z*v->vdir[1] + x*v->hvec[1] + y*v->vvec[1]; direc[2] = z*v->vdir[2] + x*v->hvec[2] + y*v->vvec[2]; VSUM(orig, v->vp, direc, v->vfore); d = normalize(direc); return(v->vaft > FTINY ? (v->vaft - v->vfore)*d : 0.0); case VT_ANG: /* angular fisheye */ x *= (1.0/180.0)*v->horiz; y *= (1.0/180.0)*v->vert; d = x*x + y*y; if (d > 1.0) return(-1.0); d = sqrt(d); z = cos(PI*d); d = d <= FTINY ? PI : sqrt(1.0 - z*z)/d; x *= d; y *= d; direc[0] = z*v->vdir[0] + x*v->hvec[0] + y*v->vvec[0]; direc[1] = z*v->vdir[1] + x*v->hvec[1] + y*v->vvec[1]; direc[2] = z*v->vdir[2] + x*v->hvec[2] + y*v->vvec[2]; VSUM(orig, v->vp, direc, v->vfore); return(v->vaft > FTINY ? v->vaft - v->vfore : 0.0); case VT_PLS: /* planispheric fisheye */ x *= sqrt(v->hn2); y *= sqrt(v->vn2); d = x*x + y*y; z = (1. - d)/(1. + d); x *= (1. + z); y *= (1. + z); direc[0] = z*v->vdir[0] + x*v->hvec[0] + y*v->vvec[0]; direc[1] = z*v->vdir[1] + x*v->hvec[1] + y*v->vvec[1]; direc[2] = z*v->vdir[2] + x*v->hvec[2] + y*v->vvec[2]; VSUM(orig, v->vp, direc, v->vfore); return(v->vaft > FTINY ? v->vaft - v->vfore : 0.0); } return(-1.0); }
void /* initialize occlusion cache */ initobscache(int sn) { register SRCREC *srcp = &source[sn]; int cachelen; FVECT rorg, rdir; RREAL d; int i, j, k; int ax=0, ax1=1, ax2=2; if (srcp->sflags & (SSKIP|SPROX|SSPOT|SVIRTUAL)) return; /* don't cache these */ if (srcp->sflags & SDISTANT) cachelen = 4*SHADCACHE*SHADCACHE; else if (srcp->sflags & SFLAT) cachelen = SHADCACHE*SHADCACHE*3 + (SHADCACHE&1)*SHADCACHE*4; else /* spherical distribution */ cachelen = SHADCACHE*SHADCACHE*6; /* allocate cache */ srcp->obscache = (OBSCACHE *)malloc(sizeof(OBSCACHE) + sizeof(OBJECT)*(cachelen-1)); if (srcp->obscache == NULL) error(SYSTEM, "out of memory in initobscache()"); /* set parameters */ if (srcp->sflags & SDISTANT) { RREAL amax = 0; for (ax1 = 3; ax1--; ) if (ABS(srcp->sloc[ax1]) > amax) { amax = ABS(srcp->sloc[ax1]); ax = ax1; } srcp->obscache->p.d.ax = ax; ax1 = (ax+1)%3; ax2 = (ax+2)%3; VCOPY(srcp->obscache->p.d.o, thescene.cuorg); if (srcp->sloc[ax] > 0) srcp->obscache->p.d.o[ax] += thescene.cusize; if (srcp->sloc[ax1] < 0) srcp->obscache->p.d.o[ax1] += thescene.cusize * srcp->sloc[ax1] / amax; if (srcp->sloc[ax2] < 0) srcp->obscache->p.d.o[ax2] += thescene.cusize * srcp->sloc[ax2] / amax; srcp->obscache->p.d.e1 = 1. / (thescene.cusize*(1. + fabs(srcp->sloc[ax1])/amax)); srcp->obscache->p.d.e2 = 1. / (thescene.cusize*(1. + fabs(srcp->sloc[ax2])/amax)); } else if (srcp->sflags & SFLAT) { VCOPY(srcp->obscache->p.f.u, srcp->ss[SU]); normalize(srcp->obscache->p.f.u); fcross(srcp->obscache->p.f.v, srcp->snorm, srcp->obscache->p.f.u); } /* clear cache */ for (i = cachelen; i--; ) srcp->obscache->obs[i] = OVOID; /* cast shadow rays */ if (srcp->sflags & SDISTANT) { for (k = 3; k--; ) rdir[k] = -srcp->sloc[k]; for (i = 2*SHADCACHE; i--; ) for (j = 2*SHADCACHE; j--; ) { VCOPY(rorg, srcp->obscache->p.d.o); rorg[ax1] += (i+.5) / (2*SHADCACHE*srcp->obscache->p.d.e1); rorg[ax2] += (j+.5) / (2*SHADCACHE*srcp->obscache->p.d.e2); castshadow(sn, rorg, rdir); } } else if (srcp->sflags & SFLAT) { d = 0.01*srcp->srad; VSUM(rorg, srcp->sloc, srcp->snorm, d); for (i = SHADCACHE; i--; ) for (j = SHADCACHE; j--; ) { d = 2./SHADCACHE*(i+.5) - 1.; VSUM(rdir, srcp->snorm, srcp->obscache->p.f.u, d); d = 2./SHADCACHE*(j+.5) - 1.; VSUM(rdir, rdir, srcp->obscache->p.f.v, d); normalize(rdir); castshadow(sn, rorg, rdir); } for (k = 2; k--; ) for (i = SHADCACHE; i--; ) for (j = SHADCACHE>>1; j--; ) {
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 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--; }
extern int localhit( /* check for hit in the octree */ RAY *r, CUBE *scene ) { OBJECT cxset[MAXCSET+1]; /* set of checked objects */ FVECT curpos; /* current cube position */ int sflags; /* sign flags */ double t, dt; int i; nrays++; /* increment trace counter */ sflags = 0; for (i = 0; i < 3; i++) { curpos[i] = r->rorg[i]; if (r->rdir[i] > 1e-7) sflags |= 1 << i; else if (r->rdir[i] < -1e-7) sflags |= 0x10 << i; } if (!sflags) { error(WARNING, "zero ray direction in localhit"); return(0); } /* start off assuming nothing hit */ if (r->rmax > FTINY) { /* except aft plane if one */ r->ro = &Aftplane; r->rot = r->rmax; VSUM(r->rop, r->rorg, r->rdir, r->rot); } /* find global cube entrance point */ t = 0.0; if (!incube(scene, curpos)) { /* find distance to entry */ for (i = 0; i < 3; i++) { /* plane in our direction */ if (sflags & 1<<i) dt = scene->cuorg[i]; else if (sflags & 0x10<<i) dt = scene->cuorg[i] + scene->cusize; else continue; /* distance to the plane */ dt = (dt - r->rorg[i])/r->rdir[i]; if (dt > t) t = dt; /* farthest face is the one */ } t += FTINY; /* fudge to get inside cube */ if (t >= r->rot) /* clipped already */ return(0); /* advance position */ VSUM(curpos, curpos, r->rdir, t); if (!incube(scene, curpos)) /* non-intersecting ray */ return(0); } cxset[0] = 0; raymove(curpos, cxset, sflags, r, scene); return((r->ro != NULL) & (r->ro != &Aftplane)); }
int o_cone( /* intersect ray with cone */ OBJREC *o, RAY *r ) { FVECT rox, rdx; double a, b, c; double root[2]; int nroots, rn; CONE *co; int i; /* get cone structure */ co = getcone(o, 1); /* * To intersect a ray with a cone, we transform the * ray into the cone's normalized space. This greatly * simplifies the computation. * For a cone or cup, normalization results in the * equation: * * x*x + y*y - z*z == 0 * * For a cylinder or tube, the normalized equation is: * * x*x + y*y - r*r == 0 * * A normalized ring obeys the following set of equations: * * z == 0 && * x*x + y*y >= r0*r0 && * x*x + y*y <= r1*r1 */ /* transform ray */ multp3(rox, r->rorg, co->tm); multv3(rdx, r->rdir, co->tm); /* compute intersection */ if (o->otype == OBJ_CONE || o->otype == OBJ_CUP) { a = rdx[0]*rdx[0] + rdx[1]*rdx[1] - rdx[2]*rdx[2]; b = 2.0*(rdx[0]*rox[0] + rdx[1]*rox[1] - rdx[2]*rox[2]); c = rox[0]*rox[0] + rox[1]*rox[1] - rox[2]*rox[2]; } else if (o->otype == OBJ_CYLINDER || o->otype == OBJ_TUBE) { a = rdx[0]*rdx[0] + rdx[1]*rdx[1]; b = 2.0*(rdx[0]*rox[0] + rdx[1]*rox[1]); c = rox[0]*rox[0] + rox[1]*rox[1] - CO_R0(co)*CO_R0(co); } else { /* OBJ_RING */ if (rdx[2] <= FTINY && rdx[2] >= -FTINY) return(0); /* parallel */ root[0] = -rox[2]/rdx[2]; if (root[0] <= FTINY || root[0] >= r->rot) return(0); /* distance check */ b = root[0]*rdx[0] + rox[0]; c = root[0]*rdx[1] + rox[1]; a = b*b + c*c; if (a < CO_R0(co)*CO_R0(co) || a > CO_R1(co)*CO_R1(co)) return(0); /* outside radii */ r->ro = o; r->rot = root[0]; VSUM(r->rop, r->rorg, r->rdir, r->rot); VCOPY(r->ron, co->ad); r->rod = -rdx[2]; r->rox = NULL; return(1); /* good */ } /* roots for cone, cup, cyl., tube */ nroots = quadratic(root, a, b, c); for (rn = 0; rn < nroots; rn++) { /* check real roots */ if (root[rn] <= FTINY) continue; /* too small */ if (root[rn] >= r->rot) break; /* too big */ /* check endpoints */ VSUM(rox, r->rorg, r->rdir, root[rn]); VSUB(rdx, rox, CO_P0(co)); b = DOT(rdx, co->ad); if (b < 0.0) continue; /* before p0 */ if (b > co->al) continue; /* after p1 */ r->ro = o; r->rot = root[rn]; VCOPY(r->rop, rox); /* get normal */ if (o->otype == OBJ_CYLINDER) a = CO_R0(co); else if (o->otype == OBJ_TUBE) a = -CO_R0(co); else { /* OBJ_CONE || OBJ_CUP */ c = CO_R1(co) - CO_R0(co); a = CO_R0(co) + b*c/co->al; if (o->otype == OBJ_CUP) { c = -c; a = -a; } } for (i = 0; i < 3; i++) r->ron[i] = (rdx[i] - b*co->ad[i])/a; if (o->otype == OBJ_CONE || o->otype == OBJ_CUP) for (i = 0; i < 3; i++) r->ron[i] = (co->al*r->ron[i] - c*co->ad[i]) / co->sl; a = DOT(r->ron, r->ron); if (a > 1.+FTINY || a < 1.-FTINY) { c = 1./(.5 + .5*a); /* avoid numerical error */ r->ron[0] *= c; r->ron[1] *= c; r->ron[2] *= c; } r->rod = -DOT(r->rdir, r->ron); r->pert[0] = r->pert[1] = r->pert[2] = 0.0; r->uv[0] = r->uv[1] = 0.0; r->rox = NULL; return(1); /* good */ } return(0); }
static int raymove( /* check for hit as we move */ FVECT pos, /* current position, modified herein */ OBJECT *cxs, /* checked objects, modified by checkhit */ int dirf, /* direction indicators to speed tests */ RAY *r, CUBE *cu ) { int ax; double dt, t; if (istree(cu->cutree)) { /* recurse on subcubes */ CUBE cukid; int br, sgn; cukid.cusize = cu->cusize * 0.5; /* find subcube */ VCOPY(cukid.cuorg, cu->cuorg); br = 0; if (pos[0] >= cukid.cuorg[0]+cukid.cusize) { cukid.cuorg[0] += cukid.cusize; br |= 1; } if (pos[1] >= cukid.cuorg[1]+cukid.cusize) { cukid.cuorg[1] += cukid.cusize; br |= 2; } if (pos[2] >= cukid.cuorg[2]+cukid.cusize) { cukid.cuorg[2] += cukid.cusize; br |= 4; } for ( ; ; ) { cukid.cutree = octkid(cu->cutree, br); if ((ax = raymove(pos,cxs,dirf,r,&cukid)) == RAYHIT) return(RAYHIT); sgn = 1 << ax; if (sgn & dirf) /* positive axis? */ if (sgn & br) return(ax); /* overflow */ else { cukid.cuorg[ax] += cukid.cusize; br |= sgn; } else if (sgn & br) { cukid.cuorg[ax] -= cukid.cusize; br &= ~sgn; } else return(ax); /* underflow */ } /*NOTREACHED*/ } if (isfull(cu->cutree)) { if (checkhit(r, cu, cxs)) return(RAYHIT); } else if (r->ro == &Aftplane && incube(cu, r->rop)) return(RAYHIT); /* advance to next cube */ if (dirf&0x11) { dt = dirf&1 ? cu->cuorg[0] + cu->cusize : cu->cuorg[0]; t = (dt - pos[0])/r->rdir[0]; ax = 0; } else t = FHUGE; if (dirf&0x22) { dt = dirf&2 ? cu->cuorg[1] + cu->cusize : cu->cuorg[1]; dt = (dt - pos[1])/r->rdir[1]; if (dt < t) { t = dt; ax = 1; } } if (dirf&0x44) { dt = dirf&4 ? cu->cuorg[2] + cu->cusize : cu->cuorg[2]; dt = (dt - pos[2])/r->rdir[2]; if (dt < t) { t = dt; ax = 2; } } VSUM(pos, pos, r->rdir, t); return(ax); }
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--; } }
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 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_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); }