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++; }
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); }