A bit hard to see what you are doing ( will try an answer anyhow ), but if you are storing a sphere for testing collision or intersecting bounds , your bounding sphere should be initialized from the model bounding box, and store it. However keep it to object's local positioning ( usually Vector3.Zero ).
I think you may be over-complicating your collision by using translation matrices to setup world positions of bounding spheres when your ship location vectors are already in world space - when you can just use the vector3 values directly? ( also makes the code easier to read )...
I suggest not applying a world position to the bounding sphere until you do the actual hit testing, thus keeping a local space sphere for each mesh.
It sounds like ( in your comment response to Peter ) that you want to also scale it?
Assuming this , ensure you always scale the bounding-sphere independently of the positioning of the player/object's position.
1:
- Create Bounding Sphere from loaded model in local space ( of the mesh itself ) - usually Vector3.Zero ( because most models are usually centered on it's center point ), or relative to the center of the overall mesh in local space ( averaged position of all mesh vertices )
2:
- Scale the bounding sphere as needed . If all models of the same source are scaled to the same value, then you can keep one bounding sphere for all instances of the same model. If you scaled the mesh vertices in local space using matrix( scale* bonetransform ) directly, then generate the bounding sphere from the mesh itself only after scaling the mesh, but might be easier to creat the bounding box from the mesh first, then initialize a bounding sphere from that bounding box, as the bounding box will fit to the mesh itself.
3:
- Apply object/player position to the bounding sphere only when testing collision or intersections ( not when the mesh is loaded or generated ). Use a local space copy to create a world space equivalent of the same bounding sphere ( and they can be cached ).
For example:
//
// the bounding sphere passed to the method, and is relative to the mesh's local space ( usually vector3.Zero, or averaged to mesh center )
//
// ObjectPosition represent the position of the player or game object
//
//
// the iCamera object contains a view frustum to test intersection against if we are testing against the camera's view frustum. This does not apply when hit testing two bounding spheres though.
//
public static bool g_IsInViewOfCamera(Vector3 ObjectPosition, BoundingSphere Sphere, iCamera Camera)
{
//
// This is the World Space bounding sphere used to test collisions or intersections:
//
BoundingSphere S = new BoundingSphere(ObjectPositionInfo.Position + Sphere.Center, Sphere.Radius);
// logic here... such as hit testing or frustum checks
// If you are testing View Frustum only:
return Camera.ViewFrustum.Contains(S) == ContainmentType.Contains ? Camera.ViewFrustum.Contains(S) == ContainmentType.Intersects : false;
}
And if you want to test only collisions between two bounding spheres (if they are both from the same model):
/// <summary>
/// Tests colition between two player positions, if both objects use the same bounding sphere
/// </summary>
/// <param name="ObjectPosition1">World Space position of a player or object</param>
/// <param name="ObjectPosition2">World Space position of the other player or object</param>
/// <param name="BoundingSphere">Local Space bounding sphere realitive to zero, generated from the mesh.</param>
/// <returns>True if they collide or intersect</returns>
/// <remarks></remarks>
public bool g_IsCollision(Vector3 ObjectPosition1, Vector3 ObjectPosition2, BoundingSphere BoundingSphere)
{
//
// World Space bounding sphere of player1 / object1
//
BoundingSphere S1 = new BoundingSphere(ObjectPosition1 + BoundingSphere.Center, BoundingSphere.Radius);
//
// World Space bounding sphere of player2 / object2
//
BoundingSphere S2 = new BoundingSphere(ObjectPosition2 + BoundingSphere.Center, BoundingSphere.Radius);
if (S1.Contains(S2) == ContainmentType.Intersects)
return true;
if (S1.Contains(S2) == ContainmentType.Contains)
return true;
return false;
}
Or if you want to test using two local space spheres generated from two different meshes:
//
// Sphere 1 and 2 are local space bounding spheres
// object positions are in world space
//
public bool g_IsCollision(Vector3 ObjectPosition1, Vector3 ObjectPosition2, BoundingSphere Sphere1, BoundingSphere Sphere2)
{
//
// World Space bounding sphere of player1 / object1
//
BoundingSphere S1 = new BoundingSphere(ObjectPosition1 + Sphere1.Center, Sphere1.Radius);
//
// World Space bounding sphere of player2 / object2
//
BoundingSphere S2 = new BoundingSphere(ObjectPosition2 + Sphere2.Center, Sphere2.Radius);
if (S1.Contains(S2) == ContainmentType.Intersects)
return true;
if (S1.Contains(S2) == ContainmentType.Contains)
return true;
return false;
}
Just my input though. I don't see any need to create world matrices to test sphere intersections when the when the vector used to create the world translation matrix is already in world space. Seems like a bit of unnecessary processing to me...
...Probably just my own opinion though...
If you want scale, then you could simply add a scale argument to the collision test routines of my above examples
public bool g_IsCollision(Vector3 ObjectPosition1, Vector3 ObjectPosition2, BoundingSphere Sphere1, BoundingSphere Sphere2, float Scale)
and then ...
BoundingSphere S1 = new BoundingSphere(ObjectPosition1 + BoundingSphere.Center, BoundingSphere.Radius * Scale);
Note:
- above examples intend that the bounding spheres are ONLY in local space relative to mesh before being passed as arguments, and can have bone transformations applied ( as bone transformations are generally relative to local space? ) , world transformation should not be applied to bounding spheres before passing to the above examples.
Another note in your code, the following looks to me like you are scaling the entire world matrix, and not the scale of the mesh itself... ( so if scale changes, the positions of ALL objects using this algorithm would scale closer or farther away from World Center instead of Mesh Centers ) - is this intended?
Matrix ship1WorldMatrix = Matrix.CreateTranslation(ship1loc) * Matrix.CreateScale(0.1f);
Update
Example Usage of the above methods, without bone transforms:
vector3 ShipLocation1 = new vector3( /* whatever value here */);
vector3 ShipLocation2 = new vector3( /* whatever value here */);
/*
Lets assume both players have the same ship:
*/
Model ShipModel = Content.Load<Model>("Models\MyShipModel"); /* etc... */
/*
*/
BoundingSphere LocalSphere = ShipModel.Meshes[0].BoundingSphere;
/*
if you want to scale the sphere independently of model.
*/
// BoundingSphere.Radius = BoundingSphere.Radius * 0.1f;
/*
Will be true if colliding ( unscaled )
*/
bool IsColliding = g_IsCollision(ShipLocation1, ShipLocation2 , LocalSphere );
You can apply the bonetransform ( or should ) from the Mesh's ParentBone - but do not multiply a world matrix against it.
The only time you really need to apply world transformation matrices is when you draw the mesh itself.