When capsule collider height equals diameter it produces NaNs

If you flatten a capsule collider so it’s height equals its diameter (2x it’s radius). i.e. the capsule is actually a sphere

In this case, Vertex0 and Vertex1 are equal which should still be in theory fine but unfortunately causes NaNs within the physics simulation/queries when doing convex convex collisions.

I first spotted this when I made a fork of physics a couple of weeks ago to use as a small spatial library and ran into this issue, patched it and totally forgot about it.

However someone reported NaNs in our physics at work earlier this week so I had a bit of a dive and after some debugging, noticed the problem again. Thankfully as mentioned I had already run into this a couple of weeks ago so was easy to realize problem and patch once i spotted it.

This picture is within a spherecast hitting the capsule, hopefully it explains the problem enough.

My workaround for this in baking is to check for it, and replace it with a sphere.

case ShapeType.Capsule:
{
    res.CapsuleProperties = shape.GetCapsuleProperties()
        .BakeToBodySpace(localToWorld, shapeToWorld)
        .ToRuntime();

    // If 2*radius == height then switch to a sphere to avoid nans
    if (res.CapsuleProperties.Vertex0.Equals(res.CapsuleProperties.Vertex1))
    {
        res.ShapeType = ShapeType.Sphere;
        res.SphereProperties =
            shape.GetCapsuleSphereProperties(out orientation).BakeToBodySpace(localToWorld, shapeToWorld, ref orientation, bakeUniformScale);
    }
    break;
}

internal SphereGeometry GetCapsuleSphereProperties(out EulerAngles orientation)
{
    orientation = m_PrimitiveOrientation;
    return new SphereGeometry
    {
        Center = m_PrimitiveCenter,
        Radius = m_Capsule.Radius,
    };
}

i don’t know if this issue occurs with the regular CapsuleCollider or it’s limited to the older PhysicsShapeAuthoring. If it’s not limited to PhysicsShapeAuthoring then a better solution to fix it at runtime would be preferred though.

1 Like

Hi! We encountered that exact issue just recently internally. I’ll make sure it’s all good in future releases.
Thanks for calling it out.

Hey! Thank you very much for reporting this issue. Indeed, there is a division by zero when calculating the distance. So I think that instead of changing the collider to a sphere, it would be better to avoid that division. We will fix this problem in a future release!

So the fix would be something like this:

...
// Point-segment distance
float3 edgeA = capsuleVertex1 - capsuleVertex0;
float dot = math.dot(edgeA, centerB - capsuleVertex0);
float edgeLengthSquared = math.lengthsq(edgeA);

// If the capsule is degenerate (becomes a sphere), just use vertex0 as the point
if (edgeLengthSquared < distanceEpsSq)
{
    return PointPoint(capsuleVertex0, centerB, capsuleRadius, capsuleRadius + sphereRadius);
}

...