extern int raymixture( /* mix modifiers */ RAY *r, OBJECT fore, OBJECT back, double coef ) { RAY fr, br; int foremat, backmat; int i; /* bound coefficient */ if (coef > 1.0) coef = 1.0; else if (coef < 0.0) coef = 0.0; /* compute foreground and background */ foremat = backmat = 0; /* foreground */ fr = *r; if (coef > FTINY) { fr.rweight *= coef; scalecolor(fr.rcoef, coef); foremat = rayshade(&fr, fore); } /* background */ br = *r; if (coef < 1.0-FTINY) { br.rweight *= 1.0-coef; scalecolor(br.rcoef, 1.0-coef); backmat = rayshade(&br, back); } /* check for transparency */ if (backmat ^ foremat) { if (backmat && coef > FTINY) raytrans(&fr); else if (foremat && coef < 1.0-FTINY) raytrans(&br); } /* mix perturbations */ for (i = 0; i < 3; i++) r->pert[i] = coef*fr.pert[i] + (1.0-coef)*br.pert[i]; /* mix pattern colors */ scalecolor(fr.pcol, coef); scalecolor(br.pcol, 1.0-coef); copycolor(r->pcol, fr.pcol); addcolor(r->pcol, br.pcol); /* return value tells if material */ if (!foremat & !backmat) return(0); /* mix returned ray values */ scalecolor(fr.rcol, coef); scalecolor(br.rcol, 1.0-coef); copycolor(r->rcol, fr.rcol); addcolor(r->rcol, br.rcol); r->rt = bright(fr.rcol) > bright(br.rcol) ? fr.rt : br.rt; return(1); }
static void dirashik( /* compute source contribution */ COLOR cval, /* returned coefficient */ void *nnp, /* material data */ FVECT ldir, /* light source direction */ double omega /* light source size */ ) { ASHIKDAT *np = nnp; double ldot; double dtmp, dtmp1, dtmp2; FVECT h; COLOR ctmp; setcolor(cval, 0.0, 0.0, 0.0); ldot = DOT(np->pnorm, ldir); if (ldot < 0.0) return; /* wrong side */ /* * Compute and add diffuse reflected component to returned * color. */ copycolor(ctmp, np->mcolor); dtmp = ldot * omega * (1.0/PI) * (1. - schlick_fres(ldot)); scalecolor(ctmp, dtmp); addcolor(cval, ctmp); if ((np->specfl & (SPA_REFL|SPA_BADU)) != SPA_REFL) return; /* * Compute specular reflection coefficient */ /* half vector */ VSUB(h, ldir, np->rp->rdir); normalize(h); /* ellipse */ dtmp1 = DOT(np->u, h); dtmp1 *= dtmp1 * np->u_power; dtmp2 = DOT(np->v, h); dtmp2 *= dtmp2 * np->v_power; /* Ashikhmin-Shirley model*/ dtmp = DOT(np->pnorm, h); dtmp = pow(dtmp, (dtmp1+dtmp2)/(1.-dtmp*dtmp)); dtmp *= sqrt((np->u_power+1.)*(np->v_power+1.)); dtmp /= 8.*PI * DOT(ldir,h) * MAX(ldot,np->pdot); /* worth using? */ if (dtmp > FTINY) { copycolor(ctmp, np->scolor); dtmp *= ldot * omega; scalecolor(ctmp, dtmp); addcolor(cval, ctmp); } }
extern void rayparticipate( /* compute ray medium participation */ RAY *r ) { COLOR ce, ca; double re, ge, be; if (intens(r->cext) <= 1./FHUGE) return; /* no medium */ re = r->rot*colval(r->cext,RED); ge = r->rot*colval(r->cext,GRN); be = r->rot*colval(r->cext,BLU); if (r->crtype & SHADOW) { /* no scattering for sources */ re *= 1. - colval(r->albedo,RED); ge *= 1. - colval(r->albedo,GRN); be *= 1. - colval(r->albedo,BLU); } setcolor(ce, re<=FTINY ? 1. : re>92. ? 0. : exp(-re), ge<=FTINY ? 1. : ge>92. ? 0. : exp(-ge), be<=FTINY ? 1. : be>92. ? 0. : exp(-be)); multcolor(r->rcol, ce); /* path extinction */ if (r->crtype & SHADOW || intens(r->albedo) <= FTINY) return; /* no scattering */ setcolor(ca, colval(r->albedo,RED)*colval(ambval,RED)*(1.-colval(ce,RED)), colval(r->albedo,GRN)*colval(ambval,GRN)*(1.-colval(ce,GRN)), colval(r->albedo,BLU)*colval(ambval,BLU)*(1.-colval(ce,BLU))); addcolor(r->rcol, ca); /* ambient in scattering */ srcscatter(r); /* source in scattering */ }
extern void scotscan( /* apply scotopic color sensitivity loss */ COLOR *scan, int xres ) { COLOR ctmp; double incolor, b, Lw; register int i; for (i = 0; i < xres; i++) { Lw = plum(scan[i]); if (Lw >= TopMesopic) incolor = 1.; else if (Lw <= BotMesopic) incolor = 0.; else incolor = (Lw - BotMesopic) / (TopMesopic - BotMesopic); if (incolor < 1.-FTINY) { b = (1.-incolor)*slum(scan[i])*inpexp/SWNORM; if (lumf == rgblum) b /= WHTEFFICACY; setcolor(ctmp, b, b, b); if (incolor <= FTINY) setcolor(scan[i], 0., 0., 0.); else scalecolor(scan[i], incolor); addcolor(scan[i], ctmp); } } }
static void sum_consp( /* sum in conspicuity result */ register struct ConspSum *cdest, register struct ConspSum *cs ) { if ((cdest == NULL) | (cs == NULL)) return; addcolor(cdest->vsum, cs->vsum); addcolor(cdest->v2sum, cs->v2sum); cdest->nsamp += cs->nsamp; cdest->xmsum += cs->xmsum; cdest->ymsum += cs->ymsum; cdest->npix += cs->npix; if (cs->hls > cdest->hls) cdest->hls = cs->hls; }
static void starpoint( /* pixel is on the star's point */ COLOR fcol, int x, int y, register HOTPIX *hp ) { COLOR ctmp; double d2; d2 = (double)(x - hp->x)*(x - hp->x) + (double)(y - hp->y)*(y - hp->y); if (d2 > sprdfact) { d2 = sprdfact / d2; if (d2 < FTINY) return; copycolor(ctmp, hp->val); scalecolor(ctmp, d2); addcolor(fcol, ctmp); } else if (d2 > FTINY) { addcolor(fcol, hp->val); } }
FormulaParser::FormulaParser(std::string const& descr, FormatFlags flags, AttributeMap const& values, PowerTag* context) : descr(descr) , flags(flags) , values(values) , pos(0) , context(context) { if (!preloaded) { preloaded = true; addcolor("blue"); addcolor("magic", "blue"); addcolor("gray"); addcolor("gold"); addcolor("green"); addcolor("orange"); addcolor("purple"); addcolor("red"); addcolor("white"); addcolor("yellow"); pretags.emplace("/c", "</span>"); pretags.emplace("icon:bullet", "<span class=\"tooltip-icon-bullet\"></span>"); } }
static void getpicture(void) /* load in picture colors */ { COLR *scanln; COLOR pval; int ccount[24]; double d; int y, i; register int x; scanln = (COLR *)malloc(xmax*sizeof(COLR)); if (scanln == NULL) { perror(progname); exit(1); } for (i = 0; i < 24; i++) { setcolor(inpRGB[i], 0., 0., 0.); ccount[i] = 0; } for (y = ymax-1; y >= 0; y--) { if (freadcolrs(scanln, xmax, stdin) < 0) { fprintf(stderr, "%s: error reading input picture\n", progname); exit(1); } for (x = 0; x < xmax; x++) if (chartndx(x, y, &i) == RG_CENT) { colr_color(pval, scanln[x]); addcolor(inpRGB[i], pval); ccount[i]++; } } for (i = 0; i < 24; i++) { /* compute averages */ if (ccount[i] == 0) continue; d = 1./ccount[i]; scalecolor(inpRGB[i], d); inpflags |= 1L<<i; } free((void *)scanln); }
extern void dobox( /* simple box filter */ COLOR csum, int xcent, int ycent, int c, int r ) { int wsum; double d; int y; register int x, offs; register COLOR *scan; wsum = 0; setcolor(csum, 0.0, 0.0, 0.0); for (y = ycent+1-ybrad; y <= ycent+ybrad; y++) { if (y < 0) continue; if (y >= yres) break; d = y_r < 1.0 ? y_r*y - (r+.5) : (double)(y - ycent); if (d < -0.5) continue; if (d >= 0.5) break; scan = scanin[y%barsize]; for (x = xcent+1-xbrad; x <= xcent+xbrad; x++) { offs = x < 0 ? xres : x >= xres ? -xres : 0; if (offs && !wrapfilt) continue; d = x_c < 1.0 ? x_c*x - (c+.5) : (double)(x - xcent); if (d < -0.5) continue; if (d >= 0.5) break; wsum++; addcolor(csum, scan[x+offs]); } } if (wsum > 1) { d = 1.0/wsum; scalecolor(csum, d); } }
void compavg( /* recompute averages */ PNODE *p ) { int i, navg; if (p->kid == NULL) return; setcolor(p->v, .0, .0, .0); navg = 0; for (i = 0; i < 4; i++) { if (p->kid[i].xmin >= p->kid[i].xmax) continue; if (p->kid[i].ymin >= p->kid[i].ymax) continue; compavg(p->kid+i); addcolor(p->v, p->kid[i].v); navg++; } if (navg > 1) scalecolor(p->v, 1./navg); }
extern void dogauss( /* gaussian filter */ COLOR csum, int xcent, int ycent, int c, int r ) { double dy, dx, weight, wsum; COLOR ctmp; int y; register int x, offs; register COLOR *scan; wsum = FTINY; setcolor(csum, 0.0, 0.0, 0.0); for (y = ycent-yrad; y <= ycent+yrad; y++) { if (y < 0) continue; if (y >= yres) break; dy = (y_r*(y+.5) - (r+.5))/rad; scan = scanin[y%barsize]; for (x = xcent-xrad; x <= xcent+xrad; x++) { offs = x < 0 ? xres : x >= xres ? -xres : 0; if (offs && !wrapfilt) continue; dx = (x_c*(x+.5) - (c+.5))/rad; weight = lookgauss(dx*dx + dy*dy); wsum += weight; copycolor(ctmp, scan[x+offs]); scalecolor(ctmp, weight); addcolor(csum, ctmp); } } weight = 1.0/wsum; scalecolor(csum, weight); }
char * material(void) /* get (and print) current material */ { char *mname = "mat"; COLOR radrgb, c2; double d; if (c_cmname != NULL) mname = c_cmname; if (!c_cmaterial->clock) return(mname); /* already current */ /* else update output */ c_cmaterial->clock = 0; if (c_cmaterial->ed > .1) { /* emitter */ cvtcolor(radrgb, &c_cmaterial->ed_c, emult*c_cmaterial->ed/(PI*WHTEFFICACY)); if (glowdist < FHUGE) { /* do a glow */ fprintf(matfp, "\nvoid glow %s\n0\n0\n", mname); fprintf(matfp, "4 %f %f %f %f\n", colval(radrgb,RED), colval(radrgb,GRN), colval(radrgb,BLU), glowdist); } else { fprintf(matfp, "\nvoid light %s\n0\n0\n", mname); fprintf(matfp, "3 %f %f %f\n", colval(radrgb,RED), colval(radrgb,GRN), colval(radrgb,BLU)); } return(mname); } d = c_cmaterial->rd + c_cmaterial->td + c_cmaterial->rs + c_cmaterial->ts; if ((d < 0.) | (d > 1.)) return(NULL); /* check for glass/dielectric */ if (c_cmaterial->nr > 1.1 && c_cmaterial->ts > .25 && c_cmaterial->rs <= .125 && c_cmaterial->td <= .01 && c_cmaterial->rd <= .01 && c_cmaterial->rs_a <= .01 && c_cmaterial->ts_a <= .01) { cvtcolor(radrgb, &c_cmaterial->ts_c, c_cmaterial->ts + c_cmaterial->rs); if (c_cmaterial->sided) { /* dielectric */ colval(radrgb,RED) = pow(colval(radrgb,RED), 1./C_1SIDEDTHICK); colval(radrgb,GRN) = pow(colval(radrgb,GRN), 1./C_1SIDEDTHICK); colval(radrgb,BLU) = pow(colval(radrgb,BLU), 1./C_1SIDEDTHICK); fprintf(matfp, "\nvoid dielectric %s\n0\n0\n", mname); fprintf(matfp, "5 %g %g %g %f 0\n", colval(radrgb,RED), colval(radrgb,GRN), colval(radrgb,BLU), c_cmaterial->nr); return(mname); } /* glass */ fprintf(matfp, "\nvoid glass %s\n0\n0\n", mname); fprintf(matfp, "4 %f %f %f %f\n", colval(radrgb,RED), colval(radrgb,GRN), colval(radrgb,BLU), c_cmaterial->nr); return(mname); } /* check for trans */ if (c_cmaterial->td > .01 || c_cmaterial->ts > .01) { double ts, a5, a6; if (c_cmaterial->sided) { ts = sqrt(c_cmaterial->ts); /* approximate */ a5 = .5; } else { ts = c_cmaterial->ts; a5 = 1.; } /* average colors */ d = c_cmaterial->rd + c_cmaterial->td + ts; cvtcolor(radrgb, &c_cmaterial->rd_c, c_cmaterial->rd/d); cvtcolor(c2, &c_cmaterial->td_c, c_cmaterial->td/d); addcolor(radrgb, c2); cvtcolor(c2, &c_cmaterial->ts_c, ts/d); addcolor(radrgb, c2); if (c_cmaterial->rs + ts > .0001) a5 = (c_cmaterial->rs*c_cmaterial->rs_a + ts*a5*c_cmaterial->ts_a) / (c_cmaterial->rs + ts); a6 = (c_cmaterial->td + ts) / (c_cmaterial->rd + c_cmaterial->td + ts); if (a6 < .999) d = c_cmaterial->rd/(1. - c_cmaterial->rs)/(1. - a6); else d = c_cmaterial->td + ts; scalecolor(radrgb, d); fprintf(matfp, "\nvoid trans %s\n0\n0\n", mname); fprintf(matfp, "7 %f %f %f\n", colval(radrgb,RED), colval(radrgb,GRN), colval(radrgb,BLU)); fprintf(matfp, "\t%f %f %f %f\n", c_cmaterial->rs, a5, a6, ts/(ts + c_cmaterial->td)); return(mname); } /* check for plastic */ if (c_cmaterial->rs < .1) { cvtcolor(radrgb, &c_cmaterial->rd_c, c_cmaterial->rd/(1.-c_cmaterial->rs)); fprintf(matfp, "\nvoid plastic %s\n0\n0\n", mname); fprintf(matfp, "5 %f %f %f %f %f\n", colval(radrgb,RED), colval(radrgb,GRN), colval(radrgb,BLU), c_cmaterial->rs, c_cmaterial->rs_a); return(mname); } /* else it's metal */ /* average colors */ cvtcolor(radrgb, &c_cmaterial->rd_c, c_cmaterial->rd); cvtcolor(c2, &c_cmaterial->rs_c, c_cmaterial->rs); addcolor(radrgb, c2); fprintf(matfp, "\nvoid metal %s\n0\n0\n", mname); fprintf(matfp, "5 %f %f %f %f %f\n", colval(radrgb,RED), colval(radrgb,GRN), colval(radrgb,BLU), c_cmaterial->rs/(c_cmaterial->rd + c_cmaterial->rs), c_cmaterial->rs_a); return(mname); }
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 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 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); }
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 sumans( /* sum input pixel to output */ int px, int py, int rcent, int ccent, double m ) { double dy2, dx; COLOR pval, ctmp; int ksiz, r, offs; double pc, pr, norm; register int i, c; register COLOR *scan; /* * This normalization method fails at the picture borders because * a different number of input pixels contribute there. */ scan = scanin[py%barsize] + (px < 0 ? xres : px >= xres ? -xres : 0); copycolor(pval, scan[px]); pc = x_c*(px+.5); pr = y_r*(py+.5); ksiz = CHECKRAD*m*rad + 1; if (ksiz > orad) ksiz = orad; /* compute normalization */ norm = 0.0; i = 0; for (r = rcent-ksiz; r <= rcent+ksiz; r++) { if (r < 0) continue; if (r >= nrows) break; dy2 = (pr - (r+.5))/(m*rad); dy2 *= dy2; for (c = ccent-ksiz; c <= ccent+ksiz; c++) { if (!wrapfilt) { if (c < 0) continue; if (c >= ncols) break; } dx = (pc - (c+.5))/(m*rad); norm += warr[i++] = lookgauss(dx*dx + dy2); } } norm = 1.0/norm; if (x_c < 1.0) norm *= x_c; if (y_r < 1.0) norm *= y_r; /* sum pixels */ i = 0; for (r = rcent-ksiz; r <= rcent+ksiz; r++) { if (r < 0) continue; if (r >= nrows) break; scan = scoutbar[r%obarsize]; for (c = ccent-ksiz; c <= ccent+ksiz; c++) { offs = c < 0 ? ncols : c >= ncols ? -ncols : 0; if (offs && !wrapfilt) continue; copycolor(ctmp, pval); dx = norm*warr[i++]; scalecolor(ctmp, dx); addcolor(scan[c+offs], ctmp); } } }
void volumePhotonDensity (PhotonMap *pmap, RAY *ray, COLOR irrad) /* Photon volume density estimate. Returns irradiance at ray -> rop. */ { unsigned i; float r2, gecc2, ph; COLOR flux; Photon *photon; const PhotonSearchQueueNode *sqn; setcolor(irrad, 0, 0, 0); if (!pmap -> maxGather) return; findPhotons(pmap, ray); /* Need at least 2 photons */ if (pmap -> squeue.tail < 2) return; #if 0 /* Volume biascomp disabled (probably redundant) */ if (pmap -> minGather == pmap -> maxGather) #endif { /* No bias compensation. Just do a plain vanilla estimate */ gecc2 = ray -> gecc * ray -> gecc; sqn = pmap -> squeue.node + 1; /* Average radius^2 between furthest two photons to improve accuracy */ r2 = max(sqn -> dist2, (sqn + 1) -> dist2); r2 = 0.25 * (pmap -> maxDist2 + r2 + 2 * sqrt(pmap -> maxDist2 * r2)); /* Skip the extra photon */ for (i = 1; i < pmap -> squeue.tail; i++, sqn++) { photon = getNearestPhoton(&pmap -> squeue, sqn -> idx); /* Compute phase function for inscattering from photon */ if (gecc2 <= FTINY) ph = 1; else { ph = DOT(ray -> rdir, photon -> norm) / 127; ph = 1 + gecc2 - 2 * ray -> gecc * ph; ph = (1 - gecc2) / (ph * sqrt(ph)); } getPhotonFlux(photon, flux); scalecolor(flux, ph); addcolor(irrad, flux); } /* Divide by search volume 4 / 3 * PI * r^3 and phase function normalization factor 1 / (4 * PI) */ scalecolor(irrad, 3 / (16 * PI * PI * r2 * sqrt(r2))); return; } #if 0 else /* Apply bias compensation to density estimate */ volumeBiasComp(pmap, ray, irrad); #endif }
static void diraniso( /* compute source contribution */ COLOR cval, /* returned coefficient */ void *nnp, /* material data */ FVECT ldir, /* light source direction */ double omega /* light source size */ ) { ANISODAT *np = nnp; double ldot; double dtmp, dtmp1, dtmp2; FVECT h; double au2, av2; COLOR ctmp; setcolor(cval, 0.0, 0.0, 0.0); ldot = DOT(np->pnorm, ldir); if (ldot < 0.0 ? np->trans <= FTINY : np->trans >= 1.0-FTINY) return; /* wrong side */ if ((ldot > FTINY) & (np->rdiff > FTINY)) { /* * Compute and add diffuse reflected component to returned * color. The diffuse reflected component will always be * modified by the color of the material. */ copycolor(ctmp, np->mcolor); dtmp = ldot * omega * np->rdiff * (1.0/PI); scalecolor(ctmp, dtmp); addcolor(cval, ctmp); } if (ldot > FTINY && np->specfl&SP_REFL) { /* * Compute specular reflection coefficient using * anisotropic Gaussian distribution model. */ /* add source width if flat */ if (np->specfl & SP_FLAT) au2 = av2 = omega * (0.25/PI); else au2 = av2 = 0.0; au2 += np->u_alpha*np->u_alpha; av2 += np->v_alpha*np->v_alpha; /* half vector */ VSUB(h, ldir, np->rp->rdir); /* ellipse */ dtmp1 = DOT(np->u, h); dtmp1 *= dtmp1 / au2; dtmp2 = DOT(np->v, h); dtmp2 *= dtmp2 / av2; /* new W-G-M-D model */ dtmp = DOT(np->pnorm, h); dtmp *= dtmp; dtmp1 = (dtmp1 + dtmp2) / dtmp; dtmp = exp(-dtmp1) * DOT(h,h) / (PI * dtmp*dtmp * sqrt(au2*av2)); /* worth using? */ if (dtmp > FTINY) { copycolor(ctmp, np->scolor); dtmp *= ldot * omega; scalecolor(ctmp, dtmp); addcolor(cval, ctmp); } } if ((ldot < -FTINY) & (np->tdiff > FTINY)) { /* * Compute diffuse transmission. */ copycolor(ctmp, np->mcolor); dtmp = -ldot * omega * np->tdiff * (1.0/PI); scalecolor(ctmp, dtmp); addcolor(cval, ctmp); } if (ldot < -FTINY && np->specfl&SP_TRAN) { /* * Compute specular transmission. Specular transmission * is always modified by material color. */ /* roughness + source */ au2 = av2 = omega * (1.0/PI); au2 += np->u_alpha*np->u_alpha; av2 += np->v_alpha*np->v_alpha; /* "half vector" */ VSUB(h, ldir, np->prdir); dtmp = DOT(h,h); if (dtmp > FTINY*FTINY) { dtmp1 = DOT(h,np->pnorm); dtmp = 1.0 - dtmp1*dtmp1/dtmp; if (dtmp > FTINY*FTINY) { dtmp1 = DOT(h,np->u); dtmp1 *= dtmp1 / au2; dtmp2 = DOT(h,np->v); dtmp2 *= dtmp2 / av2; dtmp = (dtmp1 + dtmp2) / dtmp; } } else dtmp = 0.0; /* Gaussian */ dtmp = exp(-dtmp) * (1.0/PI) * sqrt(-ldot/(np->pdot*au2*av2)); /* worth using? */ if (dtmp > FTINY) { copycolor(ctmp, np->mcolor); dtmp *= np->tspec * omega; scalecolor(ctmp, dtmp); addcolor(cval, ctmp); } } }
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); }
extern double sumambient( /* get interpolated ambient value */ COLOR acol, RAY *r, FVECT rn, int al, AMBTREE *at, FVECT c0, double s ) { double d, e1, e2, wt, wsum; COLOR ct; FVECT ck0; int i; int j; AMBVAL *av; wsum = 0.0; /* do this node */ for (av = at->alist; av != NULL; av = av->next) { double rn_dot = -2.0; if (tracktime) av->latick = ambclock; /* * Ambient level test. */ if (av->lvl > al) /* list sorted, so this works */ break; if (av->weight < 0.9*r->rweight) continue; /* * Ambient radius test. */ VSUB(ck0, av->pos, r->rop); e1 = DOT(ck0, ck0) / (av->rad * av->rad); if (e1 > ambacc*ambacc*1.21) continue; /* * Direction test using closest normal. */ d = DOT(av->dir, r->ron); if (rn != r->ron) { rn_dot = DOT(av->dir, rn); if (rn_dot > 1.0-FTINY) rn_dot = 1.0-FTINY; if (rn_dot >= d-FTINY) { d = rn_dot; rn_dot = -2.0; } } e2 = (1.0 - d) * r->rweight; if (e2 < 0.0) e2 = 0.0; else if (e1 + e2 > ambacc*ambacc*1.21) continue; /* * Ray behind test. */ d = 0.0; for (j = 0; j < 3; j++) d += (r->rop[j] - av->pos[j]) * (av->dir[j] + r->ron[j]); if (d*0.5 < -minarad*ambacc-.001) continue; /* * Jittering final test reduces image artifacts. */ e1 = sqrt(e1); e2 = sqrt(e2); wt = e1 + e2; if (wt > ambacc*(.9+.2*urand(9015+samplendx))) continue; /* * Recompute directional error using perturbed normal */ if (rn_dot > 0.0) { e2 = sqrt((1.0 - rn_dot)*r->rweight); wt = e1 + e2; } if (wt <= 1e-3) wt = 1e3; else wt = 1.0 / wt; wsum += wt; extambient(ct, av, r->rop, rn); scalecolor(ct, wt); addcolor(acol, ct); } if (at->kid == NULL) return(wsum); /* do children */ s *= 0.5; for (i = 0; i < 8; i++) { for (j = 0; j < 3; j++) { ck0[j] = c0[j]; if (1<<j & i) ck0[j] += s; if (r->rop[j] < ck0[j] - OCTSCALE*s) break; if (r->rop[j] > ck0[j] + (1.0+OCTSCALE)*s) break; } if (j == 3) wsum += sumambient(acol, r, rn, al, at->kid+i, ck0, s); } return(wsum); }
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 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 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); }
void photonDensity (PhotonMap *pmap, RAY *ray, COLOR irrad) /* Photon density estimate. Returns irradiance at ray -> rop. */ { unsigned i; float r2; COLOR flux; Photon *photon; const PhotonSearchQueueNode *sqn; setcolor(irrad, 0, 0, 0); if (!pmap -> maxGather) return; /* Ignore sources */ if (ray -> ro && islight(objptr(ray -> ro -> omod) -> otype)) return; findPhotons(pmap, ray); /* Need at least 2 photons */ if (pmap -> squeue.tail < 2) { #ifdef PMAP_NONEFOUND sprintf(errmsg, "no photons found on %s at (%.3f, %.3f, %.3f)", ray -> ro ? ray -> ro -> oname : "<null>", ray -> rop [0], ray -> rop [1], ray -> rop [2]); error(WARNING, errmsg); #endif return; } if (pmap -> minGather == pmap -> maxGather) { /* No bias compensation. Just do a plain vanilla estimate */ sqn = pmap -> squeue.node + 1; /* Average radius^2 between furthest two photons to improve accuracy */ r2 = max(sqn -> dist2, (sqn + 1) -> dist2); r2 = 0.25 * (pmap -> maxDist2 + r2 + 2 * sqrt(pmap -> maxDist2 * r2)); /* Skip the extra photon */ for (i = 1 ; i < pmap -> squeue.tail; i++, sqn++) { photon = getNearestPhoton(&pmap -> squeue, sqn -> idx); getPhotonFlux(photon, flux); #ifdef PMAP_EPANECHNIKOV /* Apply Epanechnikov kernel to photon flux based on photon dist */ scalecolor(flux, 2 * (1 - sqn -> dist2 / r2)); #endif addcolor(irrad, flux); } /* Divide by search area PI * r^2, 1 / PI required as ambient normalisation factor */ scalecolor(irrad, 1 / (PI * PI * r2)); return; } else /* Apply bias compensation to density estimate */ biasComp(pmap, irrad); }
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_brdf2( /* color a ray that hit a BRDF material */ OBJREC *m, RAY *r ) { BRDFDAT nd; COLOR ctmp; FVECT vtmp; double dtmp; /* always a shadow */ if (r->crtype & SHADOW) return(1); /* check arguments */ if ((m->oargs.nsargs < (hasdata(m->otype)?4:2)) | (m->oargs.nfargs < ((m->otype==MAT_TFUNC)|(m->otype==MAT_TDATA)?6:4))) objerror(m, USER, "bad # 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); nd.mp = m; nd.pr = r; /* get material color */ setcolor(nd.mcolor, m->oargs.farg[0], m->oargs.farg[1], m->oargs.farg[2]); /* get specular component */ nd.rspec = m->oargs.farg[3]; /* compute transmittance */ if ((m->otype == MAT_TFUNC) | (m->otype == MAT_TDATA)) { nd.trans = m->oargs.farg[4]*(1.0 - nd.rspec); nd.tspec = nd.trans * m->oargs.farg[5]; dtmp = nd.trans - nd.tspec; setcolor(nd.tdiff, dtmp, dtmp, dtmp); } else { nd.tspec = nd.trans = 0.0; setcolor(nd.tdiff, 0.0, 0.0, 0.0); } /* compute reflectance */ dtmp = 1.0 - nd.trans - nd.rspec; setcolor(nd.rdiff, dtmp, dtmp, dtmp); nd.pdot = raynormal(nd.pnorm, r); /* perturb normal */ multcolor(nd.mcolor, r->pcol); /* modify material color */ multcolor(nd.rdiff, nd.mcolor); multcolor(nd.tdiff, nd.mcolor); /* load auxiliary files */ if (hasdata(m->otype)) { nd.dp = getdata(m->oargs.sarg[1]); getfunc(m, 2, 0, 0); } else { nd.dp = NULL; getfunc(m, 1, 0, 0); } /* compute ambient */ if (nd.trans < 1.0-FTINY) { copycolor(ctmp, nd.mcolor); /* modified by material color */ scalecolor(ctmp, 1.0-nd.trans); multambient(ctmp, r, nd.pnorm); addcolor(r->rcol, ctmp); /* add to returned color */ } if (nd.trans > FTINY) { /* from other side */ flipsurface(r); vtmp[0] = -nd.pnorm[0]; vtmp[1] = -nd.pnorm[1]; vtmp[2] = -nd.pnorm[2]; copycolor(ctmp, nd.mcolor); scalecolor(ctmp, nd.trans); multambient(ctmp, r, vtmp); addcolor(r->rcol, ctmp); flipsurface(r); } /* add direct component */ direct(r, dirbrdf, &nd); return(1); }
static void dirbrdf( /* compute source contribution */ COLOR cval, /* returned coefficient */ void *nnp, /* material data */ FVECT ldir, /* light source direction */ double omega /* light source size */ ) { BRDFDAT *np = nnp; double ldot; double dtmp; COLOR ctmp; FVECT ldx; static double vldx[5], pt[MAXDIM]; char **sa; int i; #define lddx (vldx+1) setcolor(cval, 0.0, 0.0, 0.0); ldot = DOT(np->pnorm, ldir); if (ldot <= FTINY && ldot >= -FTINY) return; /* too close to grazing */ if (ldot < 0.0 ? np->trans <= FTINY : np->trans >= 1.0-FTINY) return; /* wrong side */ if (ldot > 0.0) { /* * Compute and add diffuse reflected component to returned * color. The diffuse reflected component will always be * modified by the color of the material. */ copycolor(ctmp, np->rdiff); dtmp = ldot * omega / PI; scalecolor(ctmp, dtmp); addcolor(cval, ctmp); } else { /* * Diffuse transmitted component. */ copycolor(ctmp, np->tdiff); dtmp = -ldot * omega / PI; scalecolor(ctmp, dtmp); addcolor(cval, ctmp); } if (ldot > 0.0 ? np->rspec <= FTINY : np->tspec <= FTINY) return; /* diffuse only */ /* set up function */ setbrdfunc(np); sa = np->mp->oargs.sarg; errno = 0; /* transform light vector */ multv3(ldx, ldir, funcxf.xfm); for (i = 0; i < 3; i++) lddx[i] = ldx[i]/funcxf.sca; lddx[3] = omega; /* compute BRTDF */ if (np->mp->otype == MAT_BRTDF) { if (sa[6][0] == '0') /* special case */ colval(ctmp,RED) = 0.0; else colval(ctmp,RED) = funvalue(sa[6], 4, lddx); if (sa[7][0] == '0') colval(ctmp,GRN) = 0.0; else if (!strcmp(sa[7],sa[6])) colval(ctmp,GRN) = colval(ctmp,RED); else colval(ctmp,GRN) = funvalue(sa[7], 4, lddx); if (!strcmp(sa[8],sa[6])) colval(ctmp,BLU) = colval(ctmp,RED); else if (!strcmp(sa[8],sa[7])) colval(ctmp,BLU) = colval(ctmp,GRN); else colval(ctmp,BLU) = funvalue(sa[8], 4, lddx); dtmp = bright(ctmp); } else if (np->dp == NULL) { dtmp = funvalue(sa[0], 4, lddx); setcolor(ctmp, dtmp, dtmp, dtmp); } else { for (i = 0; i < np->dp->nd; i++) pt[i] = funvalue(sa[3+i], 4, lddx); vldx[0] = datavalue(np->dp, pt); dtmp = funvalue(sa[0], 5, vldx); setcolor(ctmp, dtmp, dtmp, dtmp); } if ((errno == EDOM) | (errno == ERANGE)) { objerror(np->mp, WARNING, "compute error"); return; } if (dtmp <= FTINY) return; if (ldot > 0.0) { /* * Compute reflected non-diffuse component. */ if ((np->mp->otype == MAT_MFUNC) | (np->mp->otype == MAT_MDATA)) multcolor(ctmp, np->mcolor); dtmp = ldot * omega * np->rspec; scalecolor(ctmp, dtmp); addcolor(cval, ctmp); } else { /* * Compute transmitted non-diffuse component. */ if ((np->mp->otype == MAT_TFUNC) | (np->mp->otype == MAT_TDATA)) multcolor(ctmp, np->mcolor); dtmp = -ldot * omega * np->tspec; scalecolor(ctmp, dtmp); addcolor(cval, ctmp); } #undef lddx }
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); } } }
void buildPhotonMap (PhotonMap *pmap, double *photonFlux, PhotonPrimaryIdx *primaryOfs, unsigned nproc) { unsigned long n, nCheck = 0; unsigned i; Photon *p; COLOR flux; char nuHeapFname [sizeof(PMAP_TMPFNAME)]; FILE *nuHeap; /* Need double here to reduce summation errors */ double avgFlux [3] = {0, 0, 0}, CoG [3] = {0, 0, 0}, CoGdist = 0; FVECT d; if (!pmap) error(INTERNAL, "undefined photon map in buildPhotonMap"); /* Get number of photons from heapfile size */ if (fseek(pmap -> heap, 0, SEEK_END) < 0) error(SYSTEM, "failed seek to end of photon heap in buildPhotonMap"); pmap -> numPhotons = ftell(pmap -> heap) / sizeof(Photon); if (!pmap -> numPhotons) error(INTERNAL, "empty photon map in buildPhotonMap"); if (!pmap -> heap) error(INTERNAL, "no heap in buildPhotonMap"); #ifdef DEBUG_PMAP eputs("Checking photon heap consistency...\n"); checkPhotonHeap(pmap -> heap); sprintf(errmsg, "Heap contains %ld photons\n", pmap -> numPhotons); eputs(errmsg); #endif /* Allocate heap buffa */ if (!pmap -> heapBuf) { pmap -> heapBufSize = PMAP_HEAPBUFSIZE; pmap -> heapBuf = calloc(pmap -> heapBufSize, sizeof(Photon)); if (!pmap -> heapBuf) error(SYSTEM, "failed to allocate postprocessed photon heap in" "buildPhotonMap"); } /* We REALLY don't need yet another @%&*! heap just to hold the scaled * photons, but can't think of a quicker fix... */ mktemp(strcpy(nuHeapFname, PMAP_TMPFNAME)); if (!(nuHeap = fopen(nuHeapFname, "w+b"))) error(SYSTEM, "failed to open postprocessed photon heap in " "buildPhotonMap"); rewind(pmap -> heap); #ifdef DEBUG_PMAP eputs("Postprocessing photons...\n"); #endif while (!feof(pmap -> heap)) { #ifdef DEBUG_PMAP printf("Reading %lu at %lu... ", pmap -> heapBufSize, ftell(pmap->heap)); #endif pmap -> heapBufLen = fread(pmap -> heapBuf, sizeof(Photon), pmap -> heapBufSize, pmap -> heap); #ifdef DEBUG_PMAP printf("Got %lu\n", pmap -> heapBufLen); #endif if (ferror(pmap -> heap)) error(SYSTEM, "failed to read photon heap in buildPhotonMap"); for (n = pmap -> heapBufLen, p = pmap -> heapBuf; n; n--, p++) { /* Update min and max pos and set photon flux */ for (i = 0; i <= 2; i++) { if (p -> pos [i] < pmap -> minPos [i]) pmap -> minPos [i] = p -> pos [i]; else if (p -> pos [i] > pmap -> maxPos [i]) pmap -> maxPos [i] = p -> pos [i]; /* Update centre of gravity with photon position */ CoG [i] += p -> pos [i]; } if (primaryOfs) /* Linearise photon primary index from subprocess index using the * per-subprocess offsets in primaryOfs */ p -> primary += primaryOfs [p -> proc]; /* Scale photon's flux (hitherto normalised to 1 over RGB); in * case of a contrib photon map, this is done per light source, * and photonFlux is assumed to be an array */ getPhotonFlux(p, flux); if (photonFlux) { scalecolor(flux, photonFlux [isContribPmap(pmap) ? photonSrcIdx(pmap, p) : 0]); setPhotonFlux(p, flux); } /* Update average photon flux; need a double here */ addcolor(avgFlux, flux); } /* Write modified photons to new heap */ fwrite(pmap -> heapBuf, sizeof(Photon), pmap -> heapBufLen, nuHeap); if (ferror(nuHeap)) error(SYSTEM, "failed postprocessing photon flux in " "buildPhotonMap"); nCheck += pmap -> heapBufLen; } #ifdef DEBUG_PMAP if (nCheck < pmap -> numPhotons) error(INTERNAL, "truncated photon heap in buildPhotonMap"); #endif /* Finalise average photon flux */ scalecolor(avgFlux, 1.0 / pmap -> numPhotons); copycolor(pmap -> photonFlux, avgFlux); /* Average photon positions to get centre of gravity */ for (i = 0; i < 3; i++) pmap -> CoG [i] = CoG [i] /= pmap -> numPhotons; rewind(pmap -> heap); /* Compute average photon distance to centre of gravity */ while (!feof(pmap -> heap)) { pmap -> heapBufLen = fread(pmap -> heapBuf, sizeof(Photon), pmap -> heapBufSize, pmap -> heap); for (n = pmap -> heapBufLen, p = pmap -> heapBuf; n; n--, p++) { VSUB(d, p -> pos, CoG); CoGdist += DOT(d, d); } } pmap -> CoGdist = CoGdist /= pmap -> numPhotons; /* Swap heaps, discarding unscaled photons */ fclose(pmap -> heap); unlink(pmap -> heapFname); pmap -> heap = nuHeap; strcpy(pmap -> heapFname, nuHeapFname); #ifdef PMAP_OOC OOC_BuildPhotonMap(pmap, nproc); #else kdT_BuildPhotonMap(pmap); #endif /* Trash heap and its buffa */ free(pmap -> heapBuf); fclose(pmap -> heap); unlink(pmap -> heapFname); pmap -> heap = NULL; pmap -> heapBuf = NULL; }