Bullet dynamics integration.

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);
    }
}

Hey, that’s pretty neat!

This makes two of us :slight_smile:
I too started working on a Bullet module some time ago, besides the work on PhysX.

Actually that’s what I searched for, right now. “Excellent!”