Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I have a problem with detecting collision between 2 models using BoundingSpheres in XNA 4.0. The code I'm using i very simple:

private bool IsCollision(Model model1, Matrix world1, Model model2, Matrix world2)
{
for (int meshIndex1 = 0; meshIndex1 < model1.Meshes.Count; meshIndex1++)
{
    BoundingSphere sphere1 = model1.Meshes[meshIndex1].BoundingSphere;
    sphere1 = sphere1.Transform(world1);

    for (int meshIndex2 = 0; meshIndex2 < model2.Meshes.Count; meshIndex2++)
    {
        BoundingSphere sphere2 = model2.Meshes[meshIndex2].BoundingSphere;
        sphere2 = sphere2.Transform(world2);

        if (sphere1.Intersects(sphere2))
            return true;
    }
}
return false;

}

The problem I'm getting is that when I call this method from the Update method, the program behaves as if this method always returns true value (which of course is not correct). The code for calling is very simple (although this is only the test code):

 if (IsCollision(model1, worldModel1, model2, worldModel2))
                {
                    Window.Title = "Intersects";
                }

What is causing this?

The way Im drawing the scene is to load the number of elements and their coordinates from a file like this (it is called from Update method):

OpenFileDialog Otvaranje = new OpenFileDialog();
        if (ks.IsKeyDown(Microsoft.Xna.Framework.Input.Keys.L))
            {
                this.GraphicsDevice.Clear(Color.CornflowerBlue);
                Otvaranje.ShowDialog();
                try
                {
                    using (StreamReader sr = new StreamReader(Otvaranje.FileName))
                    {
                        String linija;
                        while ((linija = sr.ReadLine()) != null)
                        {
                            red = linija.Split(',');                               
                            model = red[0];
                            x = red[1];
                            y = red[2];
                            z = red[3];
                            elementi.Add(Convert.ToInt32(model));
                            podatci.Add(new Vector3(Convert.ToSingle(x), Convert.ToSingle(y), Convert.ToSinglez)));                                                              
                            sfere.Add(new BoundingSphere(new Vector3(Convert.ToSingle(x), Convert.ToSingle(y), Convert.ToSingle(z)), 1f));                                                              

                        }
                    }

And then in the Update() method I had the following code (this was my first attempt):

if(sfere.Count != 0){
for(int i = 1; i<sfere.Count; i++)
{
 if(sfere[0].Intersects(sfere[i])) Window.Title = "Intersects"; 
}
}

This code never returned that collision is true because the bounding boxes are moving when the box moves, and I don't know why. The code that moves the box is this:

if (Microsoft.Xna.Framework.Input.ButtonState.Pressed == Mouse.GetState().LeftButton)
                {
                    worldKutija = Matrix.CreateTranslation(new Vector3(0.01f, 0f, 0f)) * worldKutija;
                }

So if the model is set to be the box it is drawn into the worldKutija, and all other models are drawn into world matrix so they would not move with the box model. So why are their BoundingSpheres moving? After this started happening I tried the code I posted in the original question, and got the problems I was talking about

share|improve this question
    
Do you reset the Window.Title to "Doesn't intersect" in every update, if there's no collision? –  Marton Jul 9 '12 at 8:52
    
Yes I do (nothing happens), but the real problem is that the program detects collision when there is non. I have a scene with multiple objects, only one of them is moving, others are static. I want to check if the moving object is intersecting with any of those static objects –  NDraskovic Jul 9 '12 at 8:54
    
You could actually output some useful information to a log file perhaps. Like the current bounding spheres. This way, you can validate your method. However, I would simply put a breakpoint inside the if (IsCollision(...)) block. –  Marton Jul 9 '12 at 8:58
    
That didn't help because of the specific way I draw the objects on the scene. Their coordinates are not hard coded, I load them from a file (when the "L" key is pressed). And the moment I load the coordinates, the IsCollision returns the true value. –  NDraskovic Jul 9 '12 at 9:06
    
Why don't you use debugging, to see why are you getting an intersection? Just add a watch to your list of models and bounding spheres, and check out the coordinates. It would be much more productive then just saying "it doesn't work". –  Marton Jul 9 '12 at 13:02
show 5 more comments

2 Answers 2

up vote 3 down vote accepted

You are forgetting to take the the bone transforms into account. Also It's not clear what is inside the World1 and World2 matrices, are you sure you move the boundingsphere's around and not just have them all be centered at (0,0)? Could you print out their origin's?

Anyway some code:

//Creates one bounding sphere for a model
BoundingSphere CreateBoundingSphereForModel(Model model, Matrix worldMatrix)
{
    Matrix[] boneTransforms = new Matrix[this.model.Bones.Count];
    this.model.CopyAbsoluteBoneTransformsTo(boneTransforms);

    BoundingSphere boundingSphere = new BoundingSphere();
    BoundingSphere meshSphere;         

    for (int i = 0; i < model.Meshes.Count; i++)
    {                
        meshSphere = model.Meshes[i].BoundingSphere.Transform(boneTransforms[i]);                
        boundingSphere = BoundingSphere.CreateMerged(boundingSphere, meshSphere);
    }
    return boundingSphere.Transform(worldMatrix);       
}

//Check intersection between two models
bool IsCollision(Model model1, Matrix world1, Model model2, Matrix world2)
{
    BoundingSphere bs1 = CreateBoundingSphereForModel(model1, world1);
    BoundingSphere bs2 = CreateBoundingSphereForModel(model2, world2);

    if(bs1.Intersects(bs2))
        return true;

    return false;
}

Note that it would be better to create a new class that holds the model, the matrix and caches the bounding spheres to improve performance.

Edit: it seems from the comments above that the problem is that the matrices are wrong, just putting both sphere's at (0,0,0). So instead to solve that use below code to create a proper world matrix:

Matrix world = Matrix.CreateTranslation(object1Position) * Matrix.CreateScale(object1Scale); 
// We don't need rotation since it doesn't matter how the sphere is rotatated ;)

Here object1Position is a Vector3 that you probably also use the draw the model at a certain position in the world.

share|improve this answer
    
Upvoted. This answer contains the solution, so I won't update mine. –  Marton Jul 9 '12 at 10:43
add comment

I think your BoundingSpheres might not be in the proper positions.

private bool IsCollision(Model model1, Matrix world1, Model model2, Matrix world2) 
{ 
for (int meshIndex1 = 0; meshIndex1 < model1.Meshes.Count; meshIndex1++) 
{ 
BoundingSphere sphere1 = model1.Meshes[meshIndex1].BoundingSphere; 
sphere1 = sphere1.Transform(world1);
//EDIT:
sphere1.Center += obj1.Position;
//

for (int meshIndex2 = 0; meshIndex2 < model2.Meshes.Count; meshIndex2++) 
{ 
    BoundingSphere sphere2 = model2.Meshes[meshIndex2].BoundingSphere; 
    sphere2 = sphere2.Transform(world2); 
    //EDIT:
    sphere2.Center += obj2.Position;
    //

    if (sphere1.Intersects(sphere2)) 
        return true; 
} 
} 
return false; 

Implying that obj1 and obj2 are the world objects, and their corresponding models are model1 and model2. I have no idea what you have in those world1 and world2 matrices though... maybe you could show us some more code.

share|improve this answer
    
The world1 contains only one model (simple box), and world2 contains "workstations". Both world1 and world 2 are the same: private Matrix world1 = Matrix.CreateTranslation(new Vector3(0, 0, 0)); private Matrix world2 = Matrix.CreateTranslation(new Vector3(0, 0, 0)); This is a college project I'm doing and the goal is to load the configuration of an assembly line and then check if the box passes in front of a certain workstation. I solved the loading part, and for this second one I added the "laser" model, and if the box intersects with the laser, it should stop. –  NDraskovic Jul 9 '12 at 9:20
    
Yeah, then your BoundingSpheres are definitely in the wrong place. Set their Center properties to the objects' position. –  Marton Jul 9 '12 at 9:21
    
What do you mean by world object? Sorry, I'm a beginner, so please be patient with me. –  NDraskovic Jul 9 '12 at 9:34
    
I mean the objects that are represented by the models. Like a car, a ball or something like that. If the models don't belong to such an object, just use the center of the model as the center of the BoundingSphere. –  Marton Jul 9 '12 at 9:36
1  
Your matrices need to be: Matrix world1 = Matrix.CreateTranslation(model1Position)*Matrix.CreateScale(scale1); else both boundingspheres are at (0,0,0) instead of at the place of where the models are drawn and so always intersect. The solution to just change the center is ok too but you can do it with the matrices in one go (else it's useless to pass the matrices) –  Roy T. Jul 9 '12 at 10:04
show 3 more comments

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.