[ODE] Collision detection slowdown?
Jean-Sebastien Guay
jean-sebastien.guay at polymtl.ca
Mon Apr 3 16:49:20 MST 2006
Hello list,
I have finally gotten things working in the small game I'm working on. As Jon
Watte suggested, I am using primitives for mobile objects (for now, spheres,
but I'll probably use capsules or boxes instead later) and trimeshes for
complex immobile objects. I ended up doing the vertex and index buffer
combination step to make a single trimesh out of composite objects. That seems
to work fine.
The problem I have now is that the collision detection seems to take an
inordinate amount of time.
The trimeshes I have in the scene right now are very simple - a few coarse
spheres, some boxes, some cylinders and a power-up. Here are some sample
polygon counts:
Power-up : 936 vertices and 312 triangles
Cylinder : 96 vertices and 32 triangles
Sphere : 144 vertices and 48 triangles
Box : 36 vertices and 12 triangles
The rest is modeled as sphere geoms.
The highest polygon count object in the scene is the terrain, which is based on
a heightmap. I have tried at two resolutions: 128x128 and 32x32. Here are the
numbers, as well as the performance I get:
No collision detection: over 40 fps
Collision detection enabled:
128x128 terrain (16641 vertices, 32768 triangles): about 7 fps
32x32 terrain (1089 vertices, 2048 triangles): about 11 fps
(the only thing I did between measurements is comment out the dSpaceCollide line
right before the dWorldQuickStep call to disable collision detection, and remove
the comment to re-enable it.
Is there some way I could speed this up? In case it makes a difference, here's
my NearCallback:
//----------------------------------------------------------------------------
// NEAR CALLBACK (just redirects the call to VCNPhysicsCore)
//----------------------------------------------------------------------------
void GlobalNearCallback(void *data, dGeomID o1, dGeomID o2)
{
((VCNPhysicsCore*)data)->NearCallback(o1, o2);
}
//--------------------------------------------------------------------------
void VCNPhysicsCore::NearCallback(dGeomID o1, dGeomID o2)
{
// If the collision involves a single object, ignore it.
if (o1 == o2) return;
VCNGameplayObject* go1 = GetGameplayObject(o1);
VCNGameplayObject* go2 = GetGameplayObject(o2);
if (go1 == go2) return;
// If the bodies are already connected by another joint other than a
// contact joint, don't check collisions.
dBodyID b1 = dGeomGetBody(o1);
dBodyID b2 = dGeomGetBody(o2);
if (b1 && b2 && dAreConnectedExcluding(b1,b2,dJointTypeContact)) return;
// Prepare contact data structure (specifies how objects bounce when they
hit
// TODO: This could be specified on a per-PhysicsObject basis and loaded
// with the object descriptions from the level data files
dContact contact[MAX_CONTACTS];
for (int i = 0; i < MAX_CONTACTS; i++)
{
contact[i].surface.mode = dContactBounce | dContactSoftCFM;
contact[i].surface.mu = dInfinity;
contact[i].surface.mu2 = 0;
contact[i].surface.bounce = 1e-5f;
contact[i].surface.bounce_vel = 1e-9f;
contact[i].surface.soft_cfm = 1e-6f;
}
// Check for actual collisions between the two objects
int numc = dCollide(o1, o2, MAX_CONTACTS, &contact[0].geom,
sizeof(dContact));
if(numc > 0)
{
//VCNContactGeom* contactGeoms = new VCNContactGeom[numc];
// Create the contact joints for the collision
for (int i = 0; i < numc; i++)
{
dJointID c = dJointCreateContact(m_World, m_CollisionJoints,
&contact[i]);
dJointAttach(c, b1, b2);
//contactGeoms[i] = VCNContactGeom(contact[i].geom);
}
// Call the gameplay object's collision handler. Its goal is
// not to move the object or anything, that is done above.
// The goal should just be to do any game-specific behavior when
// contact occurs between two specific objects (for example, when a
// character contacts a power-up it should be picked up at that moment)
if (go1 != 0 && go2 != 0) {
go1->HandleCollision(go2);
}
}
}
//--------------------------------------------------------------------------
And the function that gets called every time step:
//--------------------------------------------------------------------------
VCNBool VCNPhysicsCore::Process()
{
// TODO: We'll need a callback function that the dSpaceCollide function
// can call which will check for collisions and adjust any game object
// parameters (speed, position) when there is a collision
dSpaceCollide(m_Space, (void*)this, GlobalNearCallback);
// Call the physics library's step function.
// Step the world. Use dWorldStep if this is not precise enough.
dWorldQuickStep(m_World, GetNextStepSize());
// Empty the collision joint group
dJointGroupEmpty(m_CollisionJoints);
// Apply the motions to the objects
UpdatePhysicsObjects();
return true;
}
//--------------------------------------------------------------------------
I was surprised that lowering the resolution to 32x32 didn't improve performance
that much, since it's 16 times less polygons... Normally I don't think 2048
polygons is really that many...
Of course, the thing that may be slowing things down is that the terrain is like
a "sink" and the submaine in my game is always inside it. Picture something like
this in 3D:
-- -- <-- water surface
\ * <-- submarine __ /
\ ___ / \ /
\___/ \____----_____/ \___/ <-- bottom of the sea
So the bounding box test for the terrain with anything would always succeed, and
it would have to check every polygon. The only way to speed it up if that's the
only thing causing the slowdown would be to split the terrain into "tiles",
right? Or is there another way?
Any suggestions would be appreciated. Thanks in advance,
J-S
[1] http://www.gamasutra.com/features/20000228/ulrich_01.htm
--
______________________________________________________
Jean-Sebastien Guay jean-sebastien.guay at polymtl.ca
http://whitestar02.webhop.org
More information about the ODE
mailing list