bool AABB::intersects( const Ray& ray, Vector& pt ) { // Rays starting and ending in an octree node must be considered // to hit the node. // if the start point OR the end point is in the AABB, then it's a hit. if( containsIn( ray.startPos ) || containsIn( ray.getEndPoint() ) ) { //generateDebugLines( Vector(0,1,0) ) ;//green is RAY STARTED INSIDE return true ; } Vector tmins, tmaxes ; // These are red in the profiler. tmins = (min - ray.startPos) / ray.direction ; tmaxes = (max - ray.startPos) / ray.direction ; Vector* sols[2] = { &tmins, &tmaxes } ; int solS=0, solI=0 ; real smallestT = HUGE ; // smallest valid t ("so far"). put at inf so first time everything smaller than it. Vector closestRaypoint ; // smallest rayPoint (associated with "smallest t so far") for( int s = 0 ; s < 2 ; s++ ) { Vector& candSols = *sols[s] ; // i walks xyz for( int i = 0 ; i < 3 ; i++ ) { real& t = candSols.e[i] ; // candidate t // validity: 0 <= t <= length if( BetweenIn( t, 0, ray.length ) ) { Vector raypoint = ray.at( t ) ; // AND ON FACE // o1 and o2 are the indices of the OTHER faces, // if i==0, o1=1, o2=2 int o1 = ( i + 1 ) % 3 ; // if( i==0 ) o1=1, o2=2; int o2 = ( i + 2 ) % 3 ; // else if( i == 1) o1=2, o2=0; if( InRect( raypoint.e[ o1 ],raypoint.e[ o2 ], min.e[o1], min.e[o2], max.e[o1], max.e[o2] ) ) { // this one wins, if it's smallest so far if( t < smallestT ) { smallestT = t ; closestRaypoint = raypoint ; // record what face it was solS = s ; solI = i ; } } } } } // now here, it's possible smallestT was unassigned, // which means it'll still be HUGE if( smallestT == HUGE ) { // no solution ///generateDebugLines( Vector(.2,.2,.2) ) ;//total miss return false ; } else { // there was an intersection. ///generateDebugLines( Vector(1,0,0) ) ;//red means it was a hit pt = closestRaypoint ; return true ; } }
bool AABB::intersects( const Ray& ray ) { // VERY IMPORTANT CHECK: If the ray starts inside // the box, then it's a hit. This was important for octrees. if( containsIn( ray.startPos ) || containsIn( ray.getEndPoint() ) ) return true ; #define TECH 0 #if TECH==0 // the algorithm says, find 3 t's, Vector t ; // LARGEST t is the only only we need to test if it's on the face. for( int i = 0 ; i < 3 ; i++ ) { if( ray.direction.e[i] > 0 ) // CULL BACK FACE t.e[i] = ( min.e[i] - ray.startPos.e[i] ) / ray.direction.e[i] ; else t.e[i] = ( max.e[i] - ray.startPos.e[i] ) / ray.direction.e[i] ; } int mi = t.maxIndex() ; if( BetweenIn( t.e[mi], 0, ray.length ) ) { Vector pt = ray.at( t.e[mi] ) ; // check it's in the box in other 2 dimensions int o1 = ( mi + 1 ) % 3 ; // i=0: o1=1, o2=2, i=1: o1=2,o2=0 etc. int o2 = ( mi + 2 ) % 3 ; return BetweenIn( pt.e[o1], min.e[o1], max.e[o1] ) && BetweenIn( pt.e[o2], min.e[o2], max.e[o2] ) ; } return false ; #elif TECH==1 // This culls the back faces first, and gives you the answer with the largest valid t for( int i = 0 ; i < 3 ; i++ ) { int o1 = ( i + 1 ) % 3 ; // i=0: o1=1, o2=2, i=1: o1=2,o2=0 etc. int o2 = ( i + 2 ) % 3 ; // min.x (NX) is possible, PX won't be hit. (unless you're inside the box.) if( ray.direction.e[i] > 0 ) // CULL BACK FACE { real t = ( min.e[i] - ray.startPos.e[i] ) / ray.direction.e[i] ; // 1. CHECK VALID T if( BetweenIn( t, 0, ray.length ) ) { // 2. CHECK IN BOX Vector pt = ray.at( t ) ; if( BetweenIn( pt.e[o1], min.e[o1], max.e[o1] ) && BetweenIn( pt.e[o2], min.e[o2], max.e[o2] ) ) return true ; // it's valid in the box } } else if( ray.direction.e[i] < 0 ) // max.x (PX) is possible { real t = ( max.e[i] - ray.startPos.e[i] ) / ray.direction.e[i] ; if( BetweenIn( t, 0, ray.length ) ) // valid t { Vector pt = ray.at( t ) ; if( BetweenIn( pt.e[o1], min.e[o1], max.e[o1] ) && BetweenIn( pt.e[o2], min.e[o2], max.e[o2] ) ) return true ; // it's valid in the box } } } return false ; // no hit. #elif TECH==2 // This solves ALL 6 solutions and finds the shortest t. // Rays starting and ending in an octree node must be considered // to hit the node. // if the start point OR the end point is in the AABB, then it's a hit. // These are red in the profiler. Vector tmins = (min - ray.startPos) / ray.direction ; Vector tmaxes = (max - ray.startPos) / ray.direction ; Vector* sols[2] = { &tmins, &tmaxes } ; for( int s = 0 ; s < 2 ; s++ ) { Vector& candSols = *sols[s] ; // i walks xyz for( int i = 0 ; i < 3 ; i++ ) { real& t = candSols.e[i] ; // candidate t // validity: 0 <= t <= length if( BetweenIn( t, 0, ray.length ) ) { Vector raypoint = ray.at( t ) ; // AND ON FACE // o1 and o2 are the indices of the OTHER faces, // if i==0, o1=1, o2=2 int o1 = ( i + 1 ) % 3 ; // if( i==0 ) o1=1, o2=2; int o2 = ( i + 2 ) % 3 ; // else if( i == 1) o1=2, o2=0; if( InRect( raypoint.e[ o1 ],raypoint.e[ o2 ], min.e[o1], min.e[o2], max.e[o1], max.e[o2] ) ) { // the box got hit, any side return true ; } } } } // No hit return false ; #endif }