Example #1
0
void ntlTree::intersectX(const ntlRay &ray, gfxReal &distance, 
		ntlVec3Gfx &normal, 
		ntlTriangle *&tri, 
		int flags, bool forceNonsmooth) const
{
  gfxReal mint = GFX_REAL_MAX;  /* current minimal t */
  ntlVec3Gfx  retnormal;       /* intersection (interpolated) normal */
	gfxReal mintu=0.0, mintv=0.0;    /* u,v for min t intersection */

  BSPNode *curr, *nearChild, *farChild; /* current node and children */
  gfxReal  planedist, mindist, maxdist;
  ntlVec3Gfx   pos;

	ntlTriangle *hit = NULL;
	tri = NULL;

  ray.intersectCompleteAABB(mStart,mEnd,mindist,maxdist); // +X

  if((maxdist < 0.0) ||
		 (!mpRoot) ||
     (mindist == GFX_REAL_MAX) ||
     (maxdist == GFX_REAL_MAX) ) {
    distance = -1.0;
    return;
  }
  mindist -= getVecEpsilon();
  maxdist += getVecEpsilon();

  /* stack init */
  mpNodeStack->elem[0].node = NULL;
  mpNodeStack->stackPtr = 1;

  curr = mpRoot;  
  mint = GFX_REAL_MAX;
  while(curr != NULL) { // +X

    while( !curr->isLeaf() ) {
      planedist = distanceToPlane(curr, curr->child[0]->max, ray );
      getChildren(curr, ray.getOrigin(), nearChild, farChild );

			// check ray direction for small plane distances
      if( (planedist>-getVecEpsilon() )&&(planedist< getVecEpsilon() ) ) {
				// ray origin on intersection plane
				planedist = 0.0;
				if(ray.getDirection()[curr->axis]>getVecEpsilon() ) {
					// larger coords
					curr = curr->child[1];
				} else if(ray.getDirection()[curr->axis]<-getVecEpsilon() ) {
					// smaller coords
					curr = curr->child[0];
				} else {
					// paralell, order doesnt really matter are min/max/plane ok?
					mpNodeStack->elem[ mpNodeStack->stackPtr ].node    = curr->child[0];
					mpNodeStack->elem[ mpNodeStack->stackPtr ].mindist = planedist;
					mpNodeStack->elem[ mpNodeStack->stackPtr ].maxdist = maxdist;
					(mpNodeStack->stackPtr)++;
					curr    = curr->child[1];
					maxdist = planedist;
				}
			} else {
				// normal ray
				if( (planedist>maxdist) || (planedist<0.0-getVecEpsilon() ) ) {
					curr = nearChild;
				} else if(planedist < mindist) {
					curr = farChild;
				} else {
					mpNodeStack->elem[ mpNodeStack->stackPtr ].node    = farChild;
					mpNodeStack->elem[ mpNodeStack->stackPtr ].mindist = planedist;
					mpNodeStack->elem[ mpNodeStack->stackPtr ].maxdist = maxdist;
					(mpNodeStack->stackPtr)++;

					curr    = nearChild;
					maxdist = planedist;
				}
			} 
    } // +X
	
    
    /* intersect with current node */
    for (vector<ntlTriangle *>::iterator iter = curr->members->begin();
				 iter != curr->members->end(); iter++ ) {

			/* check for triangle flags before intersecting */
			if((!flags) || ( ((*iter)->getFlags() & flags) > 0 )) {

				if( ((*iter)->getLastRay() == ray.getID() )&&((*iter)->getLastRay()>0) ) {
					// was already intersected...
				} else {
					// we still need to intersect this triangle
					gfxReal u=0.0,v=0.0, t=-1.0;
					ray.intersectTriangleX( mpVertices, (*iter), t,u,v);
					(*iter)->setLastRay( ray.getID() );
					
					if( (t > 0.0) && (t<mint) )  {
						mint = t;	  
						hit = (*iter);
						mintu = u; mintv = v;
					}
				}

			} // flags check
    } // +X

    /* check if intersection is valid */
    if( (mint>0.0) && (mint < GFX_REAL_MAX) ) {
      pos = ray.getOrigin() + ray.getDirection()*mint;

      if( (pos[0] >= curr->min[0]) && (pos[0] <= curr->max[0]) &&
					(pos[1] >= curr->min[1]) && (pos[1] <= curr->max[1]) &&
					(pos[2] >= curr->min[2]) && (pos[2] <= curr->max[2]) ) 
			{

				if(forceNonsmooth) {
					// calculate triangle normal
					ntlVec3Gfx e0,e1,e2;
					e0 = (*mpVertices)[ hit->getPoints()[0] ];
					e1 = (*mpVertices)[ hit->getPoints()[1] ];
					e2 = (*mpVertices)[ hit->getPoints()[2] ];
					retnormal = cross( -(e2-e0), (e1-e0) );
				} else {
					// calculate interpolated normal
					retnormal = (*mpVertNormals)[ hit->getPoints()[0] ] * (1.0-mintu-mintv)+
						(*mpVertNormals)[ hit->getPoints()[1] ]*mintu +
						(*mpVertNormals)[ hit->getPoints()[2] ]*mintv;
				}
				normalize(retnormal);
				normal = retnormal;
				distance = mint;
				tri = hit;
				return;
      }
    }     // +X

    (mpNodeStack->stackPtr)--;
    curr    = mpNodeStack->elem[ mpNodeStack->stackPtr ].node;
    mindist = mpNodeStack->elem[ mpNodeStack->stackPtr ].mindist;
    maxdist = mpNodeStack->elem[ mpNodeStack->stackPtr ].maxdist;
  } /* traverse tree */

	if(mint == GFX_REAL_MAX) {
		distance = -1.0;
	} else {

		// intersection outside the BSP bounding volumes might occur due to roundoff...
		if(forceNonsmooth) {
			// calculate triangle normal
			ntlVec3Gfx e0,e1,e2;
			e0 = (*mpVertices)[ hit->getPoints()[0] ];
			e1 = (*mpVertices)[ hit->getPoints()[1] ];
			e2 = (*mpVertices)[ hit->getPoints()[2] ];
			retnormal = cross( -(e2-e0), (e1-e0) );
		} else {
			// calculate interpolated normal
			retnormal = (*mpVertNormals)[ hit->getPoints()[0] ] * (1.0-mintu-mintv)+
				(*mpVertNormals)[ hit->getPoints()[1] ]*mintu +
				(*mpVertNormals)[ hit->getPoints()[2] ]*mintv;
		}

		normalize(retnormal);
		normal = retnormal;
		distance = mint;
		tri = hit;
	} // +X
	return;
}