int m_aniso( /* anisotropic material */ register OBJREC *o ) { register MATREC *m; /* check arguments */ if (o->oargs.nfargs < (o->otype == MAT_TRANS2 ? 8 : 6)) objerror(o, USER, "bad # of real arguments"); /* allocate/insert material */ m = newmaterial(o->oname); /* assign parameters */ setcolor(m->u.m.ambdiff, o->oargs.farg[0], o->oargs.farg[1], o->oargs.farg[2]); if ((m->type = o->otype) == MAT_METAL2) copycolor(m->u.m.specular, m->u.m.ambdiff); else setcolor(m->u.m.specular, 1., 1., 1.); scalecolor(m->u.m.specular, o->oargs.farg[3]); scalecolor(m->u.m.ambdiff, 1.-o->oargs.farg[3]); if (m->type == MAT_TRANS2) { scalecolor(m->u.m.specular, 1.-o->oargs.farg[6]); scalecolor(m->u.m.ambdiff, 1.-o->oargs.farg[6]); } if (o->oargs.farg[4]*o->oargs.farg[5] <= FTINY*FTINY) m->u.m.specexp = MAXSPECEXP; else m->u.m.specexp = 2./(o->oargs.farg[4]*o->oargs.farg[5]); if (m->u.m.specexp > MAXSPECEXP) m->u.m.specexp = MAXSPECEXP; return(0); }
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 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); } } }
extern void extambient( /* extrapolate value at pv, nv */ COLOR cr, AMBVAL *ap, FVECT pv, FVECT nv ) { FVECT v1; int i; double d; d = 1.0; /* zeroeth order */ /* gradient due to translation */ for (i = 0; i < 3; i++) d += ap->gpos[i]*(pv[i]-ap->pos[i]); /* gradient due to rotation */ VCROSS(v1, ap->dir, nv); d += DOT(ap->gdir, v1); if (d <= 0.0) { setcolor(cr, 0.0, 0.0, 0.0); return; } copycolor(cr, ap->val); scalecolor(cr, d); }
static void init(void) /* initialize */ { double quad[4][2]; register int i; /* make coordinate transformation */ quad[0][0] = bounds[0][0]; quad[0][1] = bounds[0][1]; quad[1][0] = bounds[1][0]; quad[1][1] = bounds[1][1]; quad[2][0] = bounds[3][0]; quad[2][1] = bounds[3][1]; quad[3][0] = bounds[2][0]; quad[3][1] = bounds[2][1]; if (pmap_quad_rect(0., 0., 6., 4., quad, imgxfm) == PMAP_BAD) { fprintf(stderr, "%s: bad chart boundaries\n", progname); exit(1); } /* map MacBeth colors to RGB space */ for (i = 0; i < 24; i++) { xyY2RGB(mbRGB[i], mbxyY[i]); scalecolor(mbRGB[i], irrad); } }
static int checkhead( /* deal with line from header */ char *line, void *p ) { char fmt[32]; double d; COLOR ctmp; if (formatval(fmt, line)) { if (!strcmp(fmt, CIEFMT)) mybright = &xyz_bright; else if (!strcmp(fmt, COLRFMT)) mybright = &rgb_bright; else wrongformat++; } else if (original && isexpos(line)) { d = 1.0/exposval(line); scalecolor(exposure, d); doexposure++; } else if (original && iscolcor(line)) { colcorval(ctmp, line); setcolor(exposure, colval(exposure,RED)/colval(ctmp,RED), colval(exposure,GRN)/colval(ctmp,GRN), colval(exposure,BLU)/colval(ctmp,BLU)); doexposure++; } else if (header) fputs(line, stdout); return(0); }
static void ppm2ra2( /* convert 2-byte Pixmap to Radiance picture */ colorscanf_t *getscan ) { COLOR *scanout; double mult; int y; register int x; /* allocate scanline */ scanout = (COLOR *)malloc(xmax*sizeof(COLOR)); if (scanout == NULL) quiterr("out of memory in ppm2ra2"); if (bradj) mult = pow(2., (double)bradj); /* convert image */ for (y = ymax-1; y >= 0; y--) { if ((*getscan)(scanout, xmax, stdin) < 0) quiterr("error reading Pixmap"); for (x = (gamcor>1.01)|(gamcor<0.99)?xmax:0; x--; ) { colval(scanout[x],RED) = pow(colval(scanout[x],RED), gamcor); colval(scanout[x],GRN) = pow(colval(scanout[x],GRN), gamcor); colval(scanout[x],BLU) = pow(colval(scanout[x],BLU), gamcor); } for (x = bradj?xmax:0; x--; ) scalecolor(scanout[x], mult); if (fwritescan(scanout, xmax, stdout) < 0) quiterr("error writing Radiance picture"); } /* free scanline */ free((void *)scanout); }
static AMBHEMI * samp_hemi( /* sample indirect hemisphere */ COLOR rcol, RAY *r, double wt ) { AMBHEMI *hp; double d; int n, i, j; /* insignificance check */ if (bright(rcol) <= FTINY) return(NULL); /* set number of divisions */ if (ambacc <= FTINY && wt > (d = 0.8*intens(rcol)*r->rweight/(ambdiv*minweight))) wt = d; /* avoid ray termination */ n = sqrt(ambdiv * wt) + 0.5; i = 1 + 5*(ambacc > FTINY); /* minimum number of samples */ if (n < i) n = i; /* allocate sampling array */ hp = (AMBHEMI *)malloc(sizeof(AMBHEMI) + sizeof(AMBSAMP)*(n*n - 1)); if (hp == NULL) error(SYSTEM, "out of memory in samp_hemi"); hp->rp = r; hp->ns = n; hp->acol[RED] = hp->acol[GRN] = hp->acol[BLU] = 0.0; memset(hp->sa, 0, sizeof(AMBSAMP)*n*n); hp->sampOK = 0; /* assign coefficient */ copycolor(hp->acoef, rcol); d = 1.0/(n*n); scalecolor(hp->acoef, d); /* make tangent plane axes */ if (!getperpendicular(hp->ux, r->ron, 1)) error(CONSISTENCY, "bad ray direction in samp_hemi"); VCROSS(hp->uy, r->ron, hp->ux); /* sample divisions */ for (i = hp->ns; i--; ) for (j = hp->ns; j--; ) hp->sampOK += ambsample(hp, i, j, 0); copycolor(rcol, hp->acol); if (!hp->sampOK) { /* utter failure? */ free(hp); return(NULL); } if (hp->sampOK < hp->ns*hp->ns) { hp->sampOK *= -1; /* soft failure */ return(hp); } if (hp->sampOK < 64) return(hp); /* insufficient for super-sampling */ n = ambssamp*wt + 0.5; if (n > 8) { /* perform super-sampling? */ ambsupersamp(hp, n); copycolor(rcol, hp->acol); } return(hp); /* all is well */ }
/* Put out ray contribution to file */ static void put_contrib(const DCOLOR cnt, FILE *fout) { double sf = 1; COLOR fv; COLR cv; if (accumulate > 1) sf = 1./(double)accumulate; switch (outfmt) { case 'a': if (accumulate > 1) fprintf(fout, "%.6e\t%.6e\t%.6e\t", sf*cnt[0], sf*cnt[1], sf*cnt[2]); else fprintf(fout, "%.6e\t%.6e\t%.6e\t", cnt[0], cnt[1], cnt[2]); break; case 'f': if (accumulate > 1) { copycolor(fv, cnt); scalecolor(fv, sf); } else copycolor(fv, cnt); fwrite(fv, sizeof(float), 3, fout); break; case 'd': if (accumulate > 1) { DCOLOR dv; copycolor(dv, cnt); scalecolor(dv, sf); fwrite(dv, sizeof(double), 3, fout); } else fwrite(cnt, sizeof(double), 3, fout); break; case 'c': if (accumulate > 1) setcolr(cv, sf*cnt[0], sf*cnt[1], sf*cnt[2]); else setcolr(cv, cnt[0], cnt[1], cnt[2]); fwrite(cv, sizeof(cv), 1, fout); break; default: error(INTERNAL, "botched output format"); } }
static void sfscan( /* apply scalefactor to scanline */ register COLOR *sl, int len, double sf ) { while (len--) { scalecolor(sl[0], sf); sl++; } }
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); }
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); }
extern void pass2init(void) /* prepare for final pass */ { if (!npix) { fprintf(stderr, "%s: picture too dark or too bright\n", progname); quit(1); } avgbrt /= (double)npix; scalecolor(exposure, AVGLVL/avgbrt); sprdfact = spread / (hotlvl * (*ourbright)(exposure)) * ((double)xres*xres + (double)yres*yres) / 4.0; }
void scalepict( /* scale picture values */ PNODE *p, double sf ) { scalecolor(p->v, sf); /* do this node */ if (p->kid == NULL) return; /* do children */ scalepict(p->kid+DL, sf); scalepict(p->kid+DR, sf); scalepict(p->kid+UL, sf); scalepict(p->kid+UR, sf); }
int waitrays(void) /* finish up pending rays */ { int nwaited = 0; int rval; RAY raydone; if (!ray_pnprocs) /* immediate mode? */ return(0); while ((rval = ray_presult(&raydone, 0)) > 0) { PNODE *p = (PNODE *)raydone.rno; copycolor(p->v, raydone.rcol); scalecolor(p->v, exposure); recolor(p); nwaited++; } if (rval < 0) return(-1); return(nwaited); }
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 mapscan( /* apply tone mapping operator to scanline */ COLOR *scan, int xres ) { double mult, Lw, b; register int x; for (x = 0; x < xres; x++) { Lw = plum(scan[x]); if (Lw < LMIN) { setcolor(scan[x], 0., 0., 0.); continue; } b = BLw(Lw); /* apply brightness mapping */ mult = (Lb(b) - ldmin)/(ldmax - ldmin)/(Lw*inpexp); if (lumf == rgblum) mult *= WHTEFFICACY; scalecolor(scan[x], mult); } }
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); } }
extern int p_bfunc( /* compute brightness pattern */ OBJREC *m, RAY *r ) { double bval; register MFUNC *mf; if (m->oargs.nsargs < 2) objerror(m, USER, "bad # arguments"); mf = getfunc(m, 1, 0x1, 0); setfunc(m, r); errno = 0; bval = evalue(mf->ep[0]); if (errno == EDOM || errno == ERANGE) { objerror(m, WARNING, "compute error"); return(0); } scalecolor(r->pcol, bval); return(0); }
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 double makeambient( /* make a new ambient value for storage */ COLOR acol, RAY *r, FVECT rn, int al ) { AMBVAL amb; FVECT gp, gd; int i; amb.weight = 1.0; /* compute weight */ for (i = al; i-- > 0; ) amb.weight *= AVGREFL; if (r->rweight < 0.1*amb.weight) /* heuristic override */ amb.weight = 1.25*r->rweight; setcolor(acol, AVGREFL, AVGREFL, AVGREFL); /* compute ambient */ amb.rad = doambient(acol, r, amb.weight, gp, gd); if (amb.rad <= FTINY) { setcolor(acol, 0.0, 0.0, 0.0); return(0.0); } scalecolor(acol, 1./AVGREFL); /* undo assumed reflectance */ /* store value */ VCOPY(amb.pos, r->rop); VCOPY(amb.dir, r->ron); amb.lvl = al; copycolor(amb.val, acol); VCOPY(amb.gpos, gp); VCOPY(amb.gdir, gd); /* insert into tree */ avsave(&amb); /* and save to file */ if (rn != r->ron) extambient(acol, &amb, r->rop, rn); /* texture */ return(amb.rad); }
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); } }
static int headline( /* check header line & echo if requested */ char *s, void *p ) { char fmt[32]; double d; COLOR ctmp; if (isheadid(s)) /* header id */ return(0); /* don't echo */ if (formatval(fmt, s)) { /* check format */ if (globmatch(ourfmt, fmt)) { wrongformat = 0; strcpy(ourfmt, fmt); } else wrongformat = globmatch(PICFMT, fmt) ? 1 : -1; return(0); /* don't echo */ } if (isexpos(s)) { /* exposure */ d = exposval(s); scalecolor(input[nfiles].expos, d); } else if (iscolcor(s)) { /* color correction */ colcorval(ctmp, s); multcolor(input[nfiles].expos, ctmp); } else if (isaspect(s)) input[nfiles].pa *= aspectval(s); else if (isview(s) && sscanview(&input[nfiles].vw, s) > 0) gotview++; if (echoheader) { /* echo line */ putchar('\t'); return(fputs(s, stdout)); } return(0); }
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 }
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); }
static int ambsample( /* initial ambient division sample */ AMBHEMI *hp, int i, int j, int n ) { AMBSAMP *ap = &ambsam(hp,i,j); RAY ar; int hlist[3], ii; double spt[2], zd; /* generate hemispherical sample */ /* ambient coefficient for weight */ if (ambacc > FTINY) setcolor(ar.rcoef, AVGREFL, AVGREFL, AVGREFL); else copycolor(ar.rcoef, hp->acoef); if (rayorigin(&ar, AMBIENT, hp->rp, ar.rcoef) < 0) return(0); if (ambacc > FTINY) { multcolor(ar.rcoef, hp->acoef); scalecolor(ar.rcoef, 1./AVGREFL); } hlist[0] = hp->rp->rno; hlist[1] = j; hlist[2] = i; multisamp(spt, 2, urand(ilhash(hlist,3)+n)); resample: SDsquare2disk(spt, (j+spt[1])/hp->ns, (i+spt[0])/hp->ns); zd = sqrt(1. - spt[0]*spt[0] - spt[1]*spt[1]); for (ii = 3; ii--; ) ar.rdir[ii] = spt[0]*hp->ux[ii] + spt[1]*hp->uy[ii] + zd*hp->rp->ron[ii]; checknorm(ar.rdir); /* avoid coincident samples */ if (!n && ambcollision(hp, i, j, ar.rdir)) { spt[0] = frandom(); spt[1] = frandom(); goto resample; /* reject this sample */ } dimlist[ndims++] = AI(hp,i,j) + 90171; rayvalue(&ar); /* evaluate ray */ ndims--; zd = raydistance(&ar); if (zd <= FTINY) return(0); /* should never happen */ multcolor(ar.rcol, ar.rcoef); /* apply coefficient */ if (zd*ap->d < 1.0) /* new/closer distance? */ ap->d = 1.0/zd; if (!n) { /* record first vertex & value */ if (zd > 10.0*thescene.cusize + 1000.) zd = 10.0*thescene.cusize + 1000.; VSUM(ap->p, ar.rorg, ar.rdir, zd); copycolor(ap->v, ar.rcol); } else { /* else update recorded value */ hp->acol[RED] -= colval(ap->v,RED); hp->acol[GRN] -= colval(ap->v,GRN); hp->acol[BLU] -= colval(ap->v,BLU); zd = 1.0/(double)(n+1); scalecolor(ar.rcol, zd); zd *= (double)n; scalecolor(ap->v, zd); addcolor(ap->v, ar.rcol); } addcolor(hp->acol, ap->v); /* add to our sum */ return(1); }
int main( int argc, char **argv ) { double d, expval = 1.0; int i; progname = argv[0]; mybright = &rgb_bright; /* default */ for (i = 1; i < argc; i++) if (argv[i][0] == '-' || argv[i][0] == '+') switch (argv[i][1]) { case 'h': /* header */ header = argv[i][0] == '+'; break; case 'H': /* resolution string */ resolution = argv[i][0] == '+'; break; case 's': /* skip bytes in header */ skipbytes = atol(argv[++i]); break; case 'u': /* unique values */ uniq = argv[i][0] == '-'; break; case 'o': /* original values */ original = argv[i][0] == '-'; break; case 'g': /* gamma correction */ gamcor = atof(argv[i+1]); if (argv[i][0] == '+') gamcor = 1.0/gamcor; i++; break; case 'e': /* exposure correction */ d = atof(argv[i+1]); if (argv[i+1][0] == '-' || argv[i+1][0] == '+') d = pow(2.0, d); if (argv[i][0] == '-') expval *= d; scalecolor(exposure, d); doexposure++; i++; break; case 'R': /* reverse byte sequence */ if (argv[i][0] == '-') { ord[0]=BLU; ord[1]=GRN; ord[2]=RED; } else { ord[0]=RED; ord[1]=GRN; ord[2]=BLU; } break; case 'r': /* reverse conversion */ reverse = argv[i][0] == '-'; break; case 'n': /* non-interleaved RGB */ interleave = argv[i][0] == '+'; break; case 'b': /* brightness values */ putprim = argv[i][0] == '-' ? BRIGHT : ALL; break; case 'p': /* primary controls */ switch (argv[i][2]) { /* these two options affect -r conversion */ case '\0': myprims[RED][CIEX] = atof(argv[++i]); myprims[RED][CIEY] = atof(argv[++i]); myprims[GRN][CIEX] = atof(argv[++i]); myprims[GRN][CIEY] = atof(argv[++i]); myprims[BLU][CIEX] = atof(argv[++i]); myprims[BLU][CIEY] = atof(argv[++i]); myprims[WHT][CIEX] = atof(argv[++i]); myprims[WHT][CIEY] = atof(argv[++i]); outprims = myprims; break; case 'x': case 'X': outprims = NULL; break; /* the following options affect +r only */ case 'r': case 'R': putprim = RED; break; case 'g': case 'G': putprim = GRN; break; case 'b': case 'B': putprim = BLU; break; default: goto unkopt; } break; case 'd': /* data only (no indices) */ dataonly = argv[i][0] == '-'; switch (argv[i][2]) { case '\0': case 'a': /* ascii */ format = 'a'; fmtid = "ascii"; break; case 'i': /* integer */ format = 'i'; fmtid = "ascii"; break; case 'b': /* byte */ dataonly = 1; format = 'b'; fmtid = "byte"; break; case 'W': /* 16-bit swapped */ swapbytes = 1; case 'w': /* 16-bit */ dataonly = 1; format = 'w'; fmtid = "16-bit"; break; case 'F': /* swapped floats */ swapbytes = 1; case 'f': /* float */ dataonly = 1; format = 'f'; fmtid = "float"; break; case 'D': /* swapped doubles */ swapbytes = 1; case 'd': /* double */ dataonly = 1; format = 'd'; fmtid = "double"; break; default: goto unkopt; } break; case 'x': /* x resolution */ case 'X': /* x resolution */ resolution = 0; if (argv[i][0] == '-') picres.rt |= XDECR; picres.xr = atoi(argv[++i]); break; case 'y': /* y resolution */ case 'Y': /* y resolution */ resolution = 0; if (argv[i][0] == '-') picres.rt |= YDECR; if (picres.xr == 0) picres.rt |= YMAJOR; picres.yr = atoi(argv[++i]); break; default: unkopt: fprintf(stderr, "%s: unknown option: %s\n", progname, argv[i]); quit(1); break; } else break; /* recognize special formats */ if (dataonly && format == 'b') { if (putprim == ALL) fmtid = "24-bit_rgb"; else fmtid = "8-bit_grey"; } if (dataonly && format == 'w') { if (putprim == ALL) fmtid = "48-bit_rgb"; else fmtid = "16-bit_grey"; } /* assign reverse ordering */ rord[ord[0]] = 0; rord[ord[1]] = 1; rord[ord[2]] = 2; /* get input */ if (i == argc) { fin = stdin; } else if (i < argc) { if ((fin = fopen(argv[i], "r")) == NULL) { fprintf(stderr, "%s: can't open file \"%s\"\n", progname, argv[i]); quit(1); } if (reverse && putprim != BRIGHT && i == argc-3) { if ((fin2 = fopen(argv[i+1], "r")) == NULL) { fprintf(stderr, "%s: can't open file \"%s\"\n", progname, argv[i+1]); quit(1); } if ((fin3 = fopen(argv[i+2], "r")) == NULL) { fprintf(stderr, "%s: can't open file \"%s\"\n", progname, argv[i+2]); quit(1); } interleave = -1; } else if (i != argc-1) fin = NULL; if (reverse && putprim != BRIGHT && !interleave) { fin2 = fopen(argv[i], "r"); fin3 = fopen(argv[i], "r"); } if (skipbytes && (fseek(fin, skipbytes, 0) || (fin2 != NULL && (fseek(fin2, skipbytes, 0) || fseek(fin3, skipbytes, 0))))) { fprintf(stderr, "%s: cannot skip %ld bytes on input\n", progname, skipbytes); quit(1); } } if (fin == NULL) { fprintf(stderr, "%s: bad # file arguments\n", progname); quit(1); } if (reverse) { #ifdef _WIN32 SET_FILE_BINARY(stdout); if (format != 'a' && format != 'i') SET_FILE_BINARY(fin); #endif /* get header */ if (header) { if (checkheader(fin, fmtid, stdout) < 0) { fprintf(stderr, "%s: wrong input format\n", progname); quit(1); } if (fin2 != NULL) { getheader(fin2, NULL, NULL); getheader(fin3, NULL, NULL); } } else newheader("RADIANCE", stdout); /* get resolution */ if ((resolution && !fgetsresolu(&picres, fin)) || picres.xr <= 0 || picres.yr <= 0) { fprintf(stderr, "%s: missing resolution\n", progname); quit(1); } if (resolution && fin2 != NULL) { RESOLU pres2; if (!fgetsresolu(&pres2, fin2) || pres2.rt != picres.rt || pres2.xr != picres.xr || pres2.yr != picres.yr || !fgetsresolu(&pres2, fin3) || pres2.rt != picres.rt || pres2.xr != picres.xr || pres2.yr != picres.yr) { fprintf(stderr, "%s: resolution mismatch\n", progname); quit(1); } } /* add to header */ printargs(i, argv, stdout); if (expval < .99 || expval > 1.01) fputexpos(expval, stdout); if (outprims != NULL) { if (outprims != stdprims) fputprims(outprims, stdout); fputformat(COLRFMT, stdout); } else /* XYZ data */ fputformat(CIEFMT, stdout); putchar('\n'); fputsresolu(&picres, stdout); /* always put resolution */ valtopix(); } else { #ifdef _WIN32 SET_FILE_BINARY(fin); if (format != 'a' && format != 'i') SET_FILE_BINARY(stdout); #endif /* get header */ getheader(fin, checkhead, NULL); if (wrongformat) { fprintf(stderr, "%s: input not a Radiance RGBE picture\n", progname); quit(1); } if (!fgetsresolu(&picres, fin)) { fprintf(stderr, "%s: missing resolution\n", progname); quit(1); } if (header) { printargs(i, argv, stdout); if (expval < .99 || expval > 1.01) fputexpos(expval, stdout); fputformat(fmtid, stdout); putchar('\n'); } if (resolution) /* put resolution */ fputsresolu(&picres, stdout); pixtoval(); } quit(0); return 0; /* pro forma return */ }
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); }
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); }