In our last game we experienced a *lot* of problems with the detection of collision, mainly because we didn't understand how to set it up properly.
Apart from the CollisionInterfaceDemo, with hardly any comments, there isn't any documentation at all on how to handle collision detection properly. During our last project we've spent days if not weeks, figuring out how to 'work around' several strange bumps in the road. And we want to prevent that from happening again
In our new project I want to setup a collision detection routine in the internalTick callback again, but also want to make sure I set it up correctly. Hopefully this code and thread will serve as a guide/manual to everyone who experiences problems with setting up a proper collision detection routine using the internal tick callback.
First things first: my physics world settings:
Code: Select all
<physics substeps="4" fixed_timestep="120"
gravity="-10.0" friction="0.5"
linear_sleeping="1.0" angular_sleeping="0.1"
deactivation_time="1.5"
/>
Code: Select all
<physics_cube>
<position x="2.0" y="-7.5" z="2.0" />
<scale x="1.0" y="4.0" z="1" />
<rotation x="0" y="0.0" z="0.0" w="1" />
</physics_cube>
<physics
friction="0.2"
restitution="0.0"
density="2.4"
linear_damping="0.5"
angular_damping="0.5"
/>
This is the code I have in the internal tick callback:
First get the dispatcher:
Code: Select all
btDispatcher* dispatcher =
const_cast<btDynamicsWorld*>(p_world)->getDispatcher();
TT_NULL_ASSERT(dispatcher);
Next we 'iterate' over all the manifolds, effectively iterating over all spaces in which there is contact.
Code: Select all
int numManifolds = dispatcher->getNumManifolds();
// Print some debug stuff
if (numManifolds > 0)
{
TT_Printf("Internal Tick: manifolds: %d\n", numManifolds);
}
for (int i = 0; i < numManifolds; ++i)
{
btPersistentManifold* contactManifold =
dispatcher->getManifoldByIndexInternal(i);
TT_NULL_ASSERT(contactManifold);
// Print some debug stuff
for (int j = 0; j < contactManifold->getNumContacts(); ++j)
{
btManifoldPoint& cp = contactManifold->getContactPoint(j);
TT_Printf(" %d > dist %f impulse %f\n", i, cp.getDistance(), cp.m_appliedImpulse);
}
btCollisionObject* body0 =
static_cast<btCollisionObject*>(contactManifold->getBody0());
btCollisionObject* body1 =
static_cast<btCollisionObject*>(contactManifold->getBody1());
TT_NULL_ASSERT(body0);
TT_NULL_ASSERT(body1);
// do stuff
contactManifold->clearManifold(); // what's this?
}
Code: Select all
Internal Tick: manifolds: 1
0 > dist -0.034546 impulse 18.978798
0 > dist -0.034546 impulse 0.000000
0 > dist -0.034546 impulse 20.950485
0 > dist -0.034546 impulse 0.138508
Collision! # points 4
So far so good. Although I find it a bit strange that only two contact points generate impulses and not all four, after all it's a cube with a flat surface... but okay
Let's take a look at the next internal callback result:
Code: Select all
Internal Tick: manifolds 1
0 > dist -0.025155 impulse 0.680674
0 > dist -0.025002 impulse 0.155525
0 > dist -0.024833 impulse 0.000000
0 > dist -0.024985 impulse 0.000000
Collision! # points 4
Of course I can check the impulses to see whether it's a real collision or not, but it feels a bit like hackery to me. After all, what would be a good threshold for an impulse? If an object is really stuck in the surface, its 'unstuck' impulse can be quite high, still generating a bogus collision detection. If I set the impulse threshold too high, I will definitively get 'false negatives'. So my guess is that that isn't the way to go.
And what's that
Code: Select all
contactManifold->clearManifold();
I also tried the following collision detection 'hack' reported somewhere on this forum:
Code: Select all
// check if collision is present
bool hasCollision = false;
for (int j = 0; j < contactManifold->getNumContacts(); ++j)
{
btManifoldPoint& cp = contactManifold->getContactPoint(j);
if (cp.getDistance() < 0.0f)
{
hasCollision = true;
break;
}
}
if (hasCollision == false)
{
contactManifold->clearManifold();
continue;
}
else
{
TT_Printf("Collision! # points %d\n", contactManifold->getNumContacts());
}
I also tried fiddling with another apparently undocumented method: refreshContactPoints(), but that didn't do much. Should we users even use that function? If so, when?
So my question is: how should I properly setup an internaltick callback to detect collisions. What are the exact steps and why? And how can I reduce the amount of reported bogus results to an absolute minimum?
Enough questions for now. Thanks a lot for your help!
Cheers,
Martijn