@ -792,27 +792,196 @@ public class BoundingSphere extends BoundingVolume {
return 1 ;
}
}
private int collideWithTri ( Triangle tri , CollisionResults results ) {
TempVars tvars = TempVars . get ( ) ;
try {
// Much of this is based on adaptation from this algorithm:
// http://realtimecollisiondetection.net/blog/?p=103
// ...mostly the stuff about eliminating sqrts wherever
// possible.
public int collideWith ( Collidable other , CollisionResults results ) {
if ( other instanceof Ray ) {
Ray ray = ( Ray ) other ;
return collideWithRay ( ray , results ) ;
} else if ( other instanceof Triangle ) {
Triangle t = ( Triangle ) other ;
// Math is done in center-relative space.
Vector3f a = tri . get1 ( ) . subtract ( center , tvars . vect1 ) ;
Vector3f b = tri . get2 ( ) . subtract ( center , tvars . vect2 ) ;
Vector3f c = tri . get3 ( ) . subtract ( center , tvars . vect3 ) ;
Vector3f ab = b . subtract ( a , tvars . vect4 ) ;
Vector3f ac = c . subtract ( a , tvars . vect5 ) ;
// Check the plane... if it doesn't intersect the plane
// then it doesn't intersect the triangle.
Vector3f n = ab . cross ( ac , tvars . vect6 ) ;
float d = a . dot ( n ) ;
float e = n . dot ( n ) ;
if ( d * d > radius * radius * e ) {
// Can't possibly intersect
return 0 ;
}
// We intersect the verts, or the edges, or the face...
// First check against the face since it's the most
// specific.
// Calculate the barycentric coordinates of the
// sphere center
Vector3f v0 = ac ;
Vector3f v1 = ab ;
// a was P relative, so p.subtract(a) is just -a
// instead of wasting a vector we'll just negate the
// dot products below... it's all v2 is used for.
Vector3f v2 = a ;
float dot00 = v0 . dot ( v0 ) ;
float dot01 = v0 . dot ( v1 ) ;
float dot02 = - v0 . dot ( v2 ) ;
float dot11 = v1 . dot ( v1 ) ;
float dot12 = - v1 . dot ( v2 ) ;
float r2 = radius * radius ;
float d1 = center . distanceSquared ( t . get1 ( ) ) ;
float d2 = center . distanceSquared ( t . get2 ( ) ) ;
float d3 = center . distanceSquared ( t . get3 ( ) ) ;
float invDenom = 1 / ( dot00 * dot11 - dot01 * dot01 ) ;
float u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom ;
float v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom ;
if ( d1 < = r2 | | d2 < = r2 | | d3 < = r2 ) {
CollisionResult r = new CollisionResult ( ) ;
r . setDistance ( FastMath . sqrt ( Math . min ( Math . min ( d1 , d2 ) , d3 ) ) - radius ) ;
if ( u > = 0 & & v > = 0 & & ( u + v ) < 1 ) {
// We intersect... and we even know where
Vector3f part1 = ac ;
Vector3f part2 = ab ;
Vector3f p = center . add ( a . add ( part1 . mult ( u ) ) . addLocal ( part2 . mult ( v ) ) ) ;
CollisionResult r = new CollisionResult ( ) ;
r . setDistance ( ( float ) Math . sqrt ( d ) - radius ) ;
r . setContactNormal ( n . normalize ( ) ) ;
r . setContactPoint ( p ) ;
results . addCollision ( r ) ;
return 1 ;
}
// Check the edges looking for the nearest point
// that is also less than the radius. We don't care
// about points that are farther away than that.
Vector3f nearestPt = null ;
float nearestDist = radius * radius ;
Vector3f base ;
Vector3f edge ;
float t ;
// Edge AB
base = a ;
edge = ab ;
t = - edge . dot ( base ) / edge . dot ( edge ) ;
if ( t > = 0 & & t < = 1 ) {
Vector3f Q = base . add ( edge . mult ( t , tvars . vect7 ) , tvars . vect8 ) ;
float distSq = Q . dot ( Q ) ; // distance squared to origin
if ( distSq < nearestDist ) {
nearestPt = Q ;
nearestDist = distSq ;
}
}
// Edge AC
base = a ;
edge = ac ;
t = - edge . dot ( base ) / edge . dot ( edge ) ;
if ( t > = 0 & & t < = 1 ) {
Vector3f Q = base . add ( edge . mult ( t , tvars . vect7 ) , tvars . vect8 ) ;
float distSq = Q . dot ( Q ) ; // distance squared to origin
if ( distSq < nearestDist ) {
nearestPt = Q ;
nearestDist = distSq ;
}
}
// Edge BC
base = b ;
Vector3f bc = c . subtract ( b ) ;
edge = bc ;
t = - edge . dot ( base ) / edge . dot ( edge ) ;
if ( t > = 0 & & t < = 1 ) {
Vector3f Q = base . add ( edge . mult ( t , tvars . vect7 ) , tvars . vect8 ) ;
float distSq = Q . dot ( Q ) ; // distance squared to origin
if ( distSq < nearestDist ) {
nearestPt = Q ;
nearestDist = distSq ;
}
}
// If we have a point at all then it is going to be
// closer than any vertex to center distance... so we're
// done.
if ( nearestPt ! = null ) {
// We have a hit
float dist = FastMath . sqrt ( nearestDist ) ;
Vector3f cn = nearestPt . divide ( - dist ) ;
CollisionResult r = new CollisionResult ( ) ;
r . setDistance ( dist ) ;
r . setContactNormal ( cn ) ;
r . setContactPoint ( nearestPt . add ( center ) ) ;
results . addCollision ( r ) ;
return 1 ;
}
// Finally check each of the triangle corners
// Vert A
base = a ;
t = base . dot ( base ) ; // distance squared to origin
if ( t < nearestDist ) {
nearestDist = t ;
nearestPt = base ;
}
// Vert B
base = b ;
t = base . dot ( base ) ; // distance squared to origin
if ( t < nearestDist ) {
nearestDist = t ;
nearestPt = base ;
}
// Vert C
base = c ;
t = base . dot ( base ) ; // distance squared to origin
if ( t < nearestDist ) {
nearestDist = t ;
nearestPt = base ;
}
if ( nearestPt ! = null ) {
// We have a hit
float dist = FastMath . sqrt ( nearestDist ) ;
Vector3f cn = nearestPt . divide ( - dist ) ;
CollisionResult r = new CollisionResult ( ) ;
r . setDistance ( dist ) ;
r . setContactNormal ( cn ) ;
r . setContactPoint ( nearestPt . add ( center ) ) ;
results . addCollision ( r ) ;
return 1 ;
}
// Nothing hit... oh, well
return 0 ;
} finally {
tvars . release ( ) ;
}
}
public int collideWith ( Collidable other , CollisionResults results ) {
if ( other instanceof Ray ) {
Ray ray = ( Ray ) other ;
return collideWithRay ( ray , results ) ;
} else if ( other instanceof Triangle ) {
Triangle t = ( Triangle ) other ;
return collideWithTri ( t , results ) ;
} else {
throw new UnsupportedCollisionException ( ) ;
}