extern int o_instance( /* compute ray intersection with octree */ OBJREC *o, register RAY *r ) { RAY rcont; double d; register INSTANCE *ins; register int i; /* get the octree */ ins = getinstance(o, IO_ALL); /* copy and transform ray */ rcont = *r; multp3(rcont.rorg, r->rorg, ins->x.b.xfm); multv3(rcont.rdir, r->rdir, ins->x.b.xfm); for (i = 0; i < 3; i++) rcont.rdir[i] /= ins->x.b.sca; rcont.rmax *= ins->x.b.sca; /* clear and trace it */ rayclear(&rcont); if (!localhit(&rcont, &ins->obj->scube)) return(0); /* missed */ if (rcont.rot * ins->x.f.sca >= r->rot) return(0); /* not close enough */ if (o->omod != OVOID) { /* if we have modifier, use it */ r->ro = o; r->rox = NULL; } else { /* else use theirs */ r->ro = rcont.ro; if (rcont.rox != NULL) { newrayxf(r); /* allocate transformation */ /* NOTE: r->rox may equal rcont.rox! */ multmat4(r->rox->f.xfm, rcont.rox->f.xfm, ins->x.f.xfm); r->rox->f.sca = rcont.rox->f.sca * ins->x.f.sca; multmat4(r->rox->b.xfm, ins->x.b.xfm, rcont.rox->b.xfm); r->rox->b.sca = ins->x.b.sca * rcont.rox->b.sca; } else r->rox = &ins->x; } /* transform it back */ r->rot = rcont.rot * ins->x.f.sca; multp3(r->rop, rcont.rop, ins->x.f.xfm); multv3(r->ron, rcont.ron, ins->x.f.xfm); multv3(r->pert, rcont.pert, ins->x.f.xfm); d = 1./ins->x.f.sca; for (i = 0; i < 3; i++) { r->ron[i] *= d; r->pert[i] *= d; } r->rod = rcont.rod; r->uv[0] = rcont.uv[0]; r->uv[1] = rcont.uv[1]; /* return hit */ return(1); }
void xf_xfmpoint(FVECT v1, FVECT v2) /* transform a point by the current matrix */ { if (xf_context == NULL) { VCOPY(v1, v2); return; } multp3(v1, v2, xf_context->xf.xfm); }
static int o_cube( /* determine if cubes intersect */ CUBE *cu1, FULLXF *fxf, CUBE *cu ) { static int vstart[4] = {0, 3, 5, 6}; FVECT cumin, cumax; FVECT vert[8]; FVECT v1, v2; int vloc, vout; register int i, j; /* check if cube vertex in octree */ for (j = 0; j < 3; j++) cumax[j] = (cumin[j] = cu1->cuorg[j]) + cu1->cusize; vloc = ABOVE | BELOW; vout = 0; for (i = 0; i < 8; i++) { for (j = 0; j < 3; j++) { v1[j] = cu->cuorg[j]; if (i & 1<<j) v1[j] += cu->cusize; } multp3(v2, v1, fxf->b.xfm); if ( (j = plocate(v2, cumin, cumax)) ) vout++; vloc &= j; } if (vout == 0) /* all inside */ return(O_IN); if (vout < 8) /* some inside */ return(O_HIT); if (vloc) /* all to one side */ return(O_MISS); /* octree vertices in cube? */ for (j = 0; j < 3; j++) cumax[j] = (cumin[j] = cu->cuorg[j]) + cu->cusize; vloc = ABOVE | BELOW; for (i = 0; i < 8; i++) { for (j = 0; j < 3; j++) { v1[j] = cu1->cuorg[j]; if (i & 1<<j) v1[j] += cu1->cusize; } multp3(vert[i], v1, fxf->f.xfm); if ( (j = plocate(vert[i], cumin, cumax)) ) vloc &= j; else return(O_HIT); /* vertex inside */ } if (vloc) /* all to one side */ return(O_MISS); /* check edges */ for (i = 0; i < 4; i++) for (j = 0; j < 3; j++) { /* clip modifies vertices! */ VCOPY(v1, vert[vstart[i]]); VCOPY(v2, vert[vstart[i] ^ 1<<j]); if (clip(v1, v2, cumin, cumax)) return(O_HIT); /* edge inside */ } return(O_MISS); /* no intersection */ }
void add2bbox( /* expand bounding box to fit object */ register OBJREC *o, FVECT bbmin, FVECT bbmax ) { CONE *co; FACE *fo; INSTANCE *io; MESHINST *mi; FVECT v; register int i, j; switch (o->otype) { case OBJ_SPHERE: case OBJ_BUBBLE: if (o->oargs.nfargs != 4) objerror(o, USER, "bad arguments"); for (i = 0; i < 3; i++) { VCOPY(v, o->oargs.farg); v[i] -= o->oargs.farg[3]; point2bbox(v, bbmin, bbmax); v[i] += 2.0 * o->oargs.farg[3]; point2bbox(v, bbmin, bbmax); } break; case OBJ_FACE: fo = getface(o); j = fo->nv; while (j--) point2bbox(VERTEX(fo,j), bbmin, bbmax); break; case OBJ_CONE: case OBJ_CUP: case OBJ_CYLINDER: case OBJ_TUBE: case OBJ_RING: co = getcone(o, 0); if (o->otype != OBJ_RING) circle2bbox(CO_P0(co), co->ad, CO_R0(co), bbmin, bbmax); circle2bbox(CO_P1(co), co->ad, CO_R1(co), bbmin, bbmax); break; case OBJ_INSTANCE: io = getinstance(o, IO_BOUNDS); for (j = 0; j < 8; j++) { for (i = 0; i < 3; i++) { v[i] = io->obj->scube.cuorg[i]; if (j & 1<<i) v[i] += io->obj->scube.cusize; } multp3(v, v, io->x.f.xfm); point2bbox(v, bbmin, bbmax); } break; case OBJ_MESH: mi = getmeshinst(o, IO_BOUNDS); for (j = 0; j < 8; j++) { for (i = 0; i < 3; i++) { v[i] = mi->msh->mcube.cuorg[i]; if (j & 1<<i) v[i] += mi->msh->mcube.cusize; } multp3(v, v, mi->x.f.xfm); point2bbox(v, bbmin, bbmax); } break; } }
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); }