I am new to bullet and I would like to have some input on its performance on Android.
I have some concerns because I tried Bullet with a small application (basically a square of more than 150 cubes of 1x1unit separated by 1unit + 2 falling cubes) and I found the result are a bit disappointing (slow FPS). Maybe I am a bit too demanding. The weird thing is that the two box fall is slow but once they touch other boxes on the ground, it gets faster (maybe 10/12fps). This is not a graphic related issue (that part seems to run fast). Am using an HTC Desire.
You can find the sample APK here: http://www.mediafire.com/?m7xt20wc44cc5h0 and the resources files here http://www.mediafire.com/?8p2j59atw3765cq (to put in /sdcard/carinae/data/etc.)
The screenshot is a bit weird on the right because it's composed of two images (screen capture is a bit rubbish on Android

The code is basically the following (sorry for that messy extract, this is just was just a small test):
My PhysicsService:
Code: Select all
PhysicsServiceWrapper::PhysicsServiceWrapper():
mCollisionConfiguration(new btDefaultCollisionConfiguration()),
mDispatcher(new btCollisionDispatcher(mCollisionConfiguration)),
mBroadPhaseInterface(new btDbvtBroadphase()),
mConstraintSolver(new btSequentialImpulseConstraintSolver())
{
}
PhysicsServiceWrapper::~PhysicsServiceWrapper()
{
delete mConstraintSolver;
delete mBroadPhaseInterface;
delete mDispatcher;
delete mCollisionConfiguration;
}
PhysicsService::PhysicsService(TimeService& pTimeService):
PhysicsServiceWrapper(),
Service(),
btDiscreteDynamicsWorld(mDispatcher, mBroadPhaseInterface, mConstraintSolver, mCollisionConfiguration),
mTimeService(pTimeService)
{
setGravity(btVector3(0,-10,0));
// Sets-up the ground.
static glm::mat4 TODO;
TODO[3].y = -1.0;
PhysicsMotionState* lGroundMotionState = new PhysicsMotionState(TODO);
btCollisionShape* lGroundShape = new btStaticPlaneShape(btVector3(0.0, 1.0, 0.0), 0.0);
btRigidBody::btRigidBodyConstructionInfo lGroundInfo(FIXED_MASS,
lGroundMotionState,
lGroundShape,
btVector3(0.0, 0.0, 0.0));
btRigidBody* lGroundBody = new btRigidBody(lGroundInfo);
addRigidBody(lGroundBody);
}
const status PhysicsService::start()
{
return STATUS_OK;
}
const status PhysicsService::stop()
{
return STATUS_OK;
}
const status PhysicsService::update()
{
double l1 = mTimeService.immediateElapsed();
stepSimulation(mTimeService.elapsed(), 5);
double l2 = mTimeService.immediateElapsed() - l1;
Log::debug("Physics: %f", l2);
return STATUS_OK;
}
My component for blocks (am experimenting a component based approach):
Code: Select all
class PhysicsBlock : public Component
{
public:
struct Record
{
public:
float mass;
glm::vec3 size;
glm::mat4* output;
private:
friend class PhysicsBlock;
btRigidBody* rigidBody;
};
PhysicsBlock(PhysicsService& pPhysicsService):
mPhysicsService(pPhysicsService),
mRecords()
{
mRecords.reserve(256);
}
virtual const status start()
{
foreach (iRecord, std::vector<Record>, mRecords) {
addRecord(*iRecord);
}
return STATUS_OK;
}
virtual const status stop()
{
foreach (iRecord, std::vector<Record>, mRecords) {
removeRecord(*iRecord);
}
return STATUS_OK;
}
virtual const status update()
{
return STATUS_OK;
}
Record& add()
{
// TODO Multithread problem here
mRecords.resize(mRecords.size()+1);
return mRecords.back();
}
private:
void addRecord(Record& pRecord) {
carinae::PhysicsMotionState* lMotionState = new carinae::PhysicsMotionState(*pRecord.output);
btCollisionShape* lCollisionShape = new btBoxShape(btVector3(pRecord.size.x,
pRecord.size.y,
pRecord.size.z));
btVector3 lInertia(0.0, 0.0, 0.0);
lCollisionShape->calculateLocalInertia(pRecord.mass, lInertia);
btRigidBody::btRigidBodyConstructionInfo lBodyInformation(pRecord.mass,
lMotionState,
lCollisionShape,
lInertia);
pRecord.rigidBody = new btRigidBody(lBodyInformation);
mPhysicsService.addRigidBody(pRecord.rigidBody);
}
void removeRecord(Record& pRecord) {
//mPhysicsService.removeRigidBody(pRecord.rigidBody);
}
PhysicsService& mPhysicsService;
std::vector<Record> mRecords;
};
Code: Select all
for (int i = -7; i <= 7; ++i) {
for (int j = -7; j <= 7; ++j) {
carinae::PhysicsBlock::Record& lPhysicsBlockRecord = lPhysicsBlock.add();
lPhysicsBlockRecord.mass = 1.0;
lPhysicsBlockRecord.size = glm::vec3(1.0, 1.0, 1.0);
lPhysicsBlockRecord.output = &lGraphicsElementRecord.attitude;
}
}
carinae::PhysicsBlock::Record& lPhysicsBlockRecord1 = lPhysicsBlock.add();
lPhysicsBlockRecord1.mass = 1.0;
lPhysicsBlockRecord1.size = glm::vec3(1.0, 1.0, 1.0);
lPhysicsBlockRecord1.output = &lGraphicsElementRecord1.attitude;
carinae::PhysicsBlock::Record& lPhysicsBlockRecord2 = lPhysicsBlock.add();
lPhysicsBlockRecord2.mass = 1.0;
lPhysicsBlockRecord2.size = glm::vec3(1.0, 1.0, 1.0);
lPhysicsBlockRecord2.output = &lGraphicsElementRecord2.attitude;
So am I performing badly (I am an absolute neebie to bullet) or am I too demanding (or both
Have you found some results yourself?
Edit: after testing a bit more, I realized that it's just the first seconds which are slow. Are first simulationSteps slower in bullet? Here is a second app, a bit more funny
http://www.mediafire.com/?nb74ybcwgj6wbu5
I also forgot to say that you need resources files (images, etc.) in the "/sdcard/carinae/data..." directory. Here is the URL for these files http://www.mediafire.com/?8p2j59atw3765cq
But the result is not really "reproducible". When I execute it several time, the result is different. Maybe that"s a clue of bad usage (or maybe some random values are used for bullet simulation?).

