Bullet physics in a large voxel world

Post Reply
SyncViews
Posts: 5
Joined: Tue Aug 26, 2014 8:12 pm

Bullet physics in a large voxel world

Post by SyncViews »

I am trying to add Bullet to my game to replace my own physics code from a while back.

The whole is currently divided into 64x32x64 sections (x,y,z, y is up), currently targeting at least 800 such sections coming to 104,857,600 loaded blocks (not run the numbers, Id expect that to be at least 80% or so solid blocks, entirely "empty" sections are not loaded).


Since I have a 3D voxel grid, its already easy for me to determine which solid cubes are within some AABB, or intersect some ray, which were the primitive tests I built my own old collision code off of. However I am not sure how to plug that into Bullet. Simply creating and trying to maintain a massive list of surface cubs (or faces/triangles) is a significant effort itself, and I am not sure how well bullet would handle such a large object count even after I managed to create all that.

There was some talk when I searched around about creating a custom btRigidBody, but I haven't been able to find technical details on that, and the related classes are largely undocumented.

Ideally some method where bullet gives me an AABB to check, and I give it back a bunch of AABB (or potentially other shapes should I choose to add say slopes) for the cubes in that region, and then bullet proceeds to do its own thing with them.
User avatar
Erwin Coumans
Site Admin
Posts: 4221
Joined: Sun Jun 26, 2005 6:43 pm
Location: California, USA
Contact:

Re: Bullet physics in a large voxel world

Post by Erwin Coumans »

Your voxel ground is likely mainly for collision detection, right? In that case, you could create a custom collision shape based on the btConcaveShape. For dynamic (moving, mass>0) rigid bodies that collide with your static world, you can produce triangles on-the-fly, inside some AABB, by implementing this API:

Code: Select all

virtual void	processAllTriangles(btTriangleCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const;
It will be a little bit of work. You could look at the btHeightfieldTerrainShape for inspiration.
Good luck!
Erwin
SyncViews
Posts: 5
Joined: Tue Aug 26, 2014 8:12 pm

Re: Bullet physics in a large voxel world

Post by SyncViews »

Thanks,

I got it to work with the piece of below code. My main issue is I am not sure what partId and triangleIndex means in this context, it looks to me like the height map passed in the (x,z) coord, but at the very least I have(x,y,z) here.

Code: Select all

void TerrainCollisionShape::processAllTriangles(
    btTriangleCallback* callback,
    const btVector3& aabbMinF,
    const btVector3& aabbMaxF)const
{
    //Get the range of integer block coordinates that may be in area
    Vector3I aabbMin((int)std::floorf(aabbMinF.x()), (int)std::floorf(aabbMinF.y()), (int)std::floorf(aabbMinF.z()));
    Vector3I aabbMax((int)std::ceilf(aabbMaxF.x()), (int)std::ceilf(aabbMaxF.y()), (int)std::ceilf(aabbMaxF.z()));
    //Check and clamp to limits
    if (aabbMin.y >= WORLD_HEIGHT) return;
    if (aabbMax.y < 0) return;
    if (aabbMin.y < 0) aabbMin.y = 0;
    if (aabbMax.y > WORLD_HEIGHT) aabbMax.y = WORLD_HEIGHT;
    //TODO: Would be more optimal to then go chunk by chunk to save the chunk lookup
    //TODO: Could also skip y values above the maximum height of the specific chunk
    for (int x = aabbMin.x; x < aabbMax.x; ++x)
    {
        for (int y = aabbMin.y; y < aabbMax.y; ++y)
        {
            for (int z = aabbMin.z; z < aabbMax.z; ++z)
            {
                auto block = world.getBlock(x, y, z);
                //TODO: Could query a shape (some normal bullet one) associated with this block type now?
                //Could that even be better for cubes?
                //Should allow for easier non-cube blocks as well
                //TODO: At the very least likely only want to be generating triangles for the exposed surfaces
                if (block->solid)
                {
                    //TODO: What is partId and triangleIndex, appear to be undocumented
                    //byHeightfieldTerrainShape passes (x,y), but I have (x,y,z)...
                    btVector3 vertices[3];
                    Vector3F p1((float)x, (float)y, (float)z);
                    Vector3F p2 = p1 + Vector3F(1, 1, 1);
                    //Top
                    vertices[0].setValue(p1.x, p2.y, p1.z);
                    vertices[1].setValue(p1.x, p2.y, p2.z);
                    vertices[2].setValue(p2.x, p2.y, p2.z);
                    callback->processTriangle(vertices, 0, 0);
                    vertices[0].setValue(p1.x, p2.y, p1.z);
                    vertices[1].setValue(p2.x, p2.y, p2.z);
                    vertices[2].setValue(p2.x, p2.y, p1.z);
                    callback->processTriangle(vertices, 0, 0);
                    //Bottom
                    vertices[0].setValue(p1.x, p1.y, p1.z);
                    vertices[1].setValue(p2.x, p1.y, p1.z);
                    vertices[2].setValue(p2.x, p1.y, p2.z);
                    callback->processTriangle(vertices, 0, 0);
                    vertices[0].setValue(p1.x, p1.y, p1.z);
                    vertices[1].setValue(p2.x, p1.y, p2.z);
                    vertices[2].setValue(p1.x, p1.y, p2.z);
                    callback->processTriangle(vertices, 0, 0);
                    //South
                    vertices[0].setValue(p1.x, p1.y, p1.z);
                    vertices[1].setValue(p1.x, p2.y, p1.z);
                    vertices[2].setValue(p2.x, p2.y, p1.z);
                    callback->processTriangle(vertices, 0, 0);
                    vertices[0].setValue(p1.x, p1.y, p1.z);
                    vertices[1].setValue(p2.x, p2.y, p1.z);
                    vertices[2].setValue(p2.x, p1.y, p1.z);
                    callback->processTriangle(vertices, 0, 0);
                    //East
                    vertices[0].setValue(p2.x, p1.y, p1.z);
                    vertices[1].setValue(p2.x, p2.y, p1.z);
                    vertices[2].setValue(p2.x, p2.y, p2.z);
                    callback->processTriangle(vertices, 0, 0);
                    vertices[0].setValue(p2.x, p1.y, p1.z);
                    vertices[1].setValue(p2.x, p2.y, p2.z);
                    vertices[2].setValue(p2.x, p1.y, p2.z);
                    callback->processTriangle(vertices, 0, 0);
                    //North
                    vertices[0].setValue(p2.x, p1.y, p2.z);
                    vertices[1].setValue(p2.x, p2.y, p2.z);
                    vertices[2].setValue(p1.x, p2.y, p2.z);
                    callback->processTriangle(vertices, 0, 0);
                    vertices[0].setValue(p2.x, p1.y, p2.z);
                    vertices[1].setValue(p1.x, p2.y, p2.z);
                    vertices[2].setValue(p1.x, p1.y, p2.z);
                    callback->processTriangle(vertices, 0, 0);
                    //West
                    vertices[0].setValue(p1.x, p1.y, p2.z);
                    vertices[1].setValue(p1.x, p2.y, p2.z);
                    vertices[2].setValue(p1.x, p2.y, p1.z);
                    callback->processTriangle(vertices, 0, 0);
                    vertices[0].setValue(p1.x, p1.y, p2.z);
                    vertices[1].setValue(p1.x, p2.y, p1.z);
                    vertices[2].setValue(p1.x, p1.y, p1.z);
                    callback->processTriangle(vertices, 0, 0);
                }
            }
        }
    }
}
SyncViews
Posts: 5
Joined: Tue Aug 26, 2014 8:12 pm

Re: Bullet physics in a large voxel world

Post by SyncViews »

OK, seem to have ran into a couple of issues:
1. Sometimes if a voxel is removed that is touching some moving object (such as the player), it seems the object (e.g. my btKinematicCharacterController gets caught on the newly created corner and jitters significantly.

2. If a fully simulated object, such as a btRigidBody with a btSphereShape comes to a complete rest, and voxels are added or removed that would effect it (e.g. causing a collision in which case I hoped Bullet would move the btRigidBody to the nearest non-colliding spot, or leaving a hole the object should fall down), Bullet does not seem to actually no anything changed, and the object remains inactive, at least until some over moving objects comes near enough to it.

I looked at the heightmap code and couldn't see anything to notify objects of a data change, and its looking to me like it doesnt really support that situation?
User avatar
Erwin Coumans
Site Admin
Posts: 4221
Joined: Sun Jun 26, 2005 6:43 pm
Location: California, USA
Contact:

Re: Bullet physics in a large voxel world

Post by Erwin Coumans »

Are you modifying a collision shape, while the collision shape is part of the dynamics world?
If so, this can lead to issues due to contact caching, Bullet has no way of knowing you changed the shape. You either

(1) remove the object (btRigidBody/btCollisionObject) from the world before making the modification, and re-insert if afterwards or
(2) flush the collision pairs manually with a line like this

Code: Select all

//clear all contact points involving mesh proxy. Note: this is a slow/unoptimized operation.
m_dynamicsWorld->getBroadphase()->getOverlappingPairCache()->cleanProxyFromPairs(staticBody->getBroadphaseHandle(),getDynamicsWorld()->getDispatcher());
(replace m_dynamicsWorld and 'staticBody' with your own)
Hope this helps,
Erwin
SyncViews
Posts: 5
Joined: Tue Aug 26, 2014 8:12 pm

Re: Bullet physics in a large voxel world

Post by SyncViews »

Well chances are something is going to change somewhere in the voxel world pretty much every frame. Would it be advisable to create seperate collision shapes for each area then, so only local objects need to recheck (if theres no "my shape changed in this aabb")? If so what sort of size should I be looking at, how much per-static shape/object cost is there? Would say 32x32x32 work at the result of having 1000's (maybe 10,000's, not done the math) being added and removed from the world, or should I aim to have only 100's of static terrain objects in the world?
User avatar
Erwin Coumans
Site Admin
Posts: 4221
Joined: Sun Jun 26, 2005 6:43 pm
Location: California, USA
Contact:

Re: Bullet physics in a large voxel world

Post by Erwin Coumans »

I all depends, you'll have to explore and see what works well for you.
Post Reply