|
|
|
@ -792,27 +792,200 @@ 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) { |
|
|
|
|
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(FastMath.sqrt(Math.min(Math.min(d1, d2), d3)) - radius); |
|
|
|
|
Vector3f normal = n.normalize(); |
|
|
|
|
float dist = -normal.dot(a); // a is center relative, so -a points to center
|
|
|
|
|
dist = dist - radius; |
|
|
|
|
|
|
|
|
|
r.setDistance(dist); |
|
|
|
|
r.setContactNormal(normal); |
|
|
|
|
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.vect9); |
|
|
|
|
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.vect10); |
|
|
|
|
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 - radius); |
|
|
|
|
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 - radius); |
|
|
|
|
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(); |
|
|
|
|
} |
|
|
|
|