Transforming bounding spheres

When testing bounding spheres as part of the collision detection process, I'm using this method:

    public static BoundingSphere TransformBoundingSphere(Matrix m, BoundingSphere b)
{
var center = b.Center;
var edge = b.Center + Vector3.Right * b.Radius;

var worldCenter = Vector3.Transform(center, m);
var worldEdge = Vector3.Transform(edge, m);

return new BoundingSphere(worldCenter, (worldEdge - worldCenter).Length());
}


... to get a sphere in world coordinates (where m is a world matrix for the object encompassed by the original sphere).

(Yes, I'm aware that this relies on uniform scaling.)

This is obvious, reliable and easy, but is there a better way?

• Upvoted for noting that the resulting sphere in the target space may not be a sphere if the scaling is non-uniform. – legends2k Apr 3 '15 at 2:24

If the scaling is uniform and it is a known quantity, why not simply multiply b.Radius by the known scale. This will save cpu cycles by not having to perform the 2nd Vector3.Transform and a square root in the .Length() call

public static BoundingSphere TransformBoundingSphere(Matrix m, BoundingSphere b)
{
var worldCenter = Vector3.Transform(b.Center, m);

return new BoundingSphere(worldCenter, b.Radius * myUniformScale);
}


If you are sure your has a uniform scale and no skew components, then the non-translation part of the matrix can be expressed as M_33 = R * (s * I), where R is the an orthogonal rotation matrix, and s is the uniform scale. This is vaguely annoying so solve, but in 3d comes out to be:

scale_x = sqrt(m00^2 + m01^2 +m02^2);
// scale_y = sqrt(m10^2 + m11^2 +m12^2);
// scale_z = sqrt(m20^2 + m21^2 +m22^2);
// Assert(scale_x == scale_y == scale_z);


For transforms for game objects (that tend to have requirements like 'uniform scale'), it's often easier to store object transforms in their components, and compute the full matrix when necessary, as opposed to storing the full matrix and then having to extract the components.

struct Transform
{
Vector3 translation;
Quaternion rotation;
float scale;

Matrix44 ToMatrix44();
};


This form also assures the transform has the appropriate form and epsilon-ish errors don't sneak in, while maintaining composability.

• Good point on the storage of transforms. Additionally, by not storing it as a 4x4 matrix, you'd be saving quite a few bytes in memory: matrix = 256 bytes, yours = 32 bytes. You also avoid extraction of parameters from the matrix, it's a simple read now. – legends2k Apr 3 '15 at 2:31
• Related answer on matrix parameter extraction in SO. For those curious on the math of extraction: a unit length vector along X (1, 0, 0) is transformed by the matrix; the distance between the origin and new point gives scaling along X. – legends2k Apr 3 '15 at 2:41