static int lambda( /* compute lambda for material */ OBJREC *m, FVECT v2, FVECT dv, FVECT lr ) { FVECT lrXdv, v2Xlr; double dtmp, denom; int i; fcross(lrXdv, lr, dv); for (i = 0; i < 3; i++) if ((lrXdv[i] > FTINY) | (lrXdv[i] < -FTINY)) break; if (i >= 3) return(-1); fcross(v2Xlr, v2, lr); dtmp = m->oargs.farg[4] / MLAMBDA; denom = dtmp + v2Xlr[i]/lrXdv[i] * (m->oargs.farg[3] + dtmp); if (denom < FTINY) return(-1); return(m->oargs.farg[4] / denom); }
static void getacoords_as( /* set up coordinate system */ ASHIKDAT *np ) { MFUNC *mf; int i; mf = getfunc(np->mp, 3, 0x7, 1); setfunc(np->mp, np->rp); errno = 0; for (i = 0; i < 3; i++) np->u[i] = evalue(mf->ep[i]); if ((errno == EDOM) | (errno == ERANGE)) { objerror(np->mp, WARNING, "compute error"); np->specfl |= SPA_BADU; return; } if (mf->fxp != &unitxf) multv3(np->u, np->u, mf->fxp->xfm); fcross(np->v, np->pnorm, np->u); if (normalize(np->v) == 0.0) { objerror(np->mp, WARNING, "illegal orientation vector"); np->specfl |= SPA_BADU; return; } fcross(np->u, np->v, np->pnorm); }
static void getacoords( /* set up coordinate system */ ANISODAT *np ) { MFUNC *mf; int i; mf = getfunc(np->mp, 3, 0x7, 1); setfunc(np->mp, np->rp); errno = 0; for (i = 0; i < 3; i++) np->u[i] = evalue(mf->ep[i]); if ((errno == EDOM) | (errno == ERANGE)) np->u[0] = np->u[1] = np->u[2] = 0.0; if (mf->fxp != &unitxf) multv3(np->u, np->u, mf->fxp->xfm); fcross(np->v, np->pnorm, np->u); if (normalize(np->v) == 0.0) { if (fabs(np->u_alpha - np->v_alpha) > 0.001) objerror(np->mp, WARNING, "illegal orientation vector"); getperpendicular(np->u, np->pnorm); /* punting */ fcross(np->v, np->pnorm, np->u); np->u_alpha = np->v_alpha = sqrt( 0.5 * (np->u_alpha*np->u_alpha + np->v_alpha*np->v_alpha) ); } else fcross(np->u, np->v, np->pnorm); }
/* Compute World->BSDF transform from surface normal and up (Y) vector */ SDError SDcompXform(RREAL vMtx[3][3], const FVECT sNrm, const FVECT uVec) { if ((vMtx == NULL) | (sNrm == NULL) | (uVec == NULL)) return SDEargument; VCOPY(vMtx[2], sNrm); if (normalize(vMtx[2]) == 0) return SDEargument; fcross(vMtx[0], uVec, vMtx[2]); if (normalize(vMtx[0]) == 0) return SDEargument; fcross(vMtx[1], vMtx[2], vMtx[0]); return SDEnone; }
static void circle( /* indicate a solid angle on image */ FVECT dir, double dom ) { FVECT start, cur; XPoint pt[NSEG+1]; FVECT pp; int ip[2]; register int i; fcross(cur, dir, ourview.vup); if (normalize(cur) == 0.0) goto fail; spinvector(start, dir, cur, acos(1.-dom/(2.*PI))); for (i = 0; i <= NSEG; i++) { spinvector(cur, start, dir, 2.*PI*i/NSEG); cur[0] += ourview.vp[0]; cur[1] += ourview.vp[1]; cur[2] += ourview.vp[2]; viewloc(pp, &ourview, cur); if (pp[2] <= 0.0) goto fail; loc2pix(ip, &pres, pp[0], pp[1]); pt[i].x = ip[0]; pt[i].y = ip[1]; } XDrawLines(theDisplay, gwind, vecGC, pt, NSEG+1, CoordModeOrigin); return; fail: fprintf(stderr, "%s: cannot draw source at (%f,%f,%f)\n", progname, dir[0], dir[1], dir[2]); }
int nonplanar( /* are vertices non-planar? */ int ac, char **av ) { VNDX vi; RREAL *p0, *p1; FVECT v1, v2, nsum, newn; double d; int i; if (!cvtndx(vi, av[0])) return(0); if (!flatten && vi[2] >= 0) return(1); /* has interpolated normals */ if (ac < 4) return(0); /* it's a triangle! */ /* set up */ p0 = vlist[vi[0]]; if (!cvtndx(vi, av[1])) return(0); /* error gets caught later */ nsum[0] = nsum[1] = nsum[2] = 0.; p1 = vlist[vi[0]]; fvsum(v2, p1, p0, -1.0); for (i = 2; i < ac; i++) { VCOPY(v1, v2); if (!cvtndx(vi, av[i])) return(0); p1 = vlist[vi[0]]; fvsum(v2, p1, p0, -1.0); fcross(newn, v1, v2); if (normalize(newn) == 0.0) { if (i < 3) return(1); /* can't deal with this */ fvsum(nsum, nsum, nsum, 1./(i-2)); continue; } d = fdot(newn,nsum); if (d >= 0) { if (d < (1.0-FTINY)*(i-2)) return(1); fvsum(nsum, nsum, newn, 1.0); } else { if (d > -(1.0-FTINY)*(i-2)) return(1); fvsum(nsum, nsum, newn, -1.0); } } return(0); }
static double l_psize(char *nm) /* compute pixel size in steradians */ { static unsigned long ltick[MAXINP]; static double psize[MAXINP]; FVECT dir0, org, dirx, diry; RREAL locx[2], locy[2]; double d; int fn; register int i; d = argument(1); if (d <= -0.5 || d >= nfiles+0.5) { errno = EDOM; return(0.0); } if (d < 0.5) return((double)nfiles); fn = d - 0.5; if (ltick[fn] != eclock) { /* need to compute? */ psize[fn] = 0.0; if (input[fn].vw.type == 0) errno = EDOM; else if (input[fn].vw.type != VT_PAR && funvalue(vray[6], 1, &d) >= -FTINY) { for (i = 0; i < 3; i++) dir0[i] = funvalue(vray[3+i], 1, &d); pix2loc(locx, &input[fn].rs, xscan+1, ymax-1-yscan); pix2loc(locy, &input[fn].rs, xscan, ymax-yscan); if (viewray(org, dirx, &input[fn].vw, locx[0], locx[1]) >= -FTINY && viewray(org, diry, &input[fn].vw, locy[0], locy[1]) >= -FTINY) { /* approximate solid angle */ for (i = 0; i < 3; i++) { dirx[i] -= dir0[i]; diry[i] -= dir0[i]; } fcross(dir0, dirx, diry); psize[fn] = VLEN(dir0); } } ltick[fn] = eclock; } return(psize[fn]); }
static void add_holo( /* register a new holodeck section */ HDGRID *hdg, char *gfn, char *pfn ) { VIEW nv; double d; register int hd; for (hd = 0; hd < HDMAX && hdlist[hd] != NULL; hd++) ; if (hd >= HDMAX) error(INTERNAL, "too many holodeck sections in add_holo"); hdlist[hd] = (HOLO *)malloc(sizeof(HOLO)); if (hdlist[hd] == NULL) error(SYSTEM, "out of memory in add_holo"); memcpy((void *)hdlist[hd], (void *)hdg, sizeof(HDGRID)); hdcompgrid(hdlist[hd]); hdgfn[hd] = savestr(gfn); hdpfn[hd] = pfn && *pfn ? savestr(pfn) : (char *)NULL; if (hd) return; /* set initial viewpoint */ nv = odev.v; VSUM(nv.vp, hdlist[0]->orig, hdlist[0]->xv[0], 0.5); VSUM(nv.vp, nv.vp, hdlist[0]->xv[1], 0.5); VSUM(nv.vp, nv.vp, hdlist[0]->xv[2], 0.5); fcross(nv.vdir, hdlist[0]->xv[1], hdlist[0]->xv[2]); VCOPY(nv.vup, hdlist[0]->xv[2]); if (do_outside) { normalize(nv.vdir); d = VLEN(hdlist[0]->xv[1]); d += VLEN(hdlist[0]->xv[2]); VSUM(nv.vp, nv.vp, nv.vdir, -d); } new_view(&nv); }
void hdcompgrid( /* compute derived grid vector and index */ HOLO *hp ) { double d; int i, j; /* initialize depth map */ if (hd_depthmap[0] < 1.) { d = 1. + .5/DCLIN; for (i = 0; i < DCINF-DCLIN; i++) { hd_depthmap[i] = d; d *= 1. + 1./DCLIN; } logstep = log(1. + 1./DCLIN); } /* compute grid coordinate vectors */ for (i = 0; i < 3; i++) { fcross(hp->wg[i], hp->xv[(i+1)%3], hp->xv[(i+2)%3]); d = DOT(hp->wg[i],hp->xv[i]); if ((d <= FTINY) & (d >= -FTINY)) error(USER, "degenerate holodeck section"); d = hp->grid[i] / d; hp->wg[i][0] *= d; hp->wg[i][1] *= d; hp->wg[i][2] *= d; } /* compute linear depth range */ hp->tlin = VLEN(hp->xv[0]) + VLEN(hp->xv[1]) + VLEN(hp->xv[2]); /* compute wall super-indices from grid */ hp->wi[0] = 1; /**** index values begin at 1 ****/ for (i = 1; i < 6; i++) { hp->wi[i] = 0; for (j = i; j < 6; j++) hp->wi[i] += hp->grid[hdwg0[j]] * hp->grid[hdwg1[j]]; hp->wi[i] *= hp->grid[hdwg0[i-1]] * hp->grid[hdwg1[i-1]]; hp->wi[i] += hp->wi[i-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); }
char * setview( /* set hvec and vvec, return message on error */ VIEW *v ) { static char ill_horiz[] = "illegal horizontal view size"; static char ill_vert[] = "illegal vertical view size"; if ((v->vfore < -FTINY) | (v->vaft < -FTINY) || (v->vaft > FTINY) & (v->vaft <= v->vfore)) return("illegal fore/aft clipping plane"); if (v->vdist <= FTINY) return("illegal view distance"); v->vdist *= normalize(v->vdir); /* normalize direction */ if (v->vdist == 0.0) return("zero view direction"); if (normalize(v->vup) == 0.0) /* normalize view up */ return("zero view up vector"); fcross(v->hvec, v->vdir, v->vup); /* compute horiz dir */ if (normalize(v->hvec) == 0.0) return("view up parallel to view direction"); fcross(v->vvec, v->hvec, v->vdir); /* compute vert dir */ if (v->horiz <= FTINY) return(ill_horiz); if (v->vert <= FTINY) return(ill_vert); switch (v->type) { case VT_PAR: /* parallel view */ v->hn2 = v->horiz; v->vn2 = v->vert; break; case VT_PER: /* perspective view */ if (v->horiz >= 180.0-FTINY) return(ill_horiz); if (v->vert >= 180.0-FTINY) return(ill_vert); v->hn2 = 2.0 * tan(v->horiz*(PI/180.0/2.0)); v->vn2 = 2.0 * tan(v->vert*(PI/180.0/2.0)); break; case VT_CYL: /* cylindrical panorama */ if (v->horiz > 360.0+FTINY) return(ill_horiz); if (v->vert >= 180.0-FTINY) return(ill_vert); v->hn2 = v->horiz * (PI/180.0); v->vn2 = 2.0 * tan(v->vert*(PI/180.0/2.0)); break; case VT_ANG: /* angular fisheye */ if (v->horiz > 360.0+FTINY) return(ill_horiz); if (v->vert > 360.0+FTINY) return(ill_vert); v->hn2 = v->horiz * (PI/180.0); v->vn2 = v->vert * (PI/180.0); break; case VT_HEM: /* hemispherical fisheye */ if (v->horiz > 180.0+FTINY) return(ill_horiz); if (v->vert > 180.0+FTINY) return(ill_vert); v->hn2 = 2.0 * sin(v->horiz*(PI/180.0/2.0)); v->vn2 = 2.0 * sin(v->vert*(PI/180.0/2.0)); break; case VT_PLS: /* planispheric fisheye */ if (v->horiz >= 360.0-FTINY) return(ill_horiz); if (v->vert >= 360.0-FTINY) return(ill_vert); v->hn2 = 2.*sin(v->horiz*(PI/180.0/2.0)) / (1.0 + cos(v->horiz*(PI/180.0/2.0))); v->vn2 = 2.*sin(v->vert*(PI/180.0/2.0)) / (1.0 + cos(v->vert*(PI/180.0/2.0))); break; default: return("unknown view type"); } if (v->type != VT_ANG && v->type != VT_PLS) { if (v->type != VT_CYL) { v->hvec[0] *= v->hn2; v->hvec[1] *= v->hn2; v->hvec[2] *= v->hn2; } v->vvec[0] *= v->vn2; v->vvec[1] *= v->vn2; v->vvec[2] *= v->vn2; } v->hn2 *= v->hn2; v->vn2 *= v->vn2; return(NULL); }
void /* initialize occlusion cache */ initobscache(int sn) { register SRCREC *srcp = &source[sn]; int cachelen; FVECT rorg, rdir; RREAL d; int i, j, k; int ax=0, ax1=1, ax2=2; if (srcp->sflags & (SSKIP|SPROX|SSPOT|SVIRTUAL)) return; /* don't cache these */ if (srcp->sflags & SDISTANT) cachelen = 4*SHADCACHE*SHADCACHE; else if (srcp->sflags & SFLAT) cachelen = SHADCACHE*SHADCACHE*3 + (SHADCACHE&1)*SHADCACHE*4; else /* spherical distribution */ cachelen = SHADCACHE*SHADCACHE*6; /* allocate cache */ srcp->obscache = (OBSCACHE *)malloc(sizeof(OBSCACHE) + sizeof(OBJECT)*(cachelen-1)); if (srcp->obscache == NULL) error(SYSTEM, "out of memory in initobscache()"); /* set parameters */ if (srcp->sflags & SDISTANT) { RREAL amax = 0; for (ax1 = 3; ax1--; ) if (ABS(srcp->sloc[ax1]) > amax) { amax = ABS(srcp->sloc[ax1]); ax = ax1; } srcp->obscache->p.d.ax = ax; ax1 = (ax+1)%3; ax2 = (ax+2)%3; VCOPY(srcp->obscache->p.d.o, thescene.cuorg); if (srcp->sloc[ax] > 0) srcp->obscache->p.d.o[ax] += thescene.cusize; if (srcp->sloc[ax1] < 0) srcp->obscache->p.d.o[ax1] += thescene.cusize * srcp->sloc[ax1] / amax; if (srcp->sloc[ax2] < 0) srcp->obscache->p.d.o[ax2] += thescene.cusize * srcp->sloc[ax2] / amax; srcp->obscache->p.d.e1 = 1. / (thescene.cusize*(1. + fabs(srcp->sloc[ax1])/amax)); srcp->obscache->p.d.e2 = 1. / (thescene.cusize*(1. + fabs(srcp->sloc[ax2])/amax)); } else if (srcp->sflags & SFLAT) { VCOPY(srcp->obscache->p.f.u, srcp->ss[SU]); normalize(srcp->obscache->p.f.u); fcross(srcp->obscache->p.f.v, srcp->snorm, srcp->obscache->p.f.u); } /* clear cache */ for (i = cachelen; i--; ) srcp->obscache->obs[i] = OVOID; /* cast shadow rays */ if (srcp->sflags & SDISTANT) { for (k = 3; k--; ) rdir[k] = -srcp->sloc[k]; for (i = 2*SHADCACHE; i--; ) for (j = 2*SHADCACHE; j--; ) { VCOPY(rorg, srcp->obscache->p.d.o); rorg[ax1] += (i+.5) / (2*SHADCACHE*srcp->obscache->p.d.e1); rorg[ax2] += (j+.5) / (2*SHADCACHE*srcp->obscache->p.d.e2); castshadow(sn, rorg, rdir); } } else if (srcp->sflags & SFLAT) { d = 0.01*srcp->srad; VSUM(rorg, srcp->sloc, srcp->snorm, d); for (i = SHADCACHE; i--; ) for (j = SHADCACHE; j--; ) { d = 2./SHADCACHE*(i+.5) - 1.; VSUM(rdir, srcp->snorm, srcp->obscache->p.f.u, d); d = 2./SHADCACHE*(j+.5) - 1.; VSUM(rdir, rdir, srcp->obscache->p.f.v, d); normalize(rdir); castshadow(sn, rorg, rdir); } for (k = 2; k--; ) for (i = SHADCACHE; i--; ) for (j = SHADCACHE>>1; j--; ) {
int buildxf( /* build transform for marker */ register char *xf, double markscale, FILE *fin ) { static FVECT vlist[MAXVERT]; static EDGE elist[MAXVERT]; FVECT xvec, yvec, zvec; double xlen; int n; register int i; /* * Read and sort vectors: longest is hypotenuse, * second longest is x' axis, * third longest is y' axis (approximate), * other vectors are ignored. * It is an error if the x' and y' axes do * not share a common vertex (their origin). */ if (fscanf(fin, "%*d %*d %d", &n) != 1) return(-1); if (n%3 != 0) return(-1); n /= 3; if (n < 3 || n > MAXVERT) return(-1); /* sort edges in descending order */ for (i = 0; i < n; i++) { if (fscanf(fin, "%lf %lf %lf", &vlist[i][0], &vlist[i][1], &vlist[i][2]) != 3) return(-1); if (i) { elist[i].beg = i-1; elist[i].end = i; elist[i].len2 = dist2(vlist[i-1],vlist[i]); } } elist[0].beg = n-1; elist[0].end = 0; elist[0].len2 = dist2(vlist[n-1],vlist[0]); qsort(elist, n, sizeof(EDGE), edgecmp); /* find x' and y' */ if (elist[1].end == elist[2].beg || elist[1].end == elist[2].end) { i = elist[1].beg; elist[1].beg = elist[1].end; elist[1].end = i; } if (elist[2].end == elist[1].beg) { i = elist[2].beg; elist[2].beg = elist[2].end; elist[2].end = i; } if (elist[1].beg != elist[2].beg) return(-1); /* x' and y' not connected! */ for (i = 0; i < 3; i++) { xvec[i] = vlist[elist[1].end][i] - vlist[elist[1].beg][i]; yvec[i] = vlist[elist[2].end][i] - vlist[elist[2].beg][i]; } if ((xlen = normalize(xvec)) == 0.0) return(-1); fcross(zvec, xvec, yvec); if (normalize(zvec) == 0.0) return(-1); fcross(yvec, zvec, xvec); n = 0; /* start transformation... */ if (markscale > 0.0) { /* add scale factor */ sprintf(xf, " -s %f", xlen*markscale); n += 2; while (*xf) ++xf; } /* add rotation */ n += addrot(xf, xvec, yvec, zvec); while (*xf) ++xf; /* add translation */ n += 4; sprintf(xf, " -t %f %f %f", vlist[elist[1].beg][0], vlist[elist[1].beg][1], vlist[elist[1].beg][2]); return(n); /* all done */ }