Beispiel #1
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 */
}
Beispiel #2
0
/* Find convex hull vertex to complete triangle (oriented call) */
static RBFNODE *
find_chull_vert(const RBFNODE *rbf0, const RBFNODE *rbf1)
{
	FVECT	vmid, vejn, vp;
	RBFNODE	*rbf, *rbfbest = NULL;
	double	dprod, area2, bestarea2 = FHUGE, bestdprod = -.5;

	VSUB(vejn, rbf1->invec, rbf0->invec);
	VADD(vmid, rbf0->invec, rbf1->invec);
	if (normalize(vejn) == 0 || normalize(vmid) == 0)
		return(NULL);
						/* XXX exhaustive search */
	/* Find triangle with minimum rotation from perpendicular */
	for (rbf = dsf_list; rbf != NULL; rbf = rbf->next) {
		if ((rbf == rbf0) | (rbf == rbf1))
			continue;
		tri_orient(vp, rbf0->invec, rbf1->invec, rbf->invec);
		if (DOT(vp, vmid) <= FTINY)
			continue;		/* wrong orientation */
		area2 = .25*DOT(vp,vp);
		VSUB(vp, rbf->invec, vmid);
		dprod = -DOT(vp, vejn);
		VSUM(vp, vp, vejn, dprod);	/* above guarantees non-zero */
		dprod = DOT(vp, vmid) / VLEN(vp);
		if (dprod <= bestdprod + FTINY*(1 - 2*(area2 < bestarea2)))
			continue;		/* found better already */
		if (overlaps_tri(rbf0, rbf1, rbf))
			continue;		/* overlaps another triangle */
		rbfbest = rbf;
		bestdprod = dprod;		/* new one to beat */
		bestarea2 = area2;
	}
	return(rbfbest);
}
Beispiel #3
0
static void
disp_bundle(			/* display a ray bundle */
	register PACKHEAD	*p
)
{
	GCOORD	gc[2];
	FVECT	ro, rd, wp;
	double	d;
	register int	i;
					/* get beam coordinates */
	if ((p->hd < 0) | (p->hd >= HDMAX) || hdlist[p->hd] == NULL)
		error(INTERNAL, "bad holodeck number in disp_bundle");
	if (!hdbcoord(gc, hdlist[p->hd], p->bi))
		error(INTERNAL, "bad beam index in disp_bundle");
					/* display each ray */
	for (i = p->nr; i--; ) {
		hdray(ro, rd, hdlist[p->hd], gc, packra(p)[i].r);
		d = hddepth(hdlist[p->hd], packra(p)[i].d);
		if (d < .99*FHUGE) {
			VSUM(wp, ro, rd, d);	/* might be behind viewpoint */
			dev_value(packra(p)[i].v, rd, wp);
		} else
			dev_value(packra(p)[i].v, rd, NULL);
	}
#ifdef DEBUG
	if (imm_mode) nimmrays += p->nr;
	else naddrays += p->nr;
#endif
}
Beispiel #4
0
static int
addclump(		/* transfer the given clump and free */
	HOLO	*hp,
	int	*bq,
	int	nb
)
{
	GCOORD	gc[2];
	FVECT	ro, rd;
	double	d;
	int	i;
	register int	k;
	register BEAM	*bp;
					/* sort based on file position */
	beamdir = hp->bi;
	qsort((char *)bq, nb, sizeof(*bq), bpcmp);
					/* transfer each beam */
	for (i = 0; i < nb; i++) {
		bp = hdgetbeam(hp, bq[i]);
		hdbcoord(gc, hp, bq[i]);
						/* add each ray to output */
		for (k = bp->nrm; k--; ) {
			d = hdray(ro, rd, hp, gc, hdbray(bp)[k].r);
			if (hp->priv == &unobstr)
				VSUM(ro, ro, rd, d);
			else
				d = 0.;
			d = hddepth(hp, hdbray(bp)[k].d) - d;
			addray(ro, rd, d, hdbray(bp)[k].v);
		}
		hdfreebeam(hp, bq[i]);		/* free the beam */
	}
	return(0);
}
Beispiel #5
0
int
t_func(			/* compute texture for ray */
    OBJREC  *m,
    RAY  *r
)
{
    FVECT  disp;
    double  d;
    MFUNC  *mf;
    int  i;

    if (m->oargs.nsargs < 4)
        objerror(m, USER, "bad # arguments");
    mf = getfunc(m, 3, 0x7, 1);
    setfunc(m, r);
    errno = 0;
    for (i = 0; i < 3; i++) {
        disp[i] = evalue(mf->ep[i]);
        if (errno == EDOM || errno == ERANGE) {
            objerror(m, WARNING, "compute error");
            return(0);
        }
    }
    if (mf->fxp != &unitxf)
        multv3(disp, disp, mf->fxp->xfm);
    if (r->rox != NULL) {
        multv3(disp, disp, r->rox->f.xfm);
        d = 1.0 / (mf->fxp->sca * r->rox->f.sca);
    } else
        d = 1.0 / mf->fxp->sca;
    VSUM(r->pert, r->pert, disp, d);
    return(0);
}
Beispiel #6
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);
}
Beispiel #7
0
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);
}
Beispiel #8
0
extern int
o_face(		/* compute intersection with polygonal face */
	OBJREC  *o,
	register RAY  *r
)
{
	double  rdot;		/* direction . normal */
	double  t;		/* distance to intersection */
	FVECT  pisect;		/* intersection point */
	register FACE  *f;	/* face record */

	f = getface(o);
		
	/*
	 *  First, we find the distance to the plane containing the
	 *  face.  If this distance is less than zero or greater
	 *  than a previous intersection, we return.  Otherwise,
	 *  we determine whether in fact the ray intersects the
	 *  face.  The ray intersects the face if the
	 *  point of intersection with the plane of the face
	 *  is inside the face.
	 */
						/* compute dist. to plane */
	rdot = -DOT(r->rdir, f->norm);
	if (rdot <= FTINY && rdot >= -FTINY)	/* ray parallels plane */
		t = FHUGE;
	else
		t = (DOT(r->rorg, f->norm) - f->offset) / rdot;
	
	if (t <= FTINY || t >= r->rot)		/* not good enough */
		return(0);
						/* compute intersection */
	VSUM(pisect, r->rorg, r->rdir, t);

	if (!inface(pisect, f))			/* ray intersects face? */
		return(0);

	r->ro = o;
	r->rot = t;
	VCOPY(r->rop, pisect);
	VCOPY(r->ron, f->norm);
	r->rod = rdot;
	r->pert[0] = r->pert[1] = r->pert[2] = 0.0;
	r->uv[0] = r->uv[1] = 0.0;
	r->rox = NULL;

	return(1);				/* hit */
}
static int
moveview(	/* move our view */
	int	dx,
	int	dy,
	int	mov,
	int	orb
)
{
	VIEW	nv;
	FVECT	odir, v1;
	double	d;
	int	li;
				/* start with old view */
	nv = odev.v;
				/* change view direction */
	if (mov | orb) {
		if ((li = qtFindLeaf(dx, dy)) < 0)
			return(0);	/* not on window */
		VSUM(odir, qtL.wp[li], nv.vp, -1.);
	} else {
		if (viewray(nv.vp, nv.vdir, &odev.v,
				(dx+.5)/odev.hres, (dy+.5)/odev.vres) < -FTINY)
			return(0);	/* outside view */
	}
	if (orb && mov) {		/* orbit left/right */
		spinvector(odir, odir, nv.vup, d=MOVDEG*PI/180.*mov);
		VSUM(nv.vp, qtL.wp[li], odir, -1.);
		spinvector(nv.vdir, nv.vdir, nv.vup, d);
	} else if (orb) {		/* orbit up/down */
		if (geodesic(odir, odir, nv.vup,
				d=MOVDEG*PI/180.*orb, GEOD_RAD) == 0.0)
			return(0);
		VSUM(nv.vp, qtL.wp[li], odir, -1.);
		geodesic(nv.vdir, nv.vdir, nv.vup, d, GEOD_RAD);
	} else if (mov) {		/* move forward/backward */
		d = MOVPCT/100. * mov;
		VSUM(nv.vp, nv.vp, odir, d);
	}
	if (!mov ^ !orb && headlocked) {	/* restore head height */
		VSUM(v1, odev.v.vp, nv.vp, -1.);
		d = DOT(v1, odev.v.vup);
		VSUM(nv.vp, nv.vp, odev.v.vup, d);
	}
	if (setview(&nv) != NULL)
		return(0);	/* illegal view */
	dev_view(&nv);
	inpresflags |= DFL(DC_SETVIEW);
	return(1);
}
Beispiel #10
0
static int
moveview(	/* move our view */
	int	dx,
	int	dy,
	int	mov,
	int	orb
)
{
	VIEW	nv;
	FVECT	odir, v1, wp;
	double	d;
				/* start with old view */
	nv = thisview;
				/* change view direction */
	if ((d = viewray(v1, odir, &thisview,
			(dx+.5)/hres, (dy+.5)/vres)) < -FTINY)
		return(0);		/* outside view */
	if (mov | orb) {
		if (!getintersect(wp, v1, odir, d))
			return(0);
		VSUM(odir, wp, nv.vp, -1.);
	} else
		VCOPY(nv.vdir, odir);
	if (orb && mov) {		/* orbit left/right */
		spinvector(odir, odir, nv.vup, d=MOVDEG*PI/180.*mov);
		VSUM(nv.vp, wp, odir, -1.);
		spinvector(nv.vdir, nv.vdir, nv.vup, d);
	} else if (orb) {		/* orbit up/down */
		if (geodesic(odir, odir, nv.vup,
				d=MOVDEG*PI/180.*orb, GEOD_RAD) == 0.0)
			return(0);
		VSUM(nv.vp, wp, odir, -1.);
		geodesic(nv.vdir, nv.vdir, nv.vup, d, GEOD_RAD);
	} else if (mov) {		/* move forward/backward */
		d = MOVPCT/100. * mov;
		VSUM(nv.vp, nv.vp, odir, d);
	}
	if (!mov ^ !orb && headlocked) {	/* restore head height */
		VSUM(v1, thisview.vp, nv.vp, -1.);
		d = DOT(v1, thisview.vup);
		VSUM(nv.vp, nv.vp, thisview.vup, d);
	}
	if (setview(&nv) != NULL)
		return(0);	/* illegal view */
	dev_view(&nv);
	return(1);
}
Beispiel #11
0
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);
}
Beispiel #12
0
double
viewray(				/* compute ray origin and direction */
FVECT  orig,
FVECT  direc,
VIEW  *v,
double  x,
double  y
)
{
	double	d, z;
	
	x += v->hoff - 0.5;
	y += v->voff - 0.5;

	switch(v->type) {
	case VT_PAR:			/* parallel view */
		orig[0] = v->vp[0] + v->vfore*v->vdir[0]
				+ x*v->hvec[0] + y*v->vvec[0];
		orig[1] = v->vp[1] + v->vfore*v->vdir[1]
				+ x*v->hvec[1] + y*v->vvec[1];
		orig[2] = v->vp[2] + v->vfore*v->vdir[2]
				+ x*v->hvec[2] + y*v->vvec[2];
		VCOPY(direc, v->vdir);
		return(v->vaft > FTINY ? v->vaft - v->vfore : 0.0);
	case VT_PER:			/* perspective view */
		direc[0] = v->vdir[0] + x*v->hvec[0] + y*v->vvec[0];
		direc[1] = v->vdir[1] + x*v->hvec[1] + y*v->vvec[1];
		direc[2] = v->vdir[2] + x*v->hvec[2] + y*v->vvec[2];
		VSUM(orig, v->vp, direc, v->vfore);
		d = normalize(direc);
		return(v->vaft > FTINY ? (v->vaft - v->vfore)*d : 0.0);
	case VT_HEM:			/* hemispherical fisheye */
		z = 1.0 - x*x*v->hn2 - y*y*v->vn2;
		if (z < 0.0)
			return(-1.0);
		z = sqrt(z);
		direc[0] = z*v->vdir[0] + x*v->hvec[0] + y*v->vvec[0];
		direc[1] = z*v->vdir[1] + x*v->hvec[1] + y*v->vvec[1];
		direc[2] = z*v->vdir[2] + x*v->hvec[2] + y*v->vvec[2];
		VSUM(orig, v->vp, direc, v->vfore);
		return(v->vaft > FTINY ? v->vaft - v->vfore : 0.0);
	case VT_CYL:			/* cylindrical panorama */
		d = x * v->horiz * (PI/180.0);
		z = cos(d);
		x = sin(d);
		direc[0] = z*v->vdir[0] + x*v->hvec[0] + y*v->vvec[0];
		direc[1] = z*v->vdir[1] + x*v->hvec[1] + y*v->vvec[1];
		direc[2] = z*v->vdir[2] + x*v->hvec[2] + y*v->vvec[2];
		VSUM(orig, v->vp, direc, v->vfore);
		d = normalize(direc);
		return(v->vaft > FTINY ? (v->vaft - v->vfore)*d : 0.0);
	case VT_ANG:			/* angular fisheye */
		x *= (1.0/180.0)*v->horiz;
		y *= (1.0/180.0)*v->vert;
		d = x*x + y*y;
		if (d > 1.0)
			return(-1.0);
		d = sqrt(d);
		z = cos(PI*d);
		d = d <= FTINY ? PI : sqrt(1.0 - z*z)/d;
		x *= d;
		y *= d;
		direc[0] = z*v->vdir[0] + x*v->hvec[0] + y*v->vvec[0];
		direc[1] = z*v->vdir[1] + x*v->hvec[1] + y*v->vvec[1];
		direc[2] = z*v->vdir[2] + x*v->hvec[2] + y*v->vvec[2];
		VSUM(orig, v->vp, direc, v->vfore);
		return(v->vaft > FTINY ? v->vaft - v->vfore : 0.0);
	case VT_PLS:			/* planispheric fisheye */
		x *= sqrt(v->hn2);
		y *= sqrt(v->vn2);
		d = x*x + y*y;
		z = (1. - d)/(1. + d);
		x *= (1. + z);
		y *= (1. + z);
		direc[0] = z*v->vdir[0] + x*v->hvec[0] + y*v->vvec[0];
		direc[1] = z*v->vdir[1] + x*v->hvec[1] + y*v->vvec[1];
		direc[2] = z*v->vdir[2] + x*v->hvec[2] + y*v->vvec[2];
		VSUM(orig, v->vp, direc, v->vfore);
		return(v->vaft > FTINY ? v->vaft - v->vfore : 0.0);
	}
	return(-1.0);
}
Beispiel #13
0
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--; ) {
Beispiel #14
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);
}
Beispiel #15
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--;
}
Beispiel #16
0
extern int
localhit(		/* check for hit in the octree */
	RAY  *r,
	CUBE  *scene
)
{
	OBJECT  cxset[MAXCSET+1];	/* set of checked objects */
	FVECT  curpos;			/* current cube position */
	int  sflags;			/* sign flags */
	double  t, dt;
	int  i;

	nrays++;			/* increment trace counter */
	sflags = 0;
	for (i = 0; i < 3; i++) {
		curpos[i] = r->rorg[i];
		if (r->rdir[i] > 1e-7)
			sflags |= 1 << i;
		else if (r->rdir[i] < -1e-7)
			sflags |= 0x10 << i;
	}
	if (!sflags) {
		error(WARNING, "zero ray direction in localhit");
		return(0);
	}
					/* start off assuming nothing hit */
	if (r->rmax > FTINY) {		/* except aft plane if one */
		r->ro = &Aftplane;
		r->rot = r->rmax;
		VSUM(r->rop, r->rorg, r->rdir, r->rot);
	}
					/* find global cube entrance point */
	t = 0.0;
	if (!incube(scene, curpos)) {
					/* find distance to entry */
		for (i = 0; i < 3; i++) {
					/* plane in our direction */
			if (sflags & 1<<i)
				dt = scene->cuorg[i];
			else if (sflags & 0x10<<i)
				dt = scene->cuorg[i] + scene->cusize;
			else
				continue;
					/* distance to the plane */
			dt = (dt - r->rorg[i])/r->rdir[i];
			if (dt > t)
				t = dt;	/* farthest face is the one */
		}
		t += FTINY;		/* fudge to get inside cube */
		if (t >= r->rot)	/* clipped already */
			return(0);
					/* advance position */
		VSUM(curpos, curpos, r->rdir, t);

		if (!incube(scene, curpos))	/* non-intersecting ray */
			return(0);
	}
	cxset[0] = 0;
	raymove(curpos, cxset, sflags, r, scene);
	return((r->ro != NULL) & (r->ro != &Aftplane));
}
Beispiel #17
0
int
o_cone(			/* intersect ray with cone */
	OBJREC  *o,
	RAY  *r
)
{
	FVECT  rox, rdx;
	double  a, b, c;
	double  root[2];
	int  nroots, rn;
	CONE  *co;
	int  i;

						/* get cone structure */
	co = getcone(o, 1);

	/*
	 *     To intersect a ray with a cone, we transform the
	 *  ray into the cone's normalized space.  This greatly
	 *  simplifies the computation.
	 *     For a cone or cup, normalization results in the
	 *  equation:
	 *
	 *		x*x + y*y - z*z == 0
	 *
	 *     For a cylinder or tube, the normalized equation is:
	 *
	 *		x*x + y*y - r*r == 0
	 *
	 *     A normalized ring obeys the following set of equations:
	 *
	 *		z == 0			&&
	 *		x*x + y*y >= r0*r0	&&
	 *		x*x + y*y <= r1*r1
	 */

					/* transform ray */
	multp3(rox, r->rorg, co->tm);
	multv3(rdx, r->rdir, co->tm);
					/* compute intersection */

	if (o->otype == OBJ_CONE || o->otype == OBJ_CUP) {

		a = rdx[0]*rdx[0] + rdx[1]*rdx[1] - rdx[2]*rdx[2];
		b = 2.0*(rdx[0]*rox[0] + rdx[1]*rox[1] - rdx[2]*rox[2]);
		c = rox[0]*rox[0] + rox[1]*rox[1] - rox[2]*rox[2];

	} else if (o->otype == OBJ_CYLINDER || o->otype == OBJ_TUBE) {

		a = rdx[0]*rdx[0] + rdx[1]*rdx[1];
		b = 2.0*(rdx[0]*rox[0] + rdx[1]*rox[1]);
		c = rox[0]*rox[0] + rox[1]*rox[1] - CO_R0(co)*CO_R0(co);

	} else { /* OBJ_RING */

		if (rdx[2] <= FTINY && rdx[2] >= -FTINY)
			return(0);			/* parallel */
		root[0] = -rox[2]/rdx[2];
		if (root[0] <= FTINY || root[0] >= r->rot)
			return(0);			/* distance check */
		b = root[0]*rdx[0] + rox[0];
		c = root[0]*rdx[1] + rox[1];
		a = b*b + c*c;
		if (a < CO_R0(co)*CO_R0(co) || a > CO_R1(co)*CO_R1(co))
			return(0);			/* outside radii */
		r->ro = o;
		r->rot = root[0];
		VSUM(r->rop, r->rorg, r->rdir, r->rot);
		VCOPY(r->ron, co->ad);
		r->rod = -rdx[2];
		r->rox = NULL;
		return(1);				/* good */
	}
					/* roots for cone, cup, cyl., tube */
	nroots = quadratic(root, a, b, c);

	for (rn = 0; rn < nroots; rn++) {	/* check real roots */
		if (root[rn] <= FTINY)
			continue;		/* too small */
		if (root[rn] >= r->rot)
			break;			/* too big */
						/* check endpoints */
		VSUM(rox, r->rorg, r->rdir, root[rn]);
		VSUB(rdx, rox, CO_P0(co));
		b = DOT(rdx, co->ad); 
		if (b < 0.0)
			continue;		/* before p0 */
		if (b > co->al)
			continue;		/* after p1 */
		r->ro = o;
		r->rot = root[rn];
		VCOPY(r->rop, rox);
						/* get normal */
		if (o->otype == OBJ_CYLINDER)
			a = CO_R0(co);
		else if (o->otype == OBJ_TUBE)
			a = -CO_R0(co);
		else { /* OBJ_CONE || OBJ_CUP */
			c = CO_R1(co) - CO_R0(co);
			a = CO_R0(co) + b*c/co->al;
			if (o->otype == OBJ_CUP) {
				c = -c;
				a = -a;
			}
		}
		for (i = 0; i < 3; i++)
			r->ron[i] = (rdx[i] - b*co->ad[i])/a;
		if (o->otype == OBJ_CONE || o->otype == OBJ_CUP)
			for (i = 0; i < 3; i++)
				r->ron[i] = (co->al*r->ron[i] - c*co->ad[i])
						/ co->sl;
		a = DOT(r->ron, r->ron);
		if (a > 1.+FTINY || a < 1.-FTINY) {
			c = 1./(.5 + .5*a);     /* avoid numerical error */
			r->ron[0] *= c; r->ron[1] *= c; r->ron[2] *= c;
		}
		r->rod = -DOT(r->rdir, r->ron);
		r->pert[0] = r->pert[1] = r->pert[2] = 0.0;
		r->uv[0] = r->uv[1] = 0.0;
		r->rox = NULL;
		return(1);			/* good */
	}
	return(0);
}
Beispiel #18
0
static int
raymove(		/* check for hit as we move */
	FVECT  pos,			/* current position, modified herein */
	OBJECT  *cxs,			/* checked objects, modified by checkhit */
	int  dirf,			/* direction indicators to speed tests */
	RAY  *r,
	CUBE  *cu
)
{
	int  ax;
	double  dt, t;

	if (istree(cu->cutree)) {		/* recurse on subcubes */
		CUBE  cukid;
		int  br, sgn;

		cukid.cusize = cu->cusize * 0.5;	/* find subcube */
		VCOPY(cukid.cuorg, cu->cuorg);
		br = 0;
		if (pos[0] >= cukid.cuorg[0]+cukid.cusize) {
			cukid.cuorg[0] += cukid.cusize;
			br |= 1;
		}
		if (pos[1] >= cukid.cuorg[1]+cukid.cusize) {
			cukid.cuorg[1] += cukid.cusize;
			br |= 2;
		}
		if (pos[2] >= cukid.cuorg[2]+cukid.cusize) {
			cukid.cuorg[2] += cukid.cusize;
			br |= 4;
		}
		for ( ; ; ) {
			cukid.cutree = octkid(cu->cutree, br);
			if ((ax = raymove(pos,cxs,dirf,r,&cukid)) == RAYHIT)
				return(RAYHIT);
			sgn = 1 << ax;
			if (sgn & dirf)			/* positive axis? */
				if (sgn & br)
					return(ax);	/* overflow */
				else {
					cukid.cuorg[ax] += cukid.cusize;
					br |= sgn;
				}
			else
				if (sgn & br) {
					cukid.cuorg[ax] -= cukid.cusize;
					br &= ~sgn;
				} else
					return(ax);	/* underflow */
		}
		/*NOTREACHED*/
	}
	if (isfull(cu->cutree)) {
		if (checkhit(r, cu, cxs))
			return(RAYHIT);
	} else if (r->ro == &Aftplane && incube(cu, r->rop))
		return(RAYHIT);
					/* advance to next cube */
	if (dirf&0x11) {
		dt = dirf&1 ? cu->cuorg[0] + cu->cusize : cu->cuorg[0];
		t = (dt - pos[0])/r->rdir[0];
		ax = 0;
	} else
		t = FHUGE;
	if (dirf&0x22) {
		dt = dirf&2 ? cu->cuorg[1] + cu->cusize : cu->cuorg[1];
		dt = (dt - pos[1])/r->rdir[1];
		if (dt < t) {
			t = dt;
			ax = 1;
		}
	}
	if (dirf&0x44) {
		dt = dirf&4 ? cu->cuorg[2] + cu->cusize : cu->cuorg[2];
		dt = (dt - pos[2])/r->rdir[2];
		if (dt < t) {
			t = dt;
			ax = 2;
		}
	}
	VSUM(pos, pos, r->rdir, t);
	return(ax);
}
Beispiel #19
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--;
	}
}
Beispiel #20
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);
}
Beispiel #21
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);
}
Beispiel #22
0
int
m_aniso(			/* shade ray that hit something anisotropic */
	OBJREC  *m,
	RAY  *r
)
{
	ANISODAT  nd;
	COLOR  ctmp;
	int  i;
						/* easy shadow test */
	if (r->crtype & SHADOW)
		return(1);

	if (m->oargs.nfargs != (m->otype == MAT_TRANS2 ? 8 : 6))
		objerror(m, USER, "bad number of real arguments");
						/* check for back side */
	if (r->rod < 0.0) {
		if (!backvis) {
			raytrans(r);
			return(1);
		}
		raytexture(r, m->omod);
		flipsurface(r);			/* reorient if backvis */
	} else
		raytexture(r, m->omod);
						/* get material color */
	nd.mp = m;
	nd.rp = r;
	setcolor(nd.mcolor, m->oargs.farg[0],
			   m->oargs.farg[1],
			   m->oargs.farg[2]);
						/* get roughness */
	nd.specfl = 0;
	nd.u_alpha = m->oargs.farg[4];
	nd.v_alpha = m->oargs.farg[5];
	if ((nd.u_alpha <= FTINY) | (nd.v_alpha <= FTINY))
		objerror(m, USER, "roughness too small");

	nd.pdot = raynormal(nd.pnorm, r);	/* perturb normal */
	if (nd.pdot < .001)
		nd.pdot = .001;			/* non-zero for diraniso() */
	multcolor(nd.mcolor, r->pcol);		/* modify material color */
						/* get specular component */
	if ((nd.rspec = m->oargs.farg[3]) > FTINY) {
		nd.specfl |= SP_REFL;
						/* compute specular color */
		if (m->otype == MAT_METAL2)
			copycolor(nd.scolor, nd.mcolor);
		else
			setcolor(nd.scolor, 1.0, 1.0, 1.0);
		scalecolor(nd.scolor, nd.rspec);
						/* check threshold */
		if (specthresh >= nd.rspec-FTINY)
			nd.specfl |= SP_RBLT;
						/* compute refl. direction */
		VSUM(nd.vrefl, r->rdir, nd.pnorm, 2.0*nd.pdot);
		if (DOT(nd.vrefl, r->ron) <= FTINY)	/* penetration? */
			VSUM(nd.vrefl, r->rdir, r->ron, 2.0*r->rod);
	}
						/* compute transmission */
	if (m->otype == MAT_TRANS2) {
		nd.trans = m->oargs.farg[6]*(1.0 - nd.rspec);
		nd.tspec = nd.trans * m->oargs.farg[7];
		nd.tdiff = nd.trans - nd.tspec;
		if (nd.tspec > FTINY) {
			nd.specfl |= SP_TRAN;
							/* check threshold */
			if (specthresh >= nd.tspec-FTINY)
				nd.specfl |= SP_TBLT;
			if (DOT(r->pert,r->pert) <= FTINY*FTINY) {
				VCOPY(nd.prdir, r->rdir);
			} else {
				for (i = 0; i < 3; i++)		/* perturb */
					nd.prdir[i] = r->rdir[i] - r->pert[i];
				if (DOT(nd.prdir, r->ron) < -FTINY)
					normalize(nd.prdir);	/* OK */
				else
					VCOPY(nd.prdir, r->rdir);
			}
		}
	} else
		nd.tdiff = nd.tspec = nd.trans = 0.0;

						/* diffuse reflection */
	nd.rdiff = 1.0 - nd.trans - nd.rspec;

	if (r->ro != NULL && isflat(r->ro->otype))
		nd.specfl |= SP_FLAT;

	getacoords(&nd);			/* set up coordinates */

	if (nd.specfl & (SP_REFL|SP_TRAN))
		agaussamp(&nd);

	if (nd.rdiff > FTINY) {		/* ambient from this side */
		copycolor(ctmp, nd.mcolor);	/* modified by material color */
		scalecolor(ctmp, nd.rdiff);
		if (nd.specfl & SP_RBLT)	/* add in specular as well? */
			addcolor(ctmp, nd.scolor);
		multambient(ctmp, r, nd.pnorm);
		addcolor(r->rcol, ctmp);	/* add to returned color */
	}
	if (nd.tdiff > FTINY) {		/* ambient from other side */
		FVECT  bnorm;

		flipsurface(r);
		bnorm[0] = -nd.pnorm[0];
		bnorm[1] = -nd.pnorm[1];
		bnorm[2] = -nd.pnorm[2];
		copycolor(ctmp, nd.mcolor);	/* modified by color */
		if (nd.specfl & SP_TBLT)
			scalecolor(ctmp, nd.trans);
		else
			scalecolor(ctmp, nd.tdiff);
		multambient(ctmp, r, bnorm);
		addcolor(r->rcol, ctmp);
		flipsurface(r);
	}
					/* add direct component */
	direct(r, diraniso, &nd);

	return(1);
}