5
\$\begingroup\$

I have been trying to get 3D collision detection working for a while and I think (hope) you people can help me.

For my project I have created a 'sprite3d' kinda class which is called ModelEntity and there there is a function that is called intersects.

intersects gets another ModelEntity as a parameter.

 public bool intersects(ModelEntity entity)
    {
        BoundingSphere bs1 = CreateBoundingSphereForModel();
        BoundingSphere bs2 = entity.CreateBoundingSphereForModel();

        bs1.Center += position;
        bs2.Center +=entity.position;

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

        return false;
    }

public BoundingSphere CreateBoundingSphereForModel()
    {
        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(getWorld());
    }

public Matrix getWorld()
    {
        return  Matrix.CreateTranslation(position) * Matrix.CreateRotationY(rotation.Y) * Matrix.CreateRotationZ(rotation.Z) * Matrix.CreateRotationX(rotation.X) ;
    }

Those are the main parts of the collision in the ModelEntity class and the place where I check collision is in the PlayState class

if (model.intersects(player) || player.intersects(model1))
        {
            cam.returnToLastPosition();
        }

cam.returnToLastPosition() is just returning the camera to the last place it has been so you can't pass through the model.

In the update loop, I set the player's position to the camera position (I have created a first person camera class which takes care of mouse and keyboard movement).

If you want to see the draw function:

public void draw(FirstPersonCamera cam)
        {
            Matrix[] transforms = new Matrix[model.Bones.Count];
            model.CopyAbsoluteBoneTransformsTo(transforms);
            foreach (ModelMesh mesh in model.Meshes)
            {
                foreach (BasicEffect effect in mesh.Effects)
                {
                    effect.EnableDefaultLighting();
                    effect.World =  transforms[mesh.ParentBone.Index] * getWorld();
                    effect.View = cam.getView();
                    effect.Projection = cam.projection;

                }
                mesh.Draw();
            }
        }

NOTE// in the intersects function I have tried to remove the part of

bs1.Center += position;
bs2.Center +=entity.position;

but it does not work anyways.

\$\endgroup\$
  • \$\begingroup\$ Elaborate on "it does not work anyways." What is it doing instead of "working?" \$\endgroup\$ – 3Dave Dec 15 '16 at 18:46
0
\$\begingroup\$

I know, it's a bit late but try

boundingSphere.Center += entityPosition;

before you return your sphere in CreateBoundingSphereForModel

\$\endgroup\$
0
\$\begingroup\$

Here's one problem:

bs1.Center += position;
bs2.Center +=entity.position;

But, you're also doing this in CreateBoundingSphereForModel():

return boundingSphere.Transform(getWorld());

So, you're transforming the sphere - which moves it into world coordinates. Then, you're offsetting it's position based on the entity's transform. Basically, you're moving the bounding sphere twice as far from the origin as the entity. Get rid of the first block (bs*.Center += entity.position) and see what happens.

public bool intersects(ModelEntity entity)
{
    BoundingSphere bs1 = CreateBoundingSphereForModel();
    BoundingSphere bs2 = entity.CreateBoundingSphereForModel();

    return bs1.Intersects(bs2))
}

One other note: Your getWorld() is doing things in the wrong order. Your approach moves the object to its world position, then rotates it around the origin. Your sphere would wind up orbiting the origin rather than spinning on its own axis.

In this framework, operations happen in SRT (scale, rotate, translate) order. (In OpenGL it would be the reverse.) So, you should have:

public Matrix getWorld()
{
    return  Matrix.CreateRotationY(rotation.Y) * Matrix.CreateRotationZ(rotation.Z) * Matrix.CreateRotationX(rotation.X) * Matrix.CreateTranslation(position);
}

Or, better yet, use CreateFromRollPitchYaw():

public Matrix getWorld()
{
    return Matrix.CreateFromRollPitchYaw(rotation.Z,rotation.X,rotation.Y) * Matrix.CreateTranslation(position);
}

... assuming that you don't want to mess with quaternions which eliminate gimbal lock.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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