Problem with character controller and btHeightfieldTerrainShape

Post Reply
Ezlo
Posts: 2
Joined: Fri Oct 16, 2020 9:02 pm

Problem with character controller and btHeightfieldTerrainShape

Post by Ezlo »

I'm writing my own character controller class inheriting from btActionInterface and using a capsule collision shape. When I move the player over a completely flat heightfield it starts to "bounce" slightly but very noticeably, especially as the camera is bound to the player position in my case. I assume the issue is related to this topic https://github.com/godotengine/godot/is ... -417537807 and this https://stackoverflow.com/questions/256 ... ith-bullet

Does this mean the btHeightfieldTerrainShape is unusable for this purpose and I'm forced to use the btBvhTriangleMeshShape or is there something I am missing?

Thank you in advance.
User avatar
drleviathan
Posts: 651
Joined: Tue Sep 30, 2014 6:03 pm
Location: San Francisco

Re: Problem with character controller and btHeightfieldTerrainShape

Post by drleviathan »

Mmmmaybe... but it is not clear. I have experienced the case where hidden normals introduce odd collision directions on a flat btBvhTriangleMeshShape surface. My understanding is: btHeightfieldTerrainShape builds temporary btTriangleShapes instances as necessary whereas btBvhTriangleMeshShape caches its btTriangleShapes in a "boundary volume hierarchy (bvh)". But in both cases you are effectively colliding against "triangle soup" and it is possible to get odd normals at the edges adjacent triangles.

Assuming your character's "bounce" is purely linear and isn't a wobble of rotation... I would suggest trying the following:

(1) Reduce the character's restitution (bounciness) to zero.

(2) Increase effective gravity when character is walking. If you ever need weaker/normal gravity you could set it dynamically as necessary (i.e. when jumping or walking off a ledge).
Ezlo
Posts: 2
Joined: Fri Oct 16, 2020 9:02 pm

Re: Problem with character controller and btHeightfieldTerrainShape

Post by Ezlo »

Thanks a lot for your reply!

The character's restitution I had already set to zero, but increasing the character's gravity definitely helps minimizing the bouncing even though it's still there. With normal gravity the maximum distance from the ground is ~ 0.2 (for reference the character/capsule is ~ 2 units) and with a gravity -50.0f the value decreases to ~0.04.

This is a gif of the character with increased gravity and the bouncing is only noticeable if you're really paying attention to it.
https://gfycat.com/hugeagreeablecurlew

So while it works and I will keep it for now this solution seems to be a little hacky and I would prefer a cleaner solution, so if anyone has any other ideas I'm all ears.

EDIT:
I just found out that the solution of the first link (https://stackoverflow.com/questions/256 ... ith-bullet) also works for btHeightfieldTerrainShape and not only the btBvhTriangleMeshShape, so generating a btTriangleInfoMap and implementing a custom callback for the terrain shape fixes the bouncing completely.

Code: Select all

#include <BulletCollision/CollisionDispatch/btInternalEdgeUtility.h>
  
    ....
    //register callback function
    gContactAddedCallback = collisionCallback;
    ....
    //generate triangle info map
    terrainTriangleInfo = new btTriangleInfoMap();
    btGenerateInternalEdgeInfo(terrainShape, terrainTriangleInfo);
    terrainShape->setTriangleInfoMap(terrainTriangleInfo);
    ....
    //create rigid body for the terrain shape
    btRigidBody::btRigidBodyConstructionInfo bodyInfo(0.0f, motionState, terrainShape, btVector3(0,0,0));
    btRigidBody* body = new btRigidBody(bodyInfo);

    //enable custom callback
    body->setCollisionFlags(body->getCollisionFlags() | btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK);
   ....
   
   //custom callback function
bool BulletPhysics::collisionCallback(btManifoldPoint& cp, const btCollisionObjectWrapper* obj1, int id1, int index1, const btCollisionObjectWrapper* obj2, int id2, int index2)
{
        btAdjustInternalEdgeContacts(cp, obj2, obj1, id2, index2);
        return true;
}
Post Reply