Пример #1
0
void
getfocus(				/* set focus distance */
	char *s
)
{
	char  buf[64];
	double	dist;

	if (sscanf(s, "%lf", &dist) < 1) {
		int	x, y;
		RAY	thisray;
		if (dev->getcur == NULL)
			return;
		(*dev->comout)("Pick focus point\n");
		if ((*dev->getcur)(&x, &y) == ABORT)
			return;
		if ((thisray.rmax = viewray(thisray.rorg, thisray.rdir,
			&ourview, (x+.5)/hresolu, (y+.5)/vresolu)) < -FTINY) {
			error(COMMAND, "not on image");
			return;
		}
		rayorigin(&thisray, PRIMARY, NULL, NULL);
		if (!localhit(&thisray, &thescene)) {
			error(COMMAND, "not a local object");
			return;
		}
		dist = thisray.rot;
	} else if (dist <= .0) {
		error(COMMAND, "focus distance must be positive");
		return;
	}
	ourview.vdist = dist;
	sprintf(buf, "Focus distance set to %f\n", dist);
	(*dev->comout)(buf);
}
Пример #2
0
static int				/* cast source ray to first blocker */
castshadow(int sn, FVECT rorg, FVECT rdir)
{
	RAY     rt;
	
	VCOPY(rt.rorg, rorg);
	VCOPY(rt.rdir, rdir);
	rt.rmax = 0;
	rayorigin(&rt, PRIMARY, NULL, NULL);
					/* check for intersection */
	while (localhit(&rt, &thescene)) {
		RAY	rt1 = rt;	/* pretend we were aimed at source */
		rt1.crtype |= rt1.rtype = SHADOW;
		rt1.rdir[0] = -rt.rdir[0];
		rt1.rdir[1] = -rt.rdir[1];
		rt1.rdir[2] = -rt.rdir[2];
		rt1.rod = -rt.rod;
		VSUB(rt1.rorg, rt.rop, rt.rdir);
		rt1.rot = 1.;
		rt1.rsrc = sn;
					/* record blocker */
		if (srcblocker(&rt1))
			return(1);
					/* move past failed blocker */
		VSUM(rt.rorg, rt.rop, rt.rdir, FTINY);
		rayclear(&rt);		/* & try again... */
	}
	return(0);			/* found no blockers */
}
Пример #3
0
int
getinterest(		/* get area of interest */
	char  *s,
	int  direc,
	FVECT  vec,
	double  *mp
)
{
	int  x, y;
	RAY  thisray;
	int  i;

	if (sscanf(s, "%lf", mp) != 1)
		*mp = 1.0;
	else if (*mp < -FTINY)		/* negative zoom is reduction */
		*mp = -1.0 / *mp;
	else if (*mp <= FTINY) {	/* too small */
		error(COMMAND, "illegal magnification");
		return(-1);
	}
	if (!sscanvec(sskip(s), vec)) {
		if (dev->getcur == NULL)
			return(-1);
		(*dev->comout)("Pick view center\n");
		if ((*dev->getcur)(&x, &y) == ABORT)
			return(-1);
		if ((thisray.rmax = viewray(thisray.rorg, thisray.rdir,
			&ourview, (x+.5)/hresolu, (y+.5)/vresolu)) < -FTINY) {
			error(COMMAND, "not on image");
			return(-1);
		}
		if (!direc || ourview.type == VT_PAR) {
			rayorigin(&thisray, PRIMARY, NULL, NULL);
			if (!localhit(&thisray, &thescene)) {
				error(COMMAND, "not a local object");
				return(-1);
			}
		}
		if (direc)
			if (ourview.type == VT_PAR)
				for (i = 0; i < 3; i++)
					vec[i] = thisray.rop[i] - ourview.vp[i];
			else
				VCOPY(vec, thisray.rdir);
		else
			VCOPY(vec, thisray.rop);
	} else if (direc) {
		for (i = 0; i < 3; i++)
			vec[i] -= ourview.vp[i];
		if (normalize(vec) == 0.0) {
			error(COMMAND, "point at view origin");
			return(-1);
		}
	}
	return(0);
}
Пример #4
0
extern void
raytrans(			/* transmit ray as is */
	RAY  *r
)
{
	RAY  tr;

	if (rayorigin(&tr, TRANS, r, NULL) == 0) {
		VCOPY(tr.rdir, r->rdir);
		rayvalue(&tr);
		copycolor(r->rcol, tr.rcol);
		r->rt = r->rot + tr.rt;
	}
}
Пример #5
0
void
getorigin(				/* origin viewpoint */
	char  *s
)
{
	VIEW	nv = ourview;
	double	d;
					/* get new view origin */
	if (sscanf(s, "%lf %lf", &d, &d) == 1) {
					/* just moving some distance */
		VSUM(nv.vp, nv.vp, nv.vdir, d);
	} else if (!sscanvec(s, nv.vp)) {
		int	x, y;		/* need to pick origin */
		RAY	thisray;
		if (dev->getcur == NULL)
			return;
		(*dev->comout)("Pick point on surface for new origin\n");
		if ((*dev->getcur)(&x, &y) == ABORT)
			return;
		if ((thisray.rmax = viewray(thisray.rorg, thisray.rdir,
			&ourview, (x+.5)/hresolu, (y+.5)/vresolu)) < -FTINY) {
			error(COMMAND, "not on image");
			return;
		}
		rayorigin(&thisray, PRIMARY, NULL, NULL);
		if (!localhit(&thisray, &thescene)) {
			error(COMMAND, "not a local object");
			return;
		}
		if (thisray.rod < 0.0)	/* don't look through other side */
			flipsurface(&thisray);
		VSUM(nv.vp, thisray.rop, thisray.ron, 20.0*FTINY);
		VCOPY(nv.vdir, thisray.ron);
	} else if (!sscanvec(sskip2(s,3), nv.vdir) || normalize(nv.vdir) == 0.0)
		VCOPY(nv.vdir, ourview.vdir);

	d = DOT(nv.vdir, nv.vup);	/* need different up vector? */
	if (d*d >= 1.-2.*FTINY) {
		int	i;
		nv.vup[0] = nv.vup[1] = nv.vup[2] = 0.0;
		for (i = 3; i--; )
			if (nv.vdir[i]*nv.vdir[i] < 0.34)
				break;
		nv.vup[i] = 1.;
	}
	newview(&nv);
}
Пример #6
0
extern int
srcray(				/* send a ray to a source, return domega */
	register RAY  *sr,		/* returned source ray */
	RAY  *r,			/* ray which hit object */
	SRCINDEX  *si			/* source sample index */
)
{
	double  d;				/* distance to source */
	register SRCREC  *srcp;

	rayorigin(sr, SHADOW, r, NULL);		/* ignore limits */

	if (r == NULL)
		sr->rmax = 0.0;

	while ((d = nextssamp(sr, si)) != 0.0) {
		sr->rsrc = si->sn;			/* remember source */
		srcp = source + si->sn;
		if (srcp->sflags & SDISTANT) {
			if (srcp->sflags & SSPOT && spotout(sr, srcp->sl.s))
				continue;
			return(1);		/* sample OK */
		}
				/* local source */
						/* check proximity */
		if (srcp->sflags & SPROX && d > srcp->sl.prox)
			continue;
						/* check angle */
		if (srcp->sflags & SSPOT) {
			if (spotout(sr, srcp->sl.s))
				continue;
					/* adjust solid angle */
			si->dom *= d*d;
			d += srcp->sl.s->flen;
			si->dom /= d*d;
		}
		return(1);			/* sample OK */
	}
	return(0);			/* no more samples */
}
Пример #7
0
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);
}
Пример #8
0
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);
}
Пример #9
0
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);
			}
	}
}
Пример #10
0
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);
}
Пример #11
0
static int
dir_proj(		/* compute a director's projection */
	MAT4  pm,
	OBJREC  *o,
	SRCREC  *s,
	int  n
)
{
	RAY  tr;
	OBJREC  *m;
	MFUNC  *mf;
	EPNODE  **va;
	FVECT  cent, newdir, nv, h;
	double  coef, olddot, newdot, od;
	int  i, j;
				/* initialize test ray */
	getmaxdisk(cent, o);
	if (s->sflags & SDISTANT)
		for (i = 0; i < 3; i++) {
			tr.rdir[i] = -s->sloc[i];
			tr.rorg[i] = cent[i] - tr.rdir[i];
		}
	else {
		for (i = 0; i < 3; i++) {
			tr.rdir[i] = cent[i] - s->sloc[i];
			tr.rorg[i] = s->sloc[i];
		}
		if (normalize(tr.rdir) == 0.0)
			return(0);		/* at source! */
	}
	od = getplaneq(nv, o);
	olddot = DOT(tr.rdir, nv);
	if (olddot <= FTINY && olddot >= -FTINY)
		return(0);		/* old dir parallels plane */
	tr.rmax = 0.0;
	rayorigin(&tr, PRIMARY, NULL, NULL);
	if (!(*ofun[o->otype].funp)(o, &tr))
		return(0);		/* no intersection! */
				/* compute redirection */
	m = vsmaterial(o);
	mf = getdfunc(m);
	setfunc(m, &tr);
	varset("DxA", '=', 0.0);
	varset("DyA", '=', 0.0);
	varset("DzA", '=', 0.0);
	errno = 0;
	va = mf->ep + 4*n;
	coef = evalue(va[0]);
	if (errno == EDOM || errno == ERANGE)
		goto computerr;
	if (coef <= FTINY)
		return(0);		/* insignificant */
	va++;
	for (i = 0; i < 3; i++) {
		newdir[i] = evalue(va[i]);
		if (errno == EDOM || errno == ERANGE)
			goto computerr;
	}
	if (mf->fxp != &unitxf)
		multv3(newdir, newdir, mf->fxp->xfm);
					/* normalization unnecessary */
	newdot = DOT(newdir, nv);
	if (newdot <= FTINY && newdot >= -FTINY)
		return(0);		/* new dir parallels plane */
				/* everything OK -- compute shear */
	for (i = 0; i < 3; i++)
		h[i] = newdir[i]/newdot - tr.rdir[i]/olddot;
	setident4(pm);
	for (j = 0; j < 3; j++) {
		for (i = 0; i < 3; i++)
			pm[i][j] += nv[i]*h[j];
		pm[3][j] = -od*h[j];
	}
	if ((newdot > 0.0) ^ (olddot > 0.0))	/* add mirroring */
		for (j = 0; j < 3; j++) {
			for (i = 0; i < 3; i++)
				pm[i][j] -= 2.*nv[i]*nv[j];
			pm[3][j] += 2.*od*nv[j];
		}
	return(1);
computerr:
	objerror(m, WARNING, "projection compute error");
	return(0);
}
Пример #12
0
int
m_mist(		/* process a ray entering or leaving some mist */
	OBJREC  *m,
	RAY  *r
)
{
	RAY  p;
	int  *myslist = NULL;
	int  newslist[MAXSLIST+1];
	COLOR  mext;
	double  re, ge, be;
	int  i, j;
					/* check arguments */
	if (m->oargs.nfargs > 7)
		objerror(m, USER, "bad arguments");
					/* get source indices */
	if (m->oargs.nsargs > 0 && (myslist = (int *)m->os) == NULL) {
		if (m->oargs.nsargs > MAXSLIST)
			objerror(m, INTERNAL, "too many sources in list");
		myslist = (int *)malloc((m->oargs.nsargs+1)*sizeof(int));
		if (myslist == NULL)
			goto memerr;
		myslist[0] = 0;			/* size is first in list */
		for (j = 0; j < m->oargs.nsargs; j++) {
			i = nsources;		/* look up each source id */
			while (i--)
				if (srcmatch(source+i, m->oargs.sarg[j]))
					break;
			if (i < 0) {
				sprintf(errmsg, "unknown source \"%s\"",
						m->oargs.sarg[j]);
				objerror(m, WARNING, errmsg);
			} else if (inslist(myslist, i)) {
				sprintf(errmsg, "duplicate source \"%s\"",
						m->oargs.sarg[j]);
				objerror(m, WARNING, errmsg);
			} else
				myslist[++myslist[0]] = i;
		}
		m->os = (char *)myslist;
	}
	if (m->oargs.nfargs > 2) {		/* compute extinction */
		setcolor(mext, m->oargs.farg[0], m->oargs.farg[1],
				m->oargs.farg[2]);
		raytexture(r, m->omod);			/* get modifiers */
		multcolor(mext, r->pcol);
	} else
		setcolor(mext, 0., 0., 0.);
						/* start transmitted ray */
	if (rayorigin(&p, TRANS, r, NULL) < 0)
		return(1);
	VCOPY(p.rdir, r->rdir);
	p.slights = newslist;
	if (r->slights != NULL)			/* copy old list if one */
		for (j = r->slights[0]; j >= 0; j--)
			p.slights[j] = r->slights[j];
	else
		p.slights[0] = 0;
	if (r->rod > 0.) {			/* entering ray */
		addcolor(p.cext, mext);
		if (m->oargs.nfargs > 5)
			setcolor(p.albedo, m->oargs.farg[3],
					m->oargs.farg[4], m->oargs.farg[5]);
		if (m->oargs.nfargs > 6)
			p.gecc = m->oargs.farg[6];
		add2slist(&p, myslist);			/* add to list */
	} else {				/* leaving ray */
		if (myslist != NULL) {			/* delete from list */
			for (j = myslist[0]; j > 0; j--)
				if ( (i = inslist(p.slights, myslist[j])) )
					p.slights[i] = -1;
			for (i = 0, j = 1; j <= p.slights[0]; j++)
				if (p.slights[j] != -1)
					p.slights[++i] = p.slights[j];
			if (p.slights[0] - i < myslist[0]) {	/* fix old */
				addcolor(r->cext, mext);
				if (m->oargs.nfargs > 5)
					setcolor(r->albedo, m->oargs.farg[3],
					m->oargs.farg[4], m->oargs.farg[5]);
				if (m->oargs.nfargs > 6)
					r->gecc = m->oargs.farg[6];
				add2slist(r, myslist);
			}
			p.slights[0] = i;
		}
		if ((re = colval(r->cext,RED) - colval(mext,RED)) <
				colval(cextinction,RED))
			re = colval(cextinction,RED);
		if ((ge = colval(r->cext,GRN) - colval(mext,GRN)) <
				colval(cextinction,GRN))
			ge = colval(cextinction,GRN);
		if ((be = colval(r->cext,BLU) - colval(mext,BLU)) <
				colval(cextinction,BLU))
			be = colval(cextinction,BLU);
		setcolor(p.cext, re, ge, be);
		if (m->oargs.nfargs > 5)
			copycolor(p.albedo, salbedo);
		if (m->oargs.nfargs > 6)
			p.gecc = seccg;
	}
	rayvalue(&p);				/* calls rayparticipate() */
	copycolor(r->rcol, p.rcol);		/* return value */
	r->rt = r->rot + p.rt;
	return(1);
memerr:
	error(SYSTEM, "out of memory in m_mist");
	return 0; /* pro forma return */
}
Пример #13
0
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--;
}
Пример #14
0
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++;
	}
Пример #15
0
int
paint(			/* compute and paint a rectangle */
	PNODE  *p
)
{
	static RAY  thisray;
	double  h, v;

	if ((p->xmax <= p->xmin) | (p->ymax <= p->ymin)) {	/* empty */
		p->x = p->xmin;
		p->y = p->ymin;
		setcolor(p->v, 0.0, 0.0, 0.0);
		return(0);
	}
						/* jitter ray direction */
	p->x = h = p->xmin + (p->xmax-p->xmin)*frandom();
	p->y = v = p->ymin + (p->ymax-p->ymin)*frandom();
	
	if ((thisray.rmax = viewray(thisray.rorg, thisray.rdir, &ourview,
			h/hresolu, v/vresolu)) < -FTINY) {
		setcolor(thisray.rcol, 0.0, 0.0, 0.0);
	} else if (!ray_pnprocs) {		/* immediate mode */
		ray_trace(&thisray);
	} else {				/* queuing mode */
		int	rval;
		rayorigin(&thisray, PRIMARY, NULL, NULL);
		thisray.rno = (RNUMBER)p;
		rval = ray_pqueue(&thisray);
		if (!rval)
			return(0);
		if (rval < 0)
			return(-1);
						/* get node for returned ray */
		p = (PNODE *)thisray.rno;
	}

	copycolor(p->v, thisray.rcol);
	scalecolor(p->v, exposure);

	recolor(p);				/* paint it */

	if (dev->flush != NULL) {		/* shall we check for input? */
		static RNUMBER	lastflush = 0;
		RNUMBER		counter = raynum;
		int		flushintvl;
		if (!ray_pnprocs) {
			counter = nrays;
			flushintvl = WFLUSH1;
		} else if (ambounce == 0)
			flushintvl = ray_pnprocs*WFLUSH;
		else if (niflush < WFLUSH)
			flushintvl = ray_pnprocs*niflush/(ambounce+1);
		else
			flushintvl = ray_pnprocs*WFLUSH/(ambounce+1);
		if (lastflush > counter)
			lastflush = 0;		/* counter wrapped */

		if (counter - lastflush >= flushintvl) {
			lastflush = counter;
			(*dev->flush)();
			niflush++;
		}
	}
	return(1);
}
Пример #16
0
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);
}
Пример #17
0
static void
agaussamp(		/* sample anisotropic Gaussian specular */
	ANISODAT  *np
)
{
	RAY  sr;
	FVECT  h;
	double  rv[2];
	double  d, sinp, cosp;
	COLOR	scol;
	int  maxiter, ntrials, nstarget, nstaken;
	int  i;
					/* compute reflection */
	if ((np->specfl & (SP_REFL|SP_RBLT)) == SP_REFL &&
			rayorigin(&sr, SPECULAR, np->rp, np->scolor) == 0) {
		nstarget = 1;
		if (specjitter > 1.5) {	/* multiple samples? */
			nstarget = specjitter*np->rp->rweight + .5;
			if (sr.rweight <= minweight*nstarget)
				nstarget = sr.rweight/minweight;
			if (nstarget > 1) {
				d = 1./nstarget;
				scalecolor(sr.rcoef, d);
				sr.rweight *= d;
			} else
				nstarget = 1;
		}
		setcolor(scol, 0., 0., 0.);
		dimlist[ndims++] = (int)(size_t)np->mp;
		maxiter = MAXITER*nstarget;
		for (nstaken = ntrials = 0; nstaken < nstarget &&
						ntrials < maxiter; ntrials++) {
			if (ntrials)
				d = frandom();
			else
				d = urand(ilhash(dimlist,ndims)+samplendx);
			multisamp(rv, 2, d);
			d = 2.0*PI * rv[0];
			cosp = tcos(d) * np->u_alpha;
			sinp = tsin(d) * np->v_alpha;
			d = 1./sqrt(cosp*cosp + sinp*sinp);
			cosp *= d;
			sinp *= d;
			if ((0. <= specjitter) & (specjitter < 1.))
				rv[1] = 1.0 - specjitter*rv[1];
			if (rv[1] <= FTINY)
				d = 1.0;
			else
				d = sqrt(-log(rv[1]) /
					(cosp*cosp/(np->u_alpha*np->u_alpha) +
					 sinp*sinp/(np->v_alpha*np->v_alpha)));
			for (i = 0; i < 3; i++)
				h[i] = np->pnorm[i] +
					d*(cosp*np->u[i] + sinp*np->v[i]);
			d = -2.0 * DOT(h, np->rp->rdir) / (1.0 + d*d);
			VSUM(sr.rdir, np->rp->rdir, h, d);
						/* sample rejection test */
			if ((d = DOT(sr.rdir, np->rp->ron)) <= FTINY)
				continue;
			checknorm(sr.rdir);
			if (nstarget > 1) {	/* W-G-M-D adjustment */
				if (nstaken) rayclear(&sr);
				rayvalue(&sr);
				d = 2./(1. + np->rp->rod/d);
				scalecolor(sr.rcol, d);
				addcolor(scol, sr.rcol);
			} else {
				rayvalue(&sr);
				multcolor(sr.rcol, sr.rcoef);
				addcolor(np->rp->rcol, sr.rcol);
			}
			++nstaken;
		}
		if (nstarget > 1) {		/* final W-G-M-D weighting */
			multcolor(scol, sr.rcoef);
			d = (double)nstarget/ntrials;
			scalecolor(scol, d);
			addcolor(np->rp->rcol, scol);
		}
		ndims--;
	}
					/* compute transmission */
	copycolor(sr.rcoef, np->mcolor);		/* modify by material color */
	scalecolor(sr.rcoef, np->tspec);
	if ((np->specfl & (SP_TRAN|SP_TBLT)) == SP_TRAN &&
			rayorigin(&sr, SPECULAR, np->rp, sr.rcoef) == 0) {
		nstarget = 1;
		if (specjitter > 1.5) {	/* multiple samples? */
			nstarget = specjitter*np->rp->rweight + .5;
			if (sr.rweight <= minweight*nstarget)
				nstarget = sr.rweight/minweight;
			if (nstarget > 1) {
				d = 1./nstarget;
				scalecolor(sr.rcoef, d);
				sr.rweight *= d;
			} else
				nstarget = 1;
		}
		dimlist[ndims++] = (int)(size_t)np->mp;
		maxiter = MAXITER*nstarget;
		for (nstaken = ntrials = 0; nstaken < nstarget &&
						ntrials < maxiter; ntrials++) {
			if (ntrials)
				d = frandom();
			else
				d = urand(ilhash(dimlist,ndims)+1823+samplendx);
			multisamp(rv, 2, d);
			d = 2.0*PI * rv[0];
			cosp = tcos(d) * np->u_alpha;
			sinp = tsin(d) * np->v_alpha;
			d = 1./sqrt(cosp*cosp + sinp*sinp);
			cosp *= d;
			sinp *= d;
			if ((0. <= specjitter) & (specjitter < 1.))
				rv[1] = 1.0 - specjitter*rv[1];
			if (rv[1] <= FTINY)
				d = 1.0;
			else
				d = sqrt(-log(rv[1]) /
					(cosp*cosp/(np->u_alpha*np->u_alpha) +
					 sinp*sinp/(np->v_alpha*np->v_alpha)));
			for (i = 0; i < 3; i++)
				sr.rdir[i] = np->prdir[i] +
						d*(cosp*np->u[i] + sinp*np->v[i]);
			if (DOT(sr.rdir, np->rp->ron) >= -FTINY)
				continue;
			normalize(sr.rdir);	/* OK, normalize */
			if (nstaken)		/* multi-sampling */
				rayclear(&sr);
			rayvalue(&sr);
			multcolor(sr.rcol, sr.rcoef);
			addcolor(np->rp->rcol, sr.rcol);
			++nstaken;
		}
		ndims--;
	}
}