void getfocus( /* set focus distance */ char *s ) { char buf[64]; double dist; if (sscanf(s, "%lf", &dist) < 1) { int x, y; RAY thisray; if (dev->getcur == NULL) return; (*dev->comout)("Pick focus point\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; } dist = thisray.rot; } else if (dist <= .0) { error(COMMAND, "focus distance must be positive"); return; } ourview.vdist = dist; sprintf(buf, "Focus distance set to %f\n", dist); (*dev->comout)(buf); }
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 */ }
int getinterest( /* get area of interest */ char *s, int direc, FVECT vec, double *mp ) { int x, y; RAY thisray; int i; if (sscanf(s, "%lf", mp) != 1) *mp = 1.0; else if (*mp < -FTINY) /* negative zoom is reduction */ *mp = -1.0 / *mp; else if (*mp <= FTINY) { /* too small */ error(COMMAND, "illegal magnification"); return(-1); } if (!sscanvec(sskip(s), vec)) { if (dev->getcur == NULL) return(-1); (*dev->comout)("Pick view center\n"); if ((*dev->getcur)(&x, &y) == ABORT) return(-1); if ((thisray.rmax = viewray(thisray.rorg, thisray.rdir, &ourview, (x+.5)/hresolu, (y+.5)/vresolu)) < -FTINY) { error(COMMAND, "not on image"); return(-1); } if (!direc || ourview.type == VT_PAR) { rayorigin(&thisray, PRIMARY, NULL, NULL); if (!localhit(&thisray, &thescene)) { error(COMMAND, "not a local object"); return(-1); } } if (direc) if (ourview.type == VT_PAR) for (i = 0; i < 3; i++) vec[i] = thisray.rop[i] - ourview.vp[i]; else VCOPY(vec, thisray.rdir); else VCOPY(vec, thisray.rop); } else if (direc) { for (i = 0; i < 3; i++) vec[i] -= ourview.vp[i]; if (normalize(vec) == 0.0) { error(COMMAND, "point at view origin"); return(-1); } } return(0); }
extern void raytrans( /* transmit ray as is */ RAY *r ) { RAY tr; if (rayorigin(&tr, TRANS, r, NULL) == 0) { VCOPY(tr.rdir, r->rdir); rayvalue(&tr); copycolor(r->rcol, tr.rcol); r->rt = r->rot + tr.rt; } }
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); }
extern int srcray( /* send a ray to a source, return domega */ register RAY *sr, /* returned source ray */ RAY *r, /* ray which hit object */ SRCINDEX *si /* source sample index */ ) { double d; /* distance to source */ register SRCREC *srcp; rayorigin(sr, SHADOW, r, NULL); /* ignore limits */ if (r == NULL) sr->rmax = 0.0; while ((d = nextssamp(sr, si)) != 0.0) { sr->rsrc = si->sn; /* remember source */ srcp = source + si->sn; if (srcp->sflags & SDISTANT) { if (srcp->sflags & SSPOT && spotout(sr, srcp->sl.s)) continue; return(1); /* sample OK */ } /* local source */ /* check proximity */ if (srcp->sflags & SPROX && d > srcp->sl.prox) continue; /* check angle */ if (srcp->sflags & SSPOT) { if (spotout(sr, srcp->sl.s)) continue; /* adjust solid angle */ si->dom *= d*d; d += srcp->sl.s->flen; si->dom /= d*d; } return(1); /* sample OK */ } return(0); /* no more samples */ }
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); }
extern void /* add sources smaller than rad to computed subimage */ drawsources( COLOR *pic[], /* subimage pixel value array */ float *zbf[], /* subimage distance array (opt.) */ int x0, /* origin and size of subimage */ int xsiz, int y0, int ysiz ) { RREAL spoly[MAXVERT][2], ppoly[MAXVERT][2]; int nsv, npv; int xmin, xmax, ymin, ymax, x, y; RREAL cxy[2]; double w; RAY sr; register SPLIST *sp; register int i; /* check each source in our list */ for (sp = sphead; sp != NULL; sp = sp->next) { /* clip source poly to subimage */ nsv = box_clip_poly(sp->vl, sp->nv, (double)x0/hres, (double)(x0+xsiz)/hres, (double)y0/vres, (double)(y0+ysiz)/vres, spoly); if (!nsv) continue; /* find common subimage (BBox) */ xmin = x0 + xsiz; xmax = x0; ymin = y0 + ysiz; ymax = y0; for (i = 0; i < nsv; i++) { if ((double)xmin/hres > spoly[i][0]) xmin = spoly[i][0]*hres + FTINY; if ((double)xmax/hres < spoly[i][0]) xmax = spoly[i][0]*hres - FTINY; if ((double)ymin/vres > spoly[i][1]) ymin = spoly[i][1]*vres + FTINY; if ((double)ymax/vres < spoly[i][1]) ymax = spoly[i][1]*vres - FTINY; } /* evaluate each pixel in BBox */ for (y = ymin; y <= ymax; y++) for (x = xmin; x <= xmax; x++) { /* subarea for pixel */ npv = box_clip_poly(spoly, nsv, (double)x/hres, (x+1.)/hres, (double)y/vres, (y+1.)/vres, ppoly); if (!npv) continue; /* no overlap */ convex_center(ppoly, npv, cxy); if ((sr.rmax = viewray(sr.rorg,sr.rdir,&ourview, cxy[0],cxy[1])) < -FTINY) continue; /* not in view */ if (source[sp->sn].sflags & SSPOT && spotout(&sr, source[sp->sn].sl.s)) continue; /* outside spot */ rayorigin(&sr, SHADOW, NULL, NULL); sr.rsrc = sp->sn; rayvalue(&sr); /* compute value */ if (bright(sr.rcol) <= FTINY) continue; /* missed/blocked */ /* modify pixel */ w = poly_area(ppoly, npv) * hres * vres; if (zbf[y-y0] != NULL && sr.rt < 0.99*zbf[y-y0][x-x0]) { zbf[y-y0][x-x0] = sr.rt; } else if (!bigdiff(sr.rcol, pic[y-y0][x-x0], 0.01)) { /* source sample */ scalecolor(pic[y-y0][x-x0], w); continue; } scalecolor(sr.rcol, w); scalecolor(pic[y-y0][x-x0], 1.-w); addcolor(pic[y-y0][x-x0], sr.rcol); } } }
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); }
static int dir_proj( /* compute a director's projection */ MAT4 pm, OBJREC *o, SRCREC *s, int n ) { RAY tr; OBJREC *m; MFUNC *mf; EPNODE **va; FVECT cent, newdir, nv, h; double coef, olddot, newdot, od; int i, j; /* initialize test ray */ getmaxdisk(cent, o); if (s->sflags & SDISTANT) for (i = 0; i < 3; i++) { tr.rdir[i] = -s->sloc[i]; tr.rorg[i] = cent[i] - tr.rdir[i]; } else { for (i = 0; i < 3; i++) { tr.rdir[i] = cent[i] - s->sloc[i]; tr.rorg[i] = s->sloc[i]; } if (normalize(tr.rdir) == 0.0) return(0); /* at source! */ } od = getplaneq(nv, o); olddot = DOT(tr.rdir, nv); if (olddot <= FTINY && olddot >= -FTINY) return(0); /* old dir parallels plane */ tr.rmax = 0.0; rayorigin(&tr, PRIMARY, NULL, NULL); if (!(*ofun[o->otype].funp)(o, &tr)) return(0); /* no intersection! */ /* compute redirection */ m = vsmaterial(o); mf = getdfunc(m); setfunc(m, &tr); varset("DxA", '=', 0.0); varset("DyA", '=', 0.0); varset("DzA", '=', 0.0); errno = 0; va = mf->ep + 4*n; coef = evalue(va[0]); if (errno == EDOM || errno == ERANGE) goto computerr; if (coef <= FTINY) return(0); /* insignificant */ va++; for (i = 0; i < 3; i++) { newdir[i] = evalue(va[i]); if (errno == EDOM || errno == ERANGE) goto computerr; } if (mf->fxp != &unitxf) multv3(newdir, newdir, mf->fxp->xfm); /* normalization unnecessary */ newdot = DOT(newdir, nv); if (newdot <= FTINY && newdot >= -FTINY) return(0); /* new dir parallels plane */ /* everything OK -- compute shear */ for (i = 0; i < 3; i++) h[i] = newdir[i]/newdot - tr.rdir[i]/olddot; setident4(pm); for (j = 0; j < 3; j++) { for (i = 0; i < 3; i++) pm[i][j] += nv[i]*h[j]; pm[3][j] = -od*h[j]; } if ((newdot > 0.0) ^ (olddot > 0.0)) /* add mirroring */ for (j = 0; j < 3; j++) { for (i = 0; i < 3; i++) pm[i][j] -= 2.*nv[i]*nv[j]; pm[3][j] += 2.*od*nv[j]; } return(1); computerr: objerror(m, WARNING, "projection compute error"); return(0); }
int m_mist( /* process a ray entering or leaving some mist */ OBJREC *m, RAY *r ) { RAY p; int *myslist = NULL; int newslist[MAXSLIST+1]; COLOR mext; double re, ge, be; int i, j; /* check arguments */ if (m->oargs.nfargs > 7) objerror(m, USER, "bad arguments"); /* get source indices */ if (m->oargs.nsargs > 0 && (myslist = (int *)m->os) == NULL) { if (m->oargs.nsargs > MAXSLIST) objerror(m, INTERNAL, "too many sources in list"); myslist = (int *)malloc((m->oargs.nsargs+1)*sizeof(int)); if (myslist == NULL) goto memerr; myslist[0] = 0; /* size is first in list */ for (j = 0; j < m->oargs.nsargs; j++) { i = nsources; /* look up each source id */ while (i--) if (srcmatch(source+i, m->oargs.sarg[j])) break; if (i < 0) { sprintf(errmsg, "unknown source \"%s\"", m->oargs.sarg[j]); objerror(m, WARNING, errmsg); } else if (inslist(myslist, i)) { sprintf(errmsg, "duplicate source \"%s\"", m->oargs.sarg[j]); objerror(m, WARNING, errmsg); } else myslist[++myslist[0]] = i; } m->os = (char *)myslist; } if (m->oargs.nfargs > 2) { /* compute extinction */ setcolor(mext, m->oargs.farg[0], m->oargs.farg[1], m->oargs.farg[2]); raytexture(r, m->omod); /* get modifiers */ multcolor(mext, r->pcol); } else setcolor(mext, 0., 0., 0.); /* start transmitted ray */ if (rayorigin(&p, TRANS, r, NULL) < 0) return(1); VCOPY(p.rdir, r->rdir); p.slights = newslist; if (r->slights != NULL) /* copy old list if one */ for (j = r->slights[0]; j >= 0; j--) p.slights[j] = r->slights[j]; else p.slights[0] = 0; if (r->rod > 0.) { /* entering ray */ addcolor(p.cext, mext); if (m->oargs.nfargs > 5) setcolor(p.albedo, m->oargs.farg[3], m->oargs.farg[4], m->oargs.farg[5]); if (m->oargs.nfargs > 6) p.gecc = m->oargs.farg[6]; add2slist(&p, myslist); /* add to list */ } else { /* leaving ray */ if (myslist != NULL) { /* delete from list */ for (j = myslist[0]; j > 0; j--) if ( (i = inslist(p.slights, myslist[j])) ) p.slights[i] = -1; for (i = 0, j = 1; j <= p.slights[0]; j++) if (p.slights[j] != -1) p.slights[++i] = p.slights[j]; if (p.slights[0] - i < myslist[0]) { /* fix old */ addcolor(r->cext, mext); if (m->oargs.nfargs > 5) setcolor(r->albedo, m->oargs.farg[3], m->oargs.farg[4], m->oargs.farg[5]); if (m->oargs.nfargs > 6) r->gecc = m->oargs.farg[6]; add2slist(r, myslist); } p.slights[0] = i; } if ((re = colval(r->cext,RED) - colval(mext,RED)) < colval(cextinction,RED)) re = colval(cextinction,RED); if ((ge = colval(r->cext,GRN) - colval(mext,GRN)) < colval(cextinction,GRN)) ge = colval(cextinction,GRN); if ((be = colval(r->cext,BLU) - colval(mext,BLU)) < colval(cextinction,BLU)) be = colval(cextinction,BLU); setcolor(p.cext, re, ge, be); if (m->oargs.nfargs > 5) copycolor(p.albedo, salbedo); if (m->oargs.nfargs > 6) p.gecc = seccg; } rayvalue(&p); /* calls rayparticipate() */ copycolor(r->rcol, p.rcol); /* return value */ r->rt = r->rot + p.rt; return(1); memerr: error(SYSTEM, "out of memory in m_mist"); return 0; /* pro forma return */ }
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 void direct( /* add direct component */ RAY *r, /* ray that hit surface */ srcdirf_t *f, /* direct component coefficient function */ void *p /* data for f */ ) { register int sn; register CONTRIB *scp; SRCINDEX si; int nshadcheck, ncnts; int nhits; double prob, ourthresh, hwt; RAY sr; /* NOTE: srccnt and cntord global so no recursion */ if (nsources <= 0) return; /* no sources?! */ /* potential contributions */ initsrcindex(&si); for (sn = 0; srcray(&sr, r, &si); sn++) { if (sn >= maxcntr) { maxcntr = sn + MAXSPART; srccnt = (CONTRIB *)realloc((void *)srccnt, maxcntr*sizeof(CONTRIB)); cntord = (CNTPTR *)realloc((void *)cntord, maxcntr*sizeof(CNTPTR)); if ((srccnt == NULL) | (cntord == NULL)) error(SYSTEM, "out of memory in direct"); } cntord[sn].sndx = sn; scp = srccnt + sn; scp->sno = sr.rsrc; /* compute coefficient */ (*f)(scp->coef, p, sr.rdir, si.dom); cntord[sn].brt = intens(scp->coef); if (cntord[sn].brt <= 0.0) continue; #if SHADCACHE /* check shadow cache */ if (si.np == 1 && srcblocked(&sr)) { cntord[sn].brt = 0.0; continue; } #endif VCOPY(scp->dir, sr.rdir); copycolor(sr.rcoef, scp->coef); /* compute potential */ sr.revf = srcvalue; rayvalue(&sr); multcolor(sr.rcol, sr.rcoef); copycolor(scp->val, sr.rcol); cntord[sn].brt = bright(sr.rcol); } /* sort contributions */ qsort(cntord, sn, sizeof(CNTPTR), cntcmp); { /* find last */ register int l, m; ncnts = l = sn; sn = 0; while ((m = (sn + ncnts) >> 1) != l) { if (cntord[m].brt > 0.0) sn = m; else ncnts = m; l = m; } } if (ncnts == 0) return; /* no contributions! */ /* accumulate tail */ for (sn = ncnts-1; sn > 0; sn--) cntord[sn-1].brt += cntord[sn].brt; /* compute number to check */ nshadcheck = pow((double)ncnts, shadcert) + .5; /* modify threshold */ ourthresh = shadthresh / r->rweight; /* test for shadows */ for (nhits = 0, hwt = 0.0, sn = 0; sn < ncnts; hwt += (double)source[scp->sno].nhits / (double)source[scp->sno].ntests, sn++) { /* check threshold */ if ((sn+nshadcheck>=ncnts ? cntord[sn].brt : cntord[sn].brt-cntord[sn+nshadcheck].brt) < ourthresh*bright(r->rcol)) break; scp = srccnt + cntord[sn].sndx; /* test for hit */ rayorigin(&sr, SHADOW, r, NULL); copycolor(sr.rcoef, scp->coef); VCOPY(sr.rdir, scp->dir); sr.rsrc = scp->sno; /* keep statistics */ if (source[scp->sno].ntests++ > 0xfffffff0) { source[scp->sno].ntests >>= 1; source[scp->sno].nhits >>= 1; } if (localhit(&sr, &thescene) && ( sr.ro != source[scp->sno].so || source[scp->sno].sflags & SFOLLOW )) { /* follow entire path */ raycont(&sr); if (trace != NULL) (*trace)(&sr); /* trace execution */ if (bright(sr.rcol) <= FTINY) { #if SHADCACHE if ((scp <= srccnt || scp[-1].sno != scp->sno) && (scp >= srccnt+ncnts-1 || scp[1].sno != scp->sno)) srcblocker(&sr); #endif continue; /* missed! */ } rayparticipate(&sr); multcolor(sr.rcol, sr.rcoef); copycolor(scp->val, sr.rcol); } else if (trace != NULL && (source[scp->sno].sflags & (SDISTANT|SVIRTUAL|SFOLLOW)) == (SDISTANT|SFOLLOW) && sourcehit(&sr) && rayshade(&sr, sr.ro->omod)) { (*trace)(&sr); /* trace execution */ /* skip call to rayparticipate() & scp->val update */ } /* add contribution if hit */ addcolor(r->rcol, scp->val); nhits++; source[scp->sno].nhits++; }
int paint( /* compute and paint a rectangle */ PNODE *p ) { static RAY thisray; double h, v; if ((p->xmax <= p->xmin) | (p->ymax <= p->ymin)) { /* empty */ p->x = p->xmin; p->y = p->ymin; setcolor(p->v, 0.0, 0.0, 0.0); return(0); } /* jitter ray direction */ p->x = h = p->xmin + (p->xmax-p->xmin)*frandom(); p->y = v = p->ymin + (p->ymax-p->ymin)*frandom(); if ((thisray.rmax = viewray(thisray.rorg, thisray.rdir, &ourview, h/hresolu, v/vresolu)) < -FTINY) { setcolor(thisray.rcol, 0.0, 0.0, 0.0); } else if (!ray_pnprocs) { /* immediate mode */ ray_trace(&thisray); } else { /* queuing mode */ int rval; rayorigin(&thisray, PRIMARY, NULL, NULL); thisray.rno = (RNUMBER)p; rval = ray_pqueue(&thisray); if (!rval) return(0); if (rval < 0) return(-1); /* get node for returned ray */ p = (PNODE *)thisray.rno; } copycolor(p->v, thisray.rcol); scalecolor(p->v, exposure); recolor(p); /* paint it */ if (dev->flush != NULL) { /* shall we check for input? */ static RNUMBER lastflush = 0; RNUMBER counter = raynum; int flushintvl; if (!ray_pnprocs) { counter = nrays; flushintvl = WFLUSH1; } else if (ambounce == 0) flushintvl = ray_pnprocs*WFLUSH; else if (niflush < WFLUSH) flushintvl = ray_pnprocs*niflush/(ambounce+1); else flushintvl = ray_pnprocs*WFLUSH/(ambounce+1); if (lastflush > counter) lastflush = 0; /* counter wrapped */ if (counter - lastflush >= flushintvl) { lastflush = counter; (*dev->flush)(); niflush++; } } 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); }
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--; } }