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 */ }
extern int o_instance( /* compute ray intersection with octree */ OBJREC *o, register RAY *r ) { RAY rcont; double d; register INSTANCE *ins; register int i; /* get the octree */ ins = getinstance(o, IO_ALL); /* copy and transform ray */ rcont = *r; multp3(rcont.rorg, r->rorg, ins->x.b.xfm); multv3(rcont.rdir, r->rdir, ins->x.b.xfm); for (i = 0; i < 3; i++) rcont.rdir[i] /= ins->x.b.sca; rcont.rmax *= ins->x.b.sca; /* clear and trace it */ rayclear(&rcont); if (!localhit(&rcont, &ins->obj->scube)) return(0); /* missed */ if (rcont.rot * ins->x.f.sca >= r->rot) return(0); /* not close enough */ if (o->omod != OVOID) { /* if we have modifier, use it */ r->ro = o; r->rox = NULL; } else { /* else use theirs */ r->ro = rcont.ro; if (rcont.rox != NULL) { newrayxf(r); /* allocate transformation */ /* NOTE: r->rox may equal rcont.rox! */ multmat4(r->rox->f.xfm, rcont.rox->f.xfm, ins->x.f.xfm); r->rox->f.sca = rcont.rox->f.sca * ins->x.f.sca; multmat4(r->rox->b.xfm, ins->x.b.xfm, rcont.rox->b.xfm); r->rox->b.sca = ins->x.b.sca * rcont.rox->b.sca; } else r->rox = &ins->x; } /* transform it back */ r->rot = rcont.rot * ins->x.f.sca; multp3(r->rop, rcont.rop, ins->x.f.xfm); multv3(r->ron, rcont.ron, ins->x.f.xfm); multv3(r->pert, rcont.pert, ins->x.f.xfm); d = 1./ins->x.f.sca; for (i = 0; i < 3; i++) { r->ron[i] *= d; r->pert[i] *= d; } r->rod = rcont.rod; r->uv[0] = rcont.uv[0]; r->uv[1] = rcont.uv[1]; /* return hit */ return(1); }
static void ray_pchild( /* process rays (never returns) */ int fd_in, int fd_out ) { int n; register int i; /* flag child process for quit() */ ray_pnprocs = -1; /* read each ray request set */ while ((n = read(fd_in, (char *)r_queue, sizeof(r_queue))) > 0) { int n2; if (n < sizeof(RAY)) break; /* get smuggled set length */ n2 = sizeof(RAY)*r_queue[0].crtype - n; if (n2 < 0) error(INTERNAL, "buffer over-read in ray_pchild()"); if (n2 > 0) { /* read the rest of the set */ i = readbuf(fd_in, (char *)r_queue + n, n2); if (i != n2) break; n += n2; } n /= sizeof(RAY); /* evaluate rays */ for (i = 0; i < n; i++) { r_queue[i].crtype = r_queue[i].rtype; r_queue[i].parent = NULL; r_queue[i].clipset = NULL; r_queue[i].slights = NULL; r_queue[i].rlvl = 0; samplendx += samplestep; rayclear(&r_queue[i]); rayvalue(&r_queue[i]); } /* write back our results */ i = writebuf(fd_out, (char *)r_queue, sizeof(RAY)*n); if (i != sizeof(RAY)*n) error(SYSTEM, "write error in ray_pchild()"); } if (n) error(SYSTEM, "read error in ray_pchild()"); ambsync(); quit(0); /* normal exit */ }
extern int rayorigin( /* start new ray from old one */ RAY *r, int rt, const RAY *ro, const COLOR rc ) { double rw, re; /* assign coefficient/weight */ if (rc == NULL) { rw = 1.0; setcolor(r->rcoef, 1., 1., 1.); } else { rw = intens(rc); if (rc != r->rcoef) copycolor(r->rcoef, rc); } if ((r->parent = ro) == NULL) { /* primary ray */ r->rlvl = 0; r->rweight = rw; r->crtype = r->rtype = rt; r->rsrc = -1; r->clipset = NULL; r->revf = raytrace; copycolor(r->cext, cextinction); copycolor(r->albedo, salbedo); r->gecc = seccg; r->slights = NULL; } else { /* spawned ray */ if (ro->rot >= FHUGE) { memset(r, 0, sizeof(RAY)); return(-1); /* illegal continuation */ } r->rlvl = ro->rlvl; if (rt & RAYREFL) { r->rlvl++; r->rsrc = -1; r->clipset = ro->clipset; r->rmax = 0.0; } else { r->rsrc = ro->rsrc; r->clipset = ro->newcset; r->rmax = ro->rmax <= FTINY ? 0.0 : ro->rmax - ro->rot; } r->revf = ro->revf; copycolor(r->cext, ro->cext); copycolor(r->albedo, ro->albedo); r->gecc = ro->gecc; r->slights = ro->slights; r->crtype = ro->crtype | (r->rtype = rt); VCOPY(r->rorg, ro->rop); r->rweight = ro->rweight * rw; /* estimate extinction */ re = colval(ro->cext,RED) < colval(ro->cext,GRN) ? colval(ro->cext,RED) : colval(ro->cext,GRN); if (colval(ro->cext,BLU) < re) re = colval(ro->cext,BLU); re *= ro->rot; if (re > 0.1) { if (re > 92.) { r->rweight = 0.0; } else { r->rweight *= exp(-re); } } } rayclear(r); if (r->rweight <= 0.0) /* check for expiration */ return(-1); if (r->crtype & SHADOW) /* shadow commitment */ return(0); if (maxdepth <= 0 && rc != NULL) { /* Russian roulette */ if (minweight <= 0.0) error(USER, "zero ray weight in Russian roulette"); if (maxdepth < 0 && r->rlvl > -maxdepth) return(-1); /* upper reflection limit */ if (r->rweight >= minweight) return(0); if (frandom() > r->rweight/minweight) return(-1); rw = minweight/r->rweight; /* promote survivor */ scalecolor(r->rcoef, rw); r->rweight = minweight; return(0); } return(r->rweight >= minweight && r->rlvl <= abs(maxdepth) ? 0 : -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--; }
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--; } }