I'm trying to make an android game with nice physics inside of closed environments, so I'd chose to use quake 2 bsp as a base for my levels.
First I was using old Tokamak physics engine, which is pretty nice. I used its' terrain callback methods with lookup for closest bsp leaves to generate indices the tokamak should use for collision computations. This lead me to pretty nice and fast rigid box collisions.
But this method had few limitations:
1. I didn't compute cw/ccw triangle indices so sphere collisions had holes with some polygons (I think tokamak uses the directions to compute normals and then use this normals for sphere test)

2. The terrain callback uses triangle tests without ccd and the outside of the world isn't solid this means on low fps (happend while I were optimizing renderer for android) I had boxes running through walls.
3. Tokamak had no character-controller\cloth\etc.
Thats why I decided to give bullet a chance.
So the compilation is pretty simple and I got it working on android and PC.
Then I found the bspdemo inside bullet sdk which made me happy 'cuz hell yeah - that's everything I need and more because no triangle computations needed, only original quake brushes converted with bullet into physical shapes!
But... the performance is SO BAD even on an empty room.
I throw around 30 cubes and get 30fps until they calm down and became static...
With Tokamak I could spam over 2k cubes on pretty huge level with high performance even if they don't calm down and even thought tokamak-based code was doing the physics on per-triangle base! Certanly for each box and its AABB the triangle-list ws regenerated for closest bsp leaves' triangles!
Any ideas how to make something like that on bullets' convexes or anything else?
Could it be that I'm using some wrong initialization?
The convex generation from quake brushes are based on bspdemo, the init is the simplest ever could be:
Code: Select all
m_collisionConfiguration = new btDefaultCollisionConfiguration();
m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration);
m_broadphase = new btDbvtBroadphase();
m_solver = new btSequentialImpulseConstraintSolver;
m_dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher, m_broadphase, m_solver, m_collisionConfiguration);
m_dynamicsWorld->setGravity(btVector3(0,-10,0));

With bullet I get 20 fps @ 50-100 cubes on same scene... this is ridiculous on core 2 cpu... I don't even think to try that on android...
Any ideas on optimizations (take bspdemo from sdk as a base - all brushes fed into bullet and processed by bullet internals)? How can I feed bullet with convex static objects in some range of closest-leafs for each rigid object?
And yes the game won't contain huge amount of rigids, but this is pretty like an example of the speed measurement.
PS: The performance loss is right in m_dynamicsWorld->stepSimulation(...); call. With high-geometry level I get low fps even if no cubes spawned.
Cube spawning:
Code: Select all
btRigidBody *addCube(const btVector3 & origin, float size = cubeScale, float mass = 10.0f) {
btCollisionShape* colShape = new btBoxShape(btVector3(size, size, size));
m_collisionShapes.push_back(colShape);
btTransform startTransform;
startTransform.setIdentity();
startTransform.setOrigin(origin);
btVector3 localInertia(0,0,0);
colShape->calculateLocalInertia(mass, localInertia);
btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform);
btRigidBody::btRigidBodyConstructionInfo rbInfo(mass, myMotionState, colShape, localInertia);
btRigidBody* body = new btRigidBody(rbInfo);
m_rigidBodies.push_back(body);
m_dynamicsWorld->addRigidBody(body);
return body;
}
Code: Select all
btRigidBody *localCreateRigidBody(float mass, const btTransform & startTransform, btCollisionShape *shape) {
bool isDynamic = (mass != 0.f);
btVector3 localInertia(0,0,0);
if (isDynamic)
shape->calculateLocalInertia(mass,localInertia);
#define USE_MOTIONSTATE 1
#ifdef USE_MOTIONSTATE
btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform);
btRigidBody::btRigidBodyConstructionInfo cInfo(mass,myMotionState,shape,localInertia);
btRigidBody* body = new btRigidBody(cInfo);
// body->setContactProcessingThreshold(m_defaultContactProcessingThreshold);
#else
btRigidBody* body = new btRigidBody(mass,0,shape,localInertia);
body->setWorldTransform(startTransform);
#endif//
m_dynamicsWorld->addRigidBody(body);
return body;
}
void addConvexVerticesCollider(btAlignedObjectArray<btVector3> & vertices, bool isEntity, const btVector3 & entityTargetLocation)
{
if (vertices.size() > 0) {
float mass = 0.f;
btTransform startTransform;
startTransform.setIdentity();
btCollisionShape* shape = new btConvexHullShape(&(vertices[0].getX()),vertices.size());
m_collisionShapes.push_back(shape);
localCreateRigidBody(mass, startTransform, shape);
}
}