There are a number of ways of detecting collisions between 3D models. It is often a trade off between speed and results that determines which method to use. Bounding shape collisions are the fastest methods and involve creating a bounding shape (sphere or box) around the 3D model and carrying out collisions between those rather than the model vertex data itself. Bounding shape collisions can work well in many cases however if you require more accurate collisions you need to actually check for collisions between model vertices. Even when handling collisions at the lowest level you would do a bounding shape collision test first to avoid having to do the expensive vertex collision code unnecessarily (we trivially reject the tests).
A Bounding Sphere is a sphere that encompasses the whole of the model's geometry. It is defined via a centre position and a radius. XNA provides a type for you to use called BoundingSphere.
XNA provides this for you per mesh of your model (in model space) so there is no need to calculate it. Remember that models in XNA are made up of 1 or more mesh. When doing collisions you will want to have one sphere that encompasses the whole model which means at model load time you will want to loop through all the mesh in your model and expand a main model sphere accordingly:
foreach (ModelMesh mesh in m_model.Meshes)
This gives us a sphere that encompasses the whole model in model space. Collisions however occur in world space so before testing for collision between two models we need to convert their spheres into world space. When we render our models we calculate a world matrix specifying the models' transformation into world space from model space - we can apply the same matrix to the bounding sphere:
To see if two spheres have collided we can use:
Note that the Intersects function has a number of overloads allowing you to test for intersection between the sphere and other shapes like a bounding box, the view frustum, a plane or a ray. There is also another function called Contains that determines the exact nature of the intersection e.g. is it completely contained by, intersects or disjointed.
Depending on the shape of your geometry a bounding box is likely to be a better fit than a sphere. Unfortunately XNA does not provide a bounding box for the mesh like it does for a sphere. You could wrap the sphere in a box (using the BoundingBox CreateFromSphere function) but this would be is a very poorly fitting box and would give no advantages over just using the sphere. Instead you can generate the bounding box itself. Notes on how to do that can be found here: XNA Bounding Box.
Once you have an Axis Aligned Bounding Box (AABB) calculated for the model it will need transforming into world space each time you want to test for collisions. As with the sphere you can just apply the world matrix to the box corners to get the box in world space. This though means your box is no longer aligned along the axis and can no longer be represented with simple min and max values. This is because the model may have been rotated as well as translated and scaled. This bounding box is now known as an Oriented Bounding Box (OBB) and requires 8 vectors to represent it (one for each corner of the box). To transform the AABB in model space into an OBB in world space:
// firstly extract the corners of the AABB into 8 vectors - 1 for each corner
Vector3 obb=new Vector3;
// Transform the vectors by the model's world matrix
Vector3.Transform(obb, ref modelWorldMatrix, obb);
Here I have taken advantage of an overloaded Transform function that takes an array of vectors and transforms them all in one go rather than doing one at a time
To perform collision tests between two oriented bounding boxes is quite complex. I may put notes up here about it at later date but meantime take a look at this solution from ZiggyWare. We can however convert our new OBB into an AABB in world space and use that for collisions. The fit is not very good but it may be OK depending on your game. To convert our OBB into an AABB we can use the BoundingBox CreateFromPoints method like so:
// create an AABB in world space form the OBB in world space
BoundingBox worldAABB = BoundingBox.CreateFromPoints(obb);
We can now test for collisions between two AABBs in world space like so:
bool. hasCollided = worldAABB(otherWorldAABB);
Note that the bounding box Intersects function also has a number of overloads allowing you to test for intersection between the bounding box and other shapes like a sphere, the view frustum, a plane or a ray. There is also another function called Contains that determines the exact nature of the intersection e.g. is it completely contained by, intersects or disjointed.
If your model has animation then the bounding shapes will change orientation with the animation. In this case you need to transform the mesh bounding shapes by the bone matrix each time and then recreate the whole model bounding shape anew. For example:
Matrix m_transforms = new Matrix[m_model.Bones.Count];
foreach (ModelMesh mesh in m_model.Meshes)
As mentioned earlier even if you go to a lower level with collision detection you will want to test against bounding shapes first before having to do the expensive low level calculations e.g. per triangle. You may find a sphere or a box is good enough for your needs. You may also find a combination works best.
In terms of speed the bounding sphere collision will be the fastest followed by an axis aligned bounding box test. An oriented bounding box test will be a bit slower. I would tend to use a bounding sphere test first and if that shows a collision then do an AABB test. For more accuracy you could then go through each of the models' mesh bounding shapes.