Optimizing CompoundCollisionShape

Hello,

I am currently working on creating a game that has a “bloxel” world similar to Minecraft. I want player movement to be calculated server side with Bullet. As such, I wrote an AppState that handles a set of RigidBodyControls with CompoundCollisionShapes (one for each 32x32 chunk) made from a set of BoxCollisionShapes for each block with at least one neighbor air. I have the networking code to move the client’s camera around in the 3D scene as needed. The issue is that the server slows down to < 1 fps whenever the player is anywhere near any chunks (ie. not falling in the air). When the player is awa from the chunks, the server’s fps goes back to 60 or more.

I do not want to use a mesh shape as the mesh building code is on the client and it would be an instance of code duplication to have it on both. I can’t put it in the common package because it relies on the texture atlas code that is only needed by the client.

What can I do to speed up these CompoundCollisionShapes? I’ve already considered doing my own collision detection, but this seems to be a bottomless well of potential issues that are already solved with Bullet.

Here is the basic code that builds the CompoundCollisionShape:

private CompoundCollisionShape buildCollisionShape(){
    CompoundCollisionShape shape = new CompoundCollisionShape();
    BoxCollisionShape boxCollisionShape = new BoxCollisionShape(new Vector3f(.5f, .5f, .5f));
    int cx, cy, cz;

    for(cx=0;cx<Chunk.CHUNK_SIZE;cx++){
        for(cy=0;cy<World.WORLD_HEIGHT;cy++){
            for(cz=0;cz<Chunk.CHUNK_SIZE;cz++){
                if(chunk.getIdAt(cx, cy, cz) != air.getId() && isBlockVisible(cx, cy, cz)){
                    shape.addChildShape(boxCollisionShape, new Vector3f(cx + .5f, cy + .5f, cz + .5f));
                }
            }
        }
    }

    return shape;
}

private boolean isBlockVisible(int x, int y, int z){
    if(chunk.getWorld().getBlockIdAt(x + 1, y, z) == air.getId()) return true;
    if(chunk.getWorld().getBlockIdAt(x - 1, y, z) == air.getId()) return true;
    if(chunk.getWorld().safeGetBlockIdAt(x, y + 1, z) == air.getId()) return true; //safeGetBlockIdAt returns an air block if it is out of bounds (ie. -1 y) This isn't an issue with X and Z as the world is infinite in those directions and will create new Chunk objects as needed
    if(chunk.getWorld().safeGetBlockIdAt(x, y - 1, z) == air.getId()) return true;
    if(chunk.getWorld().getBlockIdAt(x, y, z + 1) == air.getId()) return true;
    if(chunk.getWorld().getBlockIdAt(x, y, z - 1) == air.getId()) return true;

    return false;
}

Building a collision shape is time consuming. I’m not sure of what you’re doing outside this code, but if you update the sahpes at each player step, it will surely be bad ^^

I would try to create a RigidBodyControl for each cube/cube group in the current scene, as (I assume that) Bullet is able to make its own optimisation to determine who may be collisionning with who (octrees). Don’t forget to set their mass to zero.

The collision shapes are only updated when the blocks change.

Well, you remember how inefficient it was to build a visual scene with a bunch of boxes? You know… because of all of the surfaces that are invisible (about 70%).

…the same thing is going to happen for the collision shape. Boxes are a HORRIBLE way to model a box world… ironically.

You are better off fixing your mesh generation design so that you can get a collision shape out of it. You’ll have fewer odd physics glitches that way, too.

Or you could just go a minecraft way and just do simple voxel-based physics, maybe with clever usage of bullet on final calculation stage.

I figured that it would be better to use boxes as it is a simple calculation to determine if a point is in a box or even if a box intersects with another (certainly more simple than checking if a point is inside a mesh of arbitrary shape). Would it be better to use a set of plane colliders in the CompoundCollisionShape? I’d prefer to not have to re-do my meshing code if possible.

I addressed this in the original post:

I have no idea how efficient a compound collision shape is… but made of just boxes, even at the box level, probably 60% of the boxes can never be intersected because they are inside the world. It’s reasonable to consider that the compound collision shape is not intelligently handling these.

A mesh collision shape, on the other hand, is likely optimized in a way similar to how JME optimizes its own meshes for collision calculations. At any rate, even if it had to intersect with every visible quad, this is still a small fraction of the number of boxes it would have to check. Moreover, you won’t get strange glitches as your object partially collides with the inside surfaces of the boxes.

And by the way, for physics collisions, boxes are not a “simple calculation”. Even against a sphere, it has to account for face, edge, and vertex collisions and generate appropriate contact points and normals for those cases. It’s likely enough doing face collision checks, anyway. In my own physics engine, that’s the way I did it as it was the easiest way for me to account for all of the cases… collide with facing sides, pick the best one. (Hopefully bullet is more optimized than that but it’s still not as trivial as you think.)

1 Like

My code is already setup to not add obscured boxes to the map so the inner blocks that are impossible to collide with aren’t an issue. When an object collides with a Box wouldn’t it just do the same calculation it would do for a quad against whatever face of the box it collided with?

I’ll try switching to PlaneCollisionShapes.

Any collision might intersect as many as three faces. It may not know which of the three is the ‘right one’ until it has checked all three.

Also, for physics calculations the contact normals on an edge or a vertex should generally be dependent on the colliding object… ie: they may not be box surface aligned. For example, a sphere colliding with a box corner would prefer a contact normal that pointed towards the center of the sphere. For a capsule, it gets more complicated.

My home-grown physics engine doesn’t deal with this case and instead just has physics glitches. (Though it occurs to me that I might be able to fix this pretty easily as I look at it differently now.)

Well, I just finished implementing planes (via SimplexCollisionShape). It performs slightly worse than the boxes, but it isn’t noticeable unless measured. Do I have any other options than adding the mesh code to the server or writing my own physics engine (mine would probably be a simple fixed rotation fixed speed unrealistic setup)? Perhaps there is a way to combine multiple SimplexCollisionShapes in order to get something that performs on par with a MeshCollisionShape? I know that a MeshCollisionShape performs well as it worked fine when I had player movement calculated on the client.

Well the very least you could try:

GeometryBatch factory out of a chunk.
→ clone
→ remove all buffers and stuff esxcept vertex and index
→ generate mesh collision shape for that.

I guess this would still be multiple times faster at runtime. (at a slightly slower rebuild time)

Compoundshapes in the worst case, perform as good as actual single boxshapes for ALL of the used boxes.

Additional you could physic on client, and do serverside chacks if sensible every time to time, (eg check if inside a box, move to fast, flying ect)

As I said, I want to avoid any sort of mesh generation on the server as if I was going to do it I would have to come up with some sort of polymorphic structure for the client’s textures.

Also, when I make a CompoundCollisionShape out of a set of quads why is it any worse than a MeshCollisionShape made from a mesh made of a bunch of quads?

Minecraft tried doing simple sanity checks on the client, and it didn’t turn out well. Even with additional server-side plugins that are designed to make better sanity checks, there are still plenty of possible exploits.

Because the MeshCollisionShape is optimized.

I mean, you already have direct evidence that it is faster so I’m not sure it does any good to ask why it’s faster. Though, at least in this thread, I haven’t seen that you’ve tested quads yet. I’d expect it to be slower, though. A mesh can make a lot more assumptions about the data (shared edges, shared vertexes, etc.)

So does WOW and i think their checks went pretty ok.

Well just compare the c source code, one can generate a optimized acceleration structure as it assumes non moving blocks, the other can be used for dynamic shapes, and must do worke very tick extra.

I’m mostly curious although I was somewhat hoping to apply the optimizations myself to a CompoundCollisionShape. I did test quads:

You understand that planes are not quads, right? Almost no spatial optimization can be done on planes at all… so effectively you have to check EVERY PLANE.

I understand that. Would it be better to use two triangle colliders for each face just like a mesh is rendered?

I just switched the server to a mesh collider and it performs much better now. Although, for 3.1, I think that improved performance with CompoundCollisionShapes would be a good idea.

We look forward to your patches.

1 Like