Moving Sphere to Static Sphere

Moving Sphere to Sphere

A moving sphere to a static sphere test is basically a slightly modified ray to sphere test.
First, we expand the static sphere’s radius by the moving sphere’s radius. Then, we call our ray to sphere function, sending the normalized velocity vector as the ray’s direction.
Then, we just need to check if the collision point is actually within the boundaries of the line created by the trajectory, so we check if the collision time is less than or equal to the length of the un-normalized velocity vector.

Here’s some sample C++ code to perform this check using the DirectX vector functions. It also contains the code for the ray to sphere test that we need to perform.

struct TRay
{
    D3DXVECTOR3 m_vecDir;
    D3DXVECTOR3 m_vecStart;
};

struct TSphere
{
    D3DXVECTOR3    m_vecCenter;
    float          m_fRadius;
};

bool MovingSphereToSphere(const TSphere& tMovingSphere, const D3DXVECTOR3& vecSphereVel, const TSphere& tStaticSphere, float& fT)
{
    //First, we create a new sphere based on the static sphere's position but with the radius of both spheres
    TSphere tempSphere(tStaticSphere);
    tempSphere.m_fRadius += tMovingSphere.m_fRadius;

    //Now, we get the length of our sphere's velocity. We will use this for the ray to sphere test and to check against collision time
    float fVecLength = D3DXVec3Length(&vecSphereVel);

    //We create a ray that starts at the moving sphere's center and has a direction of the normalized velocity
    TRay tempRay;
    tempRay.m_vecStart = tMovingSphere.m_vecCenter;
    tempRay.m_vecDir = vecSphereVel / fVecLength;

    //We call our ray to sphere function,
    if(RayToSphere(tempRay, tempSphere, fT))
    {
        //We check if the time is less than or equal to the velocity's length
        if(fT <= fVecLength)
        {
            return true;
        }
    }
    return false;
}

bool RayToSphere(const TRay& tRay, const TSphere& tSphere, float &fT)
{
    //Create a vector from the sphere to the ray's start point
    D3DXVECTOR3 vecV1 = tRay.m_vecStart - tSphere.m_vecCenter;

    //Get the dot product of this vector with the ray's direction
    //This will become the 'b' part of our quadratic equation
    float fB = D3DXVec3Dot(&vecV1, &tRay.m_vecDir);

    //Get the square distance from the start of the ray to the sphere's surface
    //This will become the 'c' part of our quadratic equation
    float fC = D3DXVec3Dot(&vecV1, &vecV1) - (tSphere.m_fRadius * tSphere.m_fRadius);

    //If the ray starts outside the sphere and points away from it, we return false
    if( fC > 0.0f && fB > 0.0f)
        return false;
   
    //Else, we get the discriminant for our equation
    float fDisc = fB*fB - fC;

    //If this is less than zero, we return false
    if( fDisc < 0.0f)
        return false;

    //If we didn't want the time of collision, we could just return true here.
    //But in this case we do want it, so we'll continue

    //We solve our equation and get the time of collision
        //We use -sqrt(fDisc) to get the smallest root, ie. the first point in which the ray touches the sphere
    fT = -fB - sqrt(fDisc);

    //If the time is less than zero, it means the ray started inside the sphere
    //If so, we just make it zero
    if(fT < 0.0f)
        fT = 0.0f;

    //Our collision point is going to be:
    //tRay.m_vecStart + tRay.m_vecDir * fT
    return true;

}