home *** CD-ROM | disk | FTP | other *** search
- /************************************************************************
- * *
- * Copyright (c) 1988, David B. Wecker *
- * All Rights Reserved *
- * *
- * This file is part of DBW_uRAY *
- * *
- * DBW_uRAY is distributed in the hope that it will be useful, but *
- * WITHOUT ANY WARRANTY. No author or distributor accepts *
- * responsibility to anyone for the consequences of using it or for *
- * whether it serves any particular purpose or works at all, unless *
- * he says so in writing. Refer to the DBW_uRAY General Public *
- * License for full details. *
- * *
- * Everyone is granted permission to copy, modify and redistribute *
- * DBW_uRAY, but only under the conditions described in the *
- * DBW_uRAY General Public License. A copy of this license is *
- * supposed to have been given to you along with DBW_uRAY so you *
- * can know your rights and responsibilities. It should be in a file *
- * named COPYING. Among other things, the copyright notice and this *
- * notice must be preserved on all copies. *
- ************************************************************************
- * *
- * Authors: *
- * DBW - David B. Wecker *
- * *
- * Versions: *
- * V1.0 881023 DBW - First released version *
- * V1.1 881110 DBW - Fixed scan coherence code *
- * V1.2 881125 DBW - Removed ALL scan coherence code (useless) *
- * added "fat" extent boxes *
- * *
- ************************************************************************/
-
- #include "uray.h"
-
- /*************************************************************************/
- /******** This module computes all ray object intersections **************/
- /*************************************************************************/
-
- /* see if we hit a bounding box (n1 = near side, f1 = far side if good) */
- /* near point = from + n1 * direction */
- /* far point = from + f1 * direction */
-
- NODE *hitextent(s,n,f)
- EXTENT *s;
- FLTDBL *n,*f;
- {
-
- /* Use registers to be as efficient as possible */
- register FLTDBL n1 = -MYHUGE,f1 = MYHUGE,n2,f2,tval,sval;
- register int i;
-
- /* check each dimension of the bounding box */
- for (i=0; i<3; i++) {
-
- /* see which side of the box that we're on */
- if ((tval=dirinv[i]) < 0.0) {
- n2 = (s->max[i] - (sval=from[i])) * tval;
- f2 = (s->min[i] - sval) * tval;
- }
- else {
- n2 = (s->min[i] - (sval=from[i])) * tval;
- f2 = (s->max[i] - sval) * tval;
- }
-
- /* if new near is worse than the old near (and old far) then bad */
- if (n2 > n1 && (n1=n2) > f1) return NULL;
-
-
- /* if new far is worse than old far and (and old near) or if we're
- too close to 0 then return bad */
- if (f2 < f1 && ((f1=f2) < n1 || f1 < TOL)) return NULL;
- }
-
- /* are we worse than the far we ENTERED the routine with? */
- if (n1 > *f) return NULL;
-
- /* set the return values */
- *n = n1;
- *f = f1;
-
- /* return the object hit */
- return (NODE *)s;
- }
-
- /* see if we hit the sphere in question */
- NODE *hitsphere(s,n1)
- SPHERE *s;
- FLTDBL *n1;
- {
- register FLTDBL r_r,d_r,radical,t1,t2;
- VEC r;
-
- vcomb(-1.0, from, s->cen, r);
- r_r = vdot(r,r);
- d_r = vdot(direction,r);
-
- if ((radical = (d_r*d_r) + s->rad - r_r) < 0.0) return NULL;
- radical = sqrt(radical);
-
- if (d_r < radical) { t1 = d_r + radical; t2 = d_r - radical; }
- else { t1 = d_r - radical; t2 = d_r + radical; }
-
- /* since there are 2 possible intersection points, pick the best */
- if (t1 <= TOL) t1 = t2;
-
- /* are we too close to the intersection point */
- if (t1 <= TOL) return NULL;
-
- /* are we further than the bounding box intersection */
- if (t1 > *n1) return NULL;
-
- /* return the intersection point */
- *n1 = t1;
-
- /* return the object that we hit */
- return (NODE *)s;
- }
-
- /* take care of all planar intersections (quad, triangle, ring) */
- NODE *hitplane(q,n1)
- RING *q;
- FLTDBL *n1;
- {
- VEC sfs,h;
- FLTDBL det,r;
-
- /* First get the determinant of the interseection plane */
- det = q->v1[0] * ((q->v2[1] * direction[2])-(q->v2[2] * direction[1]));
- det -= q->v2[0] * ((q->v1[1] * direction[2])-(q->v1[2] * direction[1]));
- det += direction[0] * ((q->v1[1] * q->v2[2]) -(q->v1[2] * q->v2[1]));
-
- /* 0 determinant says that we missed the plane of intersection */
- if (det == 0.0) return NULL;
-
- vcomb(-1.0,q->p0,from,h);
-
- /* now build the exact intersection point */
- sfs[2] = h[0] * ((q->v1[1] * q->v2[2]) - (q->v1[2] * q->v2[1]));
- sfs[2] -= h[1] * ((q->v1[0] * q->v2[2]) - (q->v1[2] * q->v2[0]));
- sfs[2] += h[2] * ((q->v1[0] * q->v2[1]) - (q->v1[1] * q->v2[0]));
- sfs[2] /= det;
- sfs[2] = -sfs[2];
-
- /* Too close to 0? */
- if (sfs[2] <= TOL) return NULL;
-
- /* Further than bounding box? */
- if (sfs[2] > *n1) return NULL;
-
- /* Now build comparison points for each object type */
- sfs[0] = h[0] * ((q->v2[1] * direction[2]) - (q->v2[2] * direction[1]));
- sfs[0] -= h[1] * ((q->v2[0] * direction[2]) - (q->v2[2] * direction[0]));
- sfs[0] += h[2] * ((q->v2[0] * direction[1]) - (q->v2[1] * direction[0]));
- sfs[0] /= det;
-
- sfs[1] = h[0] * ((q->v1[2] * direction[1]) - (q->v1[1] * direction[2]));
- sfs[1] += h[1] * ((q->v1[0] * direction[2]) - (q->v1[2] * direction[0]));
- sfs[1] -= h[2] * ((q->v1[0] * direction[1]) - (q->v1[1] * direction[0]));
- sfs[1] /= det;
-
- switch (q->typ) {
-
- /* Make sure that we aren't off the triangles surface */
- case TYP_T:
- if (sfs[0] < 0.0 || sfs[1] < 0.0 || sfs[0]+sfs[1] > 1.0) return NULL;
- break;
-
- /* make sure that we're within the bounds of the quad */
- case TYP_Q:
- if (sfs[0] < 0.0 || sfs[1] < 0.0 || sfs[0] > 1.0 || sfs[1] > 1.0)
- return NULL;
- break;
-
- /* make sure that we're between the ring's radii */
- case TYP_R:
- r = sfs[0] * sfs[0] + sfs[1] * sfs[1];
- if (r > q->rad2 || r < q->rad1) return NULL;
- break;
- }
-
- /* return the intersection point */
- *n1 = sfs[2];
- return (NODE *)q;
- }
-
- /* recursive part of the intersection() routine */
- NODE *intersection2(cur,n1,f1)
- NODE *cur;
- FLTDBL *n1,*f1;
- {
-
- register NODE *best = NULL,*hit;
- register int i;
- FLTDBL ln1,lf1,ln2,lf2;
-
- /* save copies of the near and far intersection points (for extents) */
- ln1 = *n1;
- lf1 = *f1;
-
- /* check each object in the hierarchy */
- while (cur) {
-
- /* re-init the intersection points */
- hit = NULL;
- ln2 = ln1;
- lf2 = lf1;
-
- /* do the specific object */
- switch (cur->typ) {
-
- /* if we hit an extent, call ourselves recursively */
- case TYP_E:
- if (hitextent(cur,&ln2,&lf2)) {
- gehits++;
- hit = intersection2(((EXTENT *)cur)->child,&ln2,&lf2);
- }
- else fehits++;
- break;
-
- /* if we hit a sphere, save the intersection info */
- case TYP_S:
- hit = hitsphere(cur,&lf2);
- ln2 = lf2;
- break;
-
- /* if we hit a planar, save the intersection info */
- case TYP_T:
- case TYP_Q:
- case TYP_R:
- hit = hitplane(cur,&lf2);
- ln2 = lf2;
- break;
- }
-
- /* if NOT an extent, update the node statistics */
- if (cur->typ != TYP_E) {
- if (hit) gnhits++;
- else fnhits++;
- }
-
- /* if hit a non extent, then save this is the best so far */
- if (hit && hit->typ != TYP_E) {
- best = hit;
- ln1 = ln2;
- lf1 = lf2;
- }
-
- /* go get next object */
- cur = cur->next;
- }
-
- /* if we got something... return in */
- if (best) {
- *n1 = ln1;
- *f1 = lf1;
- }
- return best;
- }
-
- /* return closest node (frm + n1 * dir) or NULL */
- NODE *intersection(frm, dir, n1)
- VEC frm, dir;
- FLTDBL *n1;
- {
- register int i;
- NODE *hit = NULL;
- FLTDBL f1;
-
- /* initialize near and far */
- *n1 = -MYHUGE;
- f1 = MYHUGE;
-
- /* set up global vectors FROM, DIRECTION and DIRINV (inverse of dir) */
- for (i=0; i<3; i++) {
- from[i] = frm[i];
- direction[i] = dir[i];
- if (FABS(direction[i]) < TOL) {
- if (direction[i] < 0.0) dirinv[i] = -MYHUGE;
- else dirinv[i] = MYHUGE;
- }
- else dirinv[i] = 1.0 / direction[i];
- }
-
- /* call the recursive part of this routine */
- hit = intersection2(nodes,n1,&f1);
-
- /* return the result */
- return hit;
- }
-
-