Collision Detection and Ellipsoids Tutorial By: Clifton Sweeney Collision Detection in Games covers: Car crashes, shooting, kicking, punching, beating, whacking, smashing, hitting, chopping, dicing, slicing, julienne fries… Expensive – Algorithm reaches Order N2 Collision detection in games is carried out into two easy steps: 1. Determine which pairs of shapes need to be tested for collision. 2. Determine collision results for each pair identified in step 1. In a virtual plane designers must take into account - Gravity - Bounce - Friction Psuedo code for intersection of a ray with a plane: double intersect(Point pOrigin, Vector pNormal, Point rOrigin, Vector rVector) { double d = -(planeNormal * planeOrigin); double numer = planeNormal * rayOrigin + d; double denom = planeNormal * rayVector; return -(numer / denom); } Determining collision points for your Ellipsoids: Find the bounding box of your sphere, centered on the source position Find the bounding box of your sphere, centered on the destination position Find the bounding box of those two bounding boxes Find all polygons that intersect that final bounding box Determining the closest point on a polygon: Point closestPointOnTriangle(Point a, Point b, Point c, Point p) { Point Rab = closestPointOnLine(a, b, p); Point Rbc = closestPointOnLine(b, c, p); Point Rca = closestPointOnLine(c, a, p); return closest [Rab, Rbc, Rca] to p; } Point closestPointOnLine(Point a, Point b, Point p) { // Determine t (the length of the vector from ‘a’ to ‘p’) Vector c = p - a; Vector V = Normalized vector [b – a]; double d = distance from a to b; double t = V * c; // Check to see if ‘t’ is beyond the extents of the line segment if (t < 0) return a; if (t > d) return b; // Return the point between ‘a’ and ‘b’ set length of V to t; return a + V; } Turn your sphere into an Ellipsoid This is a sphere turned into an ellipse with a radius vector of [3,6]. This results in an ellipse that is 6 units wide and 12 units tall. // The collision detection entry point collisionDetection(Point sourcePoint, Vector velocityVector, Vector gravityVector) { velocityVector += gravityVector; call collideWithWorld(sourcePoint, velocityVector); } // The collision detection recursive routine collideWithWorld(Point sourcePoint, Vector velocityVector) { // How far do we need to go? Double distanceToTravel = length of velocityVector; // Do we need to bother? if (distanceToTravel < EPSILON) return; Point destinationPoint = sourcePoint + velocityVector; // Whom might we collide with? List potentialColliders = determine list of potential colliders; // If there are none, we can safely move to the destination and bail if (potentialColliders is empty) { sourcePoint += velocityVector; return; } // Determine the nearest collider from the list potentialColliders bool firstTimeThrough = true; Double nearestDistance = -1.0; Poly nearestCollider = NULL; Point nearestIntersectionPoint = NULL; Point nearestPolygonIntersectionPoint = NULL; for (each polygon in potentialColliders) { // Plane origin/normal Point pOrigin = any vertex from the current polygon; Vector pNormal = surface normal from the current polygon; // Determine the distance from the plane to the source Double pDist = intersect(source, -pNormal, pOrigin, pNormal); Point sphereIntersectionPoint; Point planeIntersectionPoint; // The radius of the ellipsoid (in the direction of pNormal) Vector directionalRadius = -pNormal * radiusVector; Double radius = length of directionalRadius; // Is the plane embedded? if (fabs(pDist) <= radius) { // Calculate the plane intersection point Vector temp = -pNormal with length set to pDist; planeIntersectionPoint = source + temp; } else { // Calculate the ellipsoid intersection point Vector temp = -pNormal with length set to radius; ellipsoidIntersectionPoint = source + temp; // Calculate the plane intersection point Ray ray(sphereIntersectionPoint, Velocity); Double t = intersect(ellipsoidIntersectionPoint, Velocity, pOrigin, pNormal); // Calculate the plane intersection point Vector V = velocityVector with length set to t; planeIntersectionPoint = ellipsoidIntersectionPoint + V; } // Unless otherwise stated, our polygonIntersectionPoint is the // same point as planeIntersectionPoint Point polygonIntersectionPoint = planeIntersectionPoint; if (planeIntersectionPoint is not within the current polygon) { polygonIntersectionPoint = nearest point on polygon's perimeter to planeIntersectionPoint; } // Invert the velocity vector Vector negativeVelocityVector = -velocityVector; Double t = intersectEllipse(sourcePoint, radiusVector, polygonIntersectionPoint, negativeVelocityVector); if (t >= 0.0 && t <= distanceToTravel) { Vector V = negativeVelocityVector with length set to t; Vector intersectionPoint = polygonIntersectionPoint + V; // Closest intersection thus far? if (firstTimeThrough || t < nearestDistance) { nearestDistance = t; nearestCollider = current collider; nearestIntersectionPoint = intersectionPoint; nearestPolygonIntersectionPoint = polygonIntersectionPoint; firstTimeThrough = false; } } } if (firstTimeThrough) { sourcePoint += velocityVector; return; } // Move to the nearest collision Vector V = velocityVector with length set to (nearestDistance - EPSILON); sourcePoint += V; // Determine the sliding plane (we do this now, because we're about to // change sourcePoint) Point slidePlaneOrigin = nearestPolygonIntersectionPoint; Vector slidePlaneNormal = nearestPolygonIntersectionPoint - sourcePoint; Double time = intersect(destinationPoint, slidePlaneNormal, slidePlaneOrigin, slidePlaneNormal); Set length of slidePlaneNormal to time; Vector destinationProjectionNormal = slidePlaneNormal; Point newDestinationPoint = destination + destinationProjectionNormal; // Generate the slide vector, which will become our new velocity vector // for the next iteration Vector newVelocityVector = newDestinationPoint – nearestPolygonIntersectionPoint; // Recursively slide (without adding gravity) collideWithWorld(sourcePoint, newVelocityVector); } Resources: http://www.cc.gatech.edu/classes/AY2004/cs4455_fall/Lectures/08CollDet.ppt http://www.cs.unc.edu/~geom/collide/index.shtml http://www.gamedev.net/reference/articles/article1026.asp