Search code examples
3dgeometrycollision-detectiongame-physics

Collision detection - response between a moving sphere and a circular cylinder


I'm implementing a simple game that encorporates 3d logic. What is the procedure or/and the relative equations in order to detect if a moving sphere collides with a cylinder? My cylinder is static right circular and aligned to z axis. I read that cylinder's equation in this case is (x - a)² + (z - b)² = r², where

(a, b): center of cylinder r: radius of cylinder

How can I use it to find if the two objects intersect and, additionally, how can I apply the corresponding response of the ball?

Thank you


Solution

  • Often a cylinder to sphere test can be simplified to a point to line segment test where:

    1. the line segment represents the line running through the center of the cylinder from end to end and the end points are known.
    2. The point represents the centerPoint of the sphere.
    3. The test finds a point on the line segment that is closest to centerPoint and simply measures the distance between points and if it is less than sphere radius + cyl radius, it is colliding.

    The compromise with this is that it makes it effectively a sphere to capsule test rather than sphere to cylinder. If you can live with this compromise, here's some pseudo code.

    vector cylCenterVector = endPoint2 - endpoint1;
    float distanceFactorFromEP1 = Dot(sphereCenter - endPoint1) / Dot(cylCenterVector , cylCenterVector );
    if(distanceFactorFromEP1 < 0) distanceFactorFromEP1 = 0;// clamp to endpoints if neccesary
    if(distanceFactorFromEP1 > 1) distanceFactorFromEP1 = 1;
    vector closestPoint = endPoint1 + (cylCenterVector * distanceFactorFromEP1);
    
    vector collisionVector = sphereCenter - closestPoint;
    float distance = collisionVector.Length();
    vector collisionNormal = collisionVector / distance;
    
    if(distance < sphereRadius + cylRadius)
    {
      //collision occurred. use collisionNormal to reflect sphere off cyl
    
      float factor = Dot(velocity, collisionNormal);
    
      velocity = velocity - (2 * factor * collisionNormal);
    
    }