i use a heightfield pass it to the world as a static rigidbody and use a ghost object as the collider, simulating a bullet (or some projectile)
this works for like 70-80% of the cases, the impact of the bullet gets calculated correctly, but like every 5th od 6th collision test completely fails, and the bullet penetrates the heightfield w/o registering a collision. this behaviour seems to correlate with the geometry of the height field, because 'shooting' the same spot several times seems more prone to trigger a collision failure., also it seems to have to do with penetration angle.
any ideas what i could tweak to eliminate this behaviour?
this is how i setup the world:
Code: Select all
m_broadphase = new btDbvtBroadphase();
m_collisionConfiguration = new btDefaultCollisionConfiguration();
m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration);
m_solver = new btSequentialImpulseConstraintSolver;
m_broadphase->getOverlappingPairCache()->setInternalGhostPairCallback(new btGhostPairCallback);
m_dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher,m_broadphase,m_solver,m_collisionConfiguration);
m_dynamicsWorld->setGravity(btVector3(0,-9.8f,0));
Code: Select all
m_terrCollShape = new btHeightfieldTerrainShape(xSize,zSize, m_pGridData, 60.0f, min, max, 1, PHY_FLOAT, false);
btVector3 scaling;
scaling.setX(PLANESCALE);
scaling.setY(1.0f);
scaling.setZ(PLANESCALE);
m_terrCollShape->setLocalScaling(scaling);
float cX=(xSize*PLANESCALE)/2.0f+m_tData.globalOffsetX;
float cZ=(zSize*PLANESCALE)/2.0f+m_tData.globalOffsetZ;
m_terrMS = new btDefaultMotionState(btTransform(btQuaternion(0,0,0,1),btVector3(cX,(min+max)/2.0f,cZ)));
btRigidBody::btRigidBodyConstructionInfo groundRigidBodyCI(0,m_terrMS,m_terrCollShape,btVector3(0,0,0));
m_terrRB = new btRigidBody(groundRigidBodyCI);
m_terrRB->setUserPointer(this);
Code: Select all
m_objGO = new btPairCachingGhostObject();
m_objGO->setWorldTransform(t);
m_objGO->setCollisionShape(m_mesh->GetCollShape());
m_objGO->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT);
m_objGO->setUserPointer(this);
Code: Select all
m_dynamicsWorld->addCollisionObject(pObj->m_objGO, btBroadphaseProxy::CharacterFilter, btBroadphaseProxy::StaticFilter|btBroadphaseProxy::DefaultFilter);
EDIT: this might be useful too, the collision procedure (mostly a copypasty from collisioninterfacedemo). it lacks precision, but that not neccesary for my app
Code: Select all
btManifoldArray manifoldArray;
btBroadphasePairArray& pairArray = m_objGO->getOverlappingPairCache()->getOverlappingPairArray();
worldHitPoint->setValue(0,0,0);
int numPairs = pairArray.size();
for (int i=0;i<numPairs;i++)
{
manifoldArray.clear();
const btBroadphasePair& pair = pairArray[i];
//unless we manually perform collision detection on this pair, the contacts are in the dynamics world paircache:
btBroadphasePair* collisionPair = dynamicsWorld->getPairCache()->findPair(pair.m_pProxy0,pair.m_pProxy1);
if (!collisionPair)
continue;
if (collisionPair->m_algorithm)
collisionPair->m_algorithm->getAllContactManifolds(manifoldArray);
for (int j=0;j<manifoldArray.size();j++)
{
btPersistentManifold* manifold = manifoldArray[j];
btScalar directionSign = manifold->getBody0() == m_objGO ? btScalar(-1.0) : btScalar(1.0);
for (int p=0;p<manifold->getNumContacts();p++)
{
const btManifoldPoint&pt = manifold->getContactPoint(p);
if (pt.getDistance()<0.f)
{
const btVector3& ptA = pt.getPositionWorldOnA();
const btVector3& ptB = pt.getPositionWorldOnB();
const btVector3& normalOnB = pt.m_normalWorldOnB;
(*worldHitPoint) = ptB;
m_type = OBJ_TYPE_DELETED;
dynamicsWorld->removeCollisionObject(m_objGO);
return true;
}
}
}
}
return false;
}
tasche