Hi,
I prefer bullet as physics engine, it’s really excellent, so I made bullet plugin but it’s messy, hardocoded etc. In short it fits only to my needs and makes no sense to publish it at this stage.
But I think sharing most important parts it’s a good idea. Below it’s more like pseudocode, it’s not compilable. Also I’m using set of floats instead of real matrices/vectors becuase it’s easy and fast to use with bindngs.
Static mesh collider class:
class Collider():
def __init__(self, model, friction, restitution):
m = model.getMat()
bullet.BeginCollider(model.getX(), model.getY(), model.getZ(), m.getCell(0, 0), m.getCell(0, 1), m.getCell(0, 2), m.getCell(1, 0), m.getCell(1, 1), m.getCell(1, 2), m.getCell(2, 0), m.getCell(2, 1), m.getCell(2, 2), friction, restitution)
geomNodeCollection = model.findAllMatches('**/+GeomNode')
#for nodepath in geomNodeCollection.asList(): old way
for nodepath in geomNodeCollection:
geomnode = nodepath.node()
self.__ProcessGeomNode(geomnode)
bullet.EndCollider()
def __ProcessGeomNode(self, geomnode):
for i in range(geomnode.getNumGeoms()):
geom = geomnode.getGeom(i)
self.__ProcessGeom(geom)
def __ProcessGeom(self, geom):
vdata = geom.getVertexData()
for i in range(geom.getNumPrimitives()):
prim = geom.getPrimitive(i)
self.__ProcessPrimitive(prim, vdata)
def __ProcessPrimitive(self, prim, vdata):
vertex = GeomVertexReader(vdata, 'vertex')
prim = prim.decompose()
for p in range(prim.getNumPrimitives()):
s = prim.getPrimitiveStart(p)
e = prim.getPrimitiveEnd(p)
if e - s != 3:
print "Only triangles are supported"
return
vertex.setRow(prim.getVertex(s))
tri0 = vertex.getData3f()
vertex.setRow(prim.getVertex(s +1))
tri1 = vertex.getData3f()
vertex.setRow(prim.getVertex(s+ 2))
tri2 = vertex.getData3f()
bullet.AddColliderTriangle(tri0.getX(), tri0.getY(), tri0.getZ(), tri1.getX(), tri1.getY(), tri1.getZ(), tri2.getX(), tri2.getY(), tri2.getZ())
Bullet’s collider mesh:
void PhysicsBullet::BeginCollider(float x, float y, float z, float m11, float m12, float m13, float m21, float m22, float m23, float m31, float m32, float m33, float arg_friction, float arg_restitution)
{
trimesh = new btTriangleMesh();
x = posx;
y = posy;
z = posz;
m11 = mtx11;
m12 = mtx12;
m13 = mtx13;
m21 = mtx21;
m22 = mtx22;
m23 = mtx23;
m31 = mtx31;
m32 = mtx32;
m33 = mtx33;
friction = arg_friction;
restitution = arg_restitution;
}
void PhysicsBullet::AddColliderTriangle(float t0v0, float t0v1, float t0v2, float t1v0, float t1v1, float t1v2, float t2v0, float t2v1, float t2v2)
{
trimesh->addTriangle(btVector3(t0v0, t0v1, t0v2), btVector3(t1v0, t1v1, t1v2), btVector3(t2v0, t2v1, t2v2));
}
void PhysicsBullet::EndCollider()
{
btCollisionShape* shape = new btBvhTriangleMeshShape(trimesh, false);
btScalar bodymass(0.0f);
btVector3 inertia(0.0f, 0.0f, 0.0f);
btTransform btt;
btt.setIdentity()
btDefaultMotionState* motion = new btDefaultMotionState(btt);
btRigidBody::btRigidBodyConstructionInfo bodyinfo(bodymass, motion, shape, inertia);
btRigidBody* body = new btRigidBody(bodyinfo);
body->setFriction(collider->friction);
body->setRestitution(collider->restitution);
world->addRigidBody(body);
}
Rigid Body class (box and sphere):
class RigidBody():
def __init__(self, node_handler, shape, pos, size, mass, friction, restitution, damping_linear, damping_angular, sleeping_linear, sleeping_angular):
if shape == "box":
self.handler_bullet = bullet.AddBox(pos[0], pos[1], pos[2], size[0], size[1], size[2], mass, friction, restitution, damping_linear, damping_angular, sleeping_linear, sleeping_angular)
elif shape == "sphere":
self.handler_bullet = bullet.AddSphere(pos[0], pos[1], pos[2], size, mass, friction, restitution, damping_linear, damping_angular, sleeping_linear, sleeping_angular)
self.handler_panda = node_handler
def Transform(self):
fmtx = bullet.GetBodyMatrixOGL(self.handler_bullet)
mtx = Mat4()
mtx.set(fmtx[0], fmtx[1], fmtx[2], fmtx[3], fmtx[4], fmtx[5], fmtx[6], fmtx[7], fmtx[8], fmtx[9], fmtx[10], fmtx[11], fmtx[12], fmtx[13], fmtx[14], fmtx[15])
self.handler_panda.setMat(mtx)
Bullet Box and Sphere:
int PhysicsBullet::AddBox(float x, float y, float z, float w, float h, float l, float mass, float friction, float restitution, float damping_linear, float damping_angular, float sleeping_linear, float sleeping_angular)
{
btCollisionShape* shape = new btBoxShape(btVector3(btScalar(w), btScalar(h), btScalar(l)));
btTransform transform;
transform.setIdentity();
btScalar bodymass(mass);
bool dynamic = (bodymass != 0.0f);
btVector3 inertia(0.0f, 0.0f, 0.0f);
if (dynamic)
shape->calculateLocalInertia(bodymass, inertia);
transform.setOrigin(btVector3(x, y, z));
btDefaultMotionState* motion = new btDefaultMotionState(transform);
btRigidBody::btRigidBodyConstructionInfo bodyinfo(bodymass, motion, shape, inertia);
btRigidBody* body = new btRigidBody(bodyinfo);
body->setFriction(btScalar(friction));
body->setRestitution(btScalar(restitution));
body->setDamping(btScalar(damping_linear), btScalar(damping_angular));
body->setSleepingThresholds(btScalar(sleeping_linear), btScalar(sleeping_angular));
world->addRigidBody(body);
}
int PhysicsBullet::AddSphere(float x, float y, float z, float r, float mass, float friction, float restitution, float damping_linear, float damping_angular, float sleeping_linear, float sleeping_angular)
{
btCollisionShape* shape = new btSphereShape(btScalar(r));
shapes.push_back(shape);
btTransform transform;
transform.setIdentity();
btScalar bodymass(mass);
bool dynamic = (bodymass != 0.0f);
btVector3 inertia(0.0f, 0.0f, 0.0f);
if (dynamic)
shape->calculateLocalInertia(bodymass, inertia);
transform.setOrigin(btVector3(x, y, z));
btDefaultMotionState* motion = new btDefaultMotionState(transform);
btRigidBody::btRigidBodyConstructionInfo bodyinfo(bodymass, motion, shape, inertia);
btRigidBody* body = new btRigidBody(bodyinfo);
body->setFriction(btScalar(friction));
body->setRestitution(btScalar(restitution));
body->setDamping(btScalar(damping_linear), btScalar(damping_angular));
body->setSleepingThresholds(btScalar(sleeping_linear), btScalar(sleeping_angular));
world->addRigidBody(body);
}
Fetching OpenGL matrix from bullet:
void PhysicsBullet::GetBodyMatrixOGL(int bodyid, btScalar* mtx) const
{
btCollisionObject* obj = world->getCollisionObjectArray()[bodyid];
btRigidBody* body = btRigidBody::upcast(obj);
if (body && body->getMotionState())
{
btTransform trans;
body->getMotionState()->getWorldTransform(trans);
trans.getOpenGLMatrix(mtx);
}
}