I have been (trying) to work with Bullet to do collision detection only.
I inherited some code which supposedly worked at some point. I have only slightly modified it to use different collision shapes.
Unfortunately, when I add a collision shape to a collision object, and then attempt to access information about the shape using collisionObject->getCollisionShape() (for example, to do collision detection or even just see what shape type it is), I receive a null pointer.
This is less than ideal and suggests a deeper problem. I therefore did some digging, and found that the revision counter for the collision shape is not incrementing - suggesting that there is an issue when setting the collisionShape in the collisionObject. Further digging reveals that when creating, say, a box shape, the correct shape type is made and I can see that the shape related information is fine, but that the Aabb and overbounding sphere information is completely random.
For example, if I make a Broadphase using AxisSweep with worldAabbMin (-10, -10, -10) and worldAabbMax (10,10,10) and a box shape of half extents 0.25, the overbounding sphere has a radius of almost 0 and Aabb showing something like (0, -1e-365, -10) and (0,5e-320, 10). If I query the broadphase what it thinks the Aabb should be, it returns an expect min and max.
There must therefore be some deeper issue. I hope that I'm just making a silly mistake with some setting.
I have tried a variety of shape combinations. Before I pass the shape to setCollisionShape, I can still access the name, type and if the shape is convex. But, as I said, the bounds and the margin appear to be nonsense. Once I set the shape, I cannot access any shape info through the collisionObject->getCollisionShape() - when I do try I get 0. I can add the collisionObject to the collisionWorld, but again, it is as if I just passed it a null pointer. After the shape is created and added to the world, I can successfully update the position and orientation of the shape, but the Aabb, etc info remains random, I get random broadphase activations, and 0 or large negative number collision points in narrow phase. I have scoured the forums for anyone facing the same issues.
Some other issues my colleagues and I have faced which may help deduce the problem:
- Capsule shapes do not work. Linking always fails.
- A floating point exception can occur when creating the Broadphase.
- When attempting to compile in Release mode, there is a segmentation fault when adding the collisionShape to the collisionWorld.
I provide a reduced code of what I am doing below. My header file declares the variables and includes bullet/btBulletCollisionCommon.h. My source file looks something like this:
//------------------------------------------------------------------------------
// constructor
bt_collision_detector::bt_collision_detector(const double& leftbound, const double& rightbound, const std::string& collision_type) :
safety_margin(0.04),
collision_poly_type(0),
chaserbusDims(0.,0.,0.),
targetbusDims(0.,0.,0.),
temp_static_rotation(0.,0.,0., 0.,0.,0., 0.,0.,0.)
{
// Create Bullet World and Collision Objects
// Use default collision configuration and dispatcher...
btDefaultCollisionConfiguration* collisionConfiguration = new btDefaultCollisionConfiguration();
collisionConfiguration->setConvexConvexMultipointIterations(3,3);
collisionConfiguration->setPlaneConvexMultipointIterations(3,3);
btCollisionDispatcher *dispatcher = new btCollisionDispatcher(collisionConfiguration);
// Init broadphase
btVector3 worldAabbMin(leftbound,leftbound,leftbound);
btVector3 worldAabbMax(rightbound,rightbound,rightbound);
btBroadphaseInterface *broadphase = new btAxisSweep3(worldAabbMin,worldAabbMax);//,10,0,false);
// Create world and load all instantiated objects into it...
collisionWorld = new btCollisionWorld(dispatcher, broadphase, collisionConfiguration);
// Instantiate Object Dimesions
chaserbusDims = btVector3(0.5,0.5,0.5);//(0.3175,0.3175,0.3175);
targetbusDims = btVector3(0.5,0.5,0.5);//(0.3175,0.3175,0.3175);
// Instantiate Object Dimesions
set_polytopes();
}
//------------------------------------------------------------------------------
void bt_collision_detector::set_polytopes()
{
//Setting polytopes
chaserbusShape = new btBoxShape(0.5*chaserbusDims);//new btSphereShape(0.25);//
targetbusShape = new btSphereShape(0.25);
//Setting collision groups
//group, mask mask must match group of other obj
// servicer
objectChaserBus = new btCollisionObject;
objectChaserBus->setCollisionShape(chaserbusShape);
std::cout<<"OBJ BUS "<<objectChaserBus->getCollisionShape()<<std::endl; // Prints 0 to screen!!
collisionWorld->addCollisionObject(objectChaserBus, COL_OBST, COL_TARG); //COL_OBST and COL_TARG are bit set in header
std::cout<<"WORLD "<<collisionWorld->getNumCollisionObjects()<<std::endl; // Says there are 0 objects
// bus
objectTargetBus= new btCollisionObject;
objectTargetBus->setCollisionShape(targetbusShape);
std::cout<<"TAR BUS "<<objectTargetBus->getCollisionShape()<<std::endl; // See above
collisionWorld->addCollisionObject(objectTargetBus, COL_TARG, COL_OBST);
std::cout<<"WORLD "<<collisionWorld->getNumCollisionObjects()<<std::endl;
}
//------------------------------------------------------------------------------
// destructor
bt_collision_detector::~bt_collision_detector()
{
// remove collision objects and free memory
delete targetbusShape;
delete chaserbusShape;
delete collisionWorld;
delete dispatcher;
delete collisionConfiguration;
delete broadphase;
}
//------------------------------------------------------------------------------
//! update object world transform
void bt_collision_detector::get_pose(const Matrix44& trafo, btCollisionObject* obj_in)
{
temp_static_rotation.setValue(trafo(0,0), trafo(0,1), trafo(0,2),
trafo(1,0), trafo(1,1), trafo(1,2),
trafo(2,0), trafo(2,1), trafo(2,2));
obj_in->setWorldTransform(btTransform(temp_static_rotation,
btVector3(trafo(0,3),trafo(1,3),trafo(2,3))));
//std::cout<<""<<std::flush;
}
//------------------------------------------------------------------------------
double bt_collision_detector::check_collision_constraint( Matrix44& tChaser_Bus, const Matrix44& tTarget_Bus, const Matrix44& tTarget_Pan1, const Matrix44 tTarget_Pan2, const Matrix44 tTarget_Ant)
{
//std::cout<<"-- -- -- Checking collision constraint"<<std::endl;
//std::cout<<"-- -- -- -- updating chaser pose"<<std::endl;
get_pose(tChaser_Bus, objectChaserBus);
get_pose(tTarget_Bus, objectTargetBus);
// DISCRETE COLLISION DETECTION
btScalar penetration = 0.;
btScalar lastpenetration = 0.;
collision_data::stdvScalar depths;
collisionWorld->getDispatcher();
//std::cout<<"-- -- -- -- collision detection "<<std::endl;
collisionWorld->performDiscreteCollisionDetection();
collisionWorld->computeOverlappingPairs();
//broadphase->calculateOverlappingPairs();
int numManifolds=collisionWorld->getDispatcher()->getNumManifolds();
std::cout<<"-- -- -- -- Number of manifolds "<<numManifolds<<std::endl;
// number of persistent manifolds (collisions between collision pairs)
for (int i=0; i<collisionWorld->getDispatcher()->getNumManifolds(); i++) {
// Find collision pairs
btPersistentManifold* contactManifold = collisionWorld->getDispatcher()->getManifoldByIndexInternal(i);
const btCollisionObject* obA = contactManifold->getBody0();
const btCollisionObject* obB = contactManifold->getBody1();
//std::cout<<"body A "<<obA->getWorldTransform().getOrigin().getX()<<std::endl;//<<" body B "<<obB->getUserIndex()<<std::endl;
//btScalar obax = obA->getWorldTransform().getOrigin().getX();
int numContacts=contactManifold->getNumContacts();
std::cout<<"-- -- -- -- -- Number of contacts "<<numContacts<<std::endl;
if (numContacts>10000) numContacts = 10000;
for (int j=0; j<numContacts; j++) {
//std::cout<<"-- -- -- -- -- looping!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!11"<<std::endl;
// detailed info about one contact point within a collision pair
//std::cout << "contact manifold " << j << " of " << contactManifold->getNumContacts() << std::endl;
// std::cerr << "lastpenetration = " << lastpenetration << std::endl;
// std::cerr << "tS:\n";
// std::cerr << tS << std::endl;
lastpenetration = contactManifold->getContactPoint(j).getDistance();
if (j==0) { penetration = lastpenetration; }
/*
if (penetration<(-1.*safety_margin)) {
if (lastpenetration > penetration) {
penetration = lastpenetration;
}
}*/
}
depths.push_back(-1.*penetration);
}
// return max pen depth for all collision pairs
int mindex = 0;
for (uint k=1; k<depths.size(); ++k) {
if (depths[k]>depths[mindex]) {
mindex = k;
}
}
if (depths.size() < 1) {
return (0.);
}
else {
return (depths[mindex]);
}
}