Search code examples
c#collision-detectionbulletphysicsbullet

Bullet physics collision detection


I'm using bulletsharp (C# wrapper of bullet physics) to do some collision detection. Everything went fine until i tried to change the collision shape of an existing rigid body from box to compound at runtime. I'm doing this to simulate the collision again with a higher accuracy. The problem is: collision of compound shapes is not detected.

Scenario:

  • DicreteDynamicsWorld containing some RigidBody with BoxShape
  • Collision of two kinematic RigidBody with BoxShape happens (and is detected)
  • Change the shapes of these two RigidBody to CompoundShape using the HACD algorithm for convex decomposition
  • Remove RigidBody from DicreteDynamicsWorld
  • RigidBody.CollisionShape = CompoundShape
  • Set Position using RigidBody.MotionState.WorldTransform
  • Add RigidBody to DicreteDynamicsWorld
  • Undo the movement which caused the collision (one object doesn't contain the other)
  • Repeat the movement
  • Collision is not detected

Remarks:

  • Changing the CollisionShape from BoxShape to CompoundShape was successful (correct CollisionShape and correct position)
  • For collision detection i'm using DicreteDynamicsWorld.Dispatcher.NumManifolds > 0 after a DicreteDynamicsWorld.StepSimulation(...)

Some code snippets as requested:

If you need something particular, please tell me. My solution is too big and too complexe to post the complete code...

RigidBody creation:

// Create rigid body
MotionState motionState = new DefaultMotionState(startTransform);
RigidBodyConstructionInfo rbInfo = new RigidBodyConstructionInfo(0.0f, motionState, collisionShape);
RigidBody rigidBody = new RigidBody(rbInfo);
rbInfo.Dispose();

// Kinematic body: mass=0 -> static/kinematic -> use flag
bool isKinematicBody = (compModel.Children[i].Type ==...) || ... ;
rigidBody.CollisionFlags = isKinematicBody ? CollisionFlags.KinematicObject : CollisionFlags.StaticObject;
rigidBody.ActivationState = ActivationState.DisableDeactivation;

Basic steps:

// Get old collision data
if (compModel.Children[i].Container.TryGetValue(ContainerType.Collision, out container))
    collisionData = ((ContainerCollision) container).CollisionData;

// Get geometry
if (compModel.Children[i].Container.TryGetValue(ContainerType.Geometry, out container))
{
    verticesGeo = ((ContainerGeometry) container).GeometryData.Vertices;
    trianglesGeo = ((ContainerGeometry) container).GeometryData.Triangles;
}

// Remove rigid body from world
_world.RemoveRigidBody(collisionData.RigidBody);

// Create new shape
List<Vector3> vertices = Utility.ToBulletVector3List(verticesGeo);
List<int> indices = Utility.ListIntArrayToListInt(trianglesGeo);
CompoundShape collisionShape = ConvexDecomposition(compModel.Children[i].Id, vertices, indices);

// Set collision shape
collisionData.RigidBody.CollisionShape = collisionShape;

// Set position
collisionData.RigidBody.MotionState.WorldTransform *= collisionData.PositionDifference;

// Add rigid body to world
_world.AddRigidBody(collisionData.RigidBody, collisionData.CollisionGroup, collisionData.CollisionMask);

CollisionContainer:

public interface IContainer
{
    ContainerType Type { get; }
}

public struct ContainerCollision : IContainer
{
    public ContainerType Type
    {
        get { return ContainerType.Collision; }
    }

    public CollisionData CollisionData;
}

Structure CollisionData:

public struct CollisionData
{
    public BulletSharp.RigidBody RigidBody;
    public BulletSharp.Matrix PositionDifference;
    public BulletSharp.Vector3 ZeroPosition;
    public short CollisionGroup;
    public short CollisionMask;
}

Any ideas, what i'm doing wrong?

Thanks.


Solution

  • Assuming that all your change in shape is happening here

    CompoundShape collisionShape = ConvexDecomposition(compModel.Children[i].Id, vertices, indices);
    
    // Set collision shape
    collisionData.RigidBody.CollisionShape = collisionShape;
    
    // Set position
    collisionData.RigidBody.MotionState.WorldTransform *= collisionData.PositionDifference;
    
        // Add rigid body to world
    _world.AddRigidBody(collisionData.RigidBody, collisionData.CollisionGroup, collisionData.CollisionMask);
    

    Probably you will have to recalculate the entire RigidBody from start, I have no clue how you do that in the first place so I will show you an example how I do it.

    public virtual RigidBody LocalCreateRigidBody(float mass, Matrix startTransform, CollisionShape shape)
            {
    
                //rigidbody is dynamic if and only if mass is non zero, otherwise static
                bool isDynamic = (mass != 0.0f);
    
                Vector3 localInertia = Vector3.Zero;
                if (isDynamic)
                    shape.CalculateLocalInertia(mass, out localInertia);
    
                //using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects
                DefaultMotionState myMotionState = new DefaultMotionState(startTransform);
    
                RigidBodyConstructionInfo rbInfo = new RigidBodyConstructionInfo(mass, myMotionState, shape, localInertia);
                RigidBody body = new RigidBody(rbInfo);
                rbInfo.Dispose();
    
    
                return body;
            }
    

    With that being said, take a note at your "collisionData" (Which I guess its a class?) and the naming of RigidBody (it might have a conflict with the BulletSharp class?)

    Best reguards with your progress and feel free to contact me if you have any questions!