Any success with Bullet's CharacterController?

I’ve been tinkering all day with Bullet, learning my way through.

The class panda3d.bullet.BulletCharacterControllerNode instanciates a btKinematicCharacterController from the bullet engine.

The idea is that you don’t want to manipulate characters the way you manipulate a crate: characters don’t bounce, characters know how to stand still, how to remain vertical, they have a volition, etc… We control their velocity, not their forces.

Sounded good, so I test it in the simplest environment ever: Wolfenstein3D.

I can’t get half of it to behave decently:

  • the collision response is jerky, there is a tremendous jitter when you push against a wall, whether you slide or not.
  • setMaxJumpHeight has no effect at all.
  • jumping works, but any other kind of free fall occurs at the speed of light and snaps you to the nearest floor instantly.
  • the step_height works, but only if your shape is a cylinder: the capsule (which is the recommended shape) shape gives super messy results.
  • you ‘slide’ down every slope, even if the slope is at 1 %. And by ‘slide’ I mean “violently jitter your way down”.

According to quite a lot of googling, that’s not Panda’s fault, that’s a common issue with Bullet’s btKinematicCharacterController. But that makes me curious, because this really seems to be a key feature and it’s been bugged for years.

Questions to the community:

How do people work around this?
Has anyone managed to use BulletCharacterControllerNode with success?

It indeed is a problem with Bullet itself. Unfortunately, the KCC hasn’t been given nearly enough love from the Bullet developers… How people work around this? Usually by writing their own kinematic character controllers from scratch, ignoring the one supplied with Bullet. It’s not rocket science, but it’s also not the easiest thing in the world and takes some time to debug and achieve stable behavior.

Can we do that in Python ? I tried, and it barfed:

TypeError: BulletWorld.attach_character() argument 1 must be BulletBaseCharacterControllerNode, not 
MyCharacterControllerNode

I defined MyCharacterControllerNode like this:

from panda3d.bullet import BulletBaseCharacterControllerNode

class MyCharacterControllerNode(BulletBaseCharacterControllerNode):
    def __init__(self, shape, step_height, name):
        pass

So, it does absolutely nothing, but it IS inherited from the Base. Somehow, doesn’t work.

I tried to call BulletBaseCharacterControllerNode.init(self) in the init of my class, but it breaks, saying “Type Error: Can Not Init Constant Class”.

Never heard of a constant class before.

I have no experience using Bullet, I’m afraid. I use ODE and I wrote my character controller around that.

The “constant class” error message is interrogate’s way of telling you that this class is an abstract base class, annd you have to derive from it and implement the interface it required. Sadly, you can not do this in Python.

–> If you can use C++ then you can derive from BulletBaseCharacterController, and implement the interface. I have tried once, but without satisfying results.

–> If you want to use Python just implement your own class which is not derived from BulletBaseCharacterController. Use a ghost object or a kinematic rigid body, and control it yourself. You don’t need to add it to BulletWorld - this is just for automatically updating the character controller. Nothng you can not do yourself.

Either way is not not the faint of heart, and it might be very well that a few handy methods required for the Python way are not exposed yet (but this can be chaged).

I agree that the incomplete Bullet character controller is a huge drawback, and suggest using either Coppertops great work with ODE, or the PhysX character controller. For the Panda3D truck we will be waiting until Bullet has fixed this missing feature, or until we spot some open source game using Bullet which has implemented it’s own character controller for Bullet, and which doesn’t mind if we borrow some ideas.

I must add my two cents. IIRC, Panda’s PhysX wrapper doesn’t have continuous collision detection support, which makes it unsuitable for many use cases – any thrown/falling object (be it a grenade or even a crate) will often just fly through walls. This is an important thing to know, if you don’t want to spend a lot of time building stuff around PhysX just to find that one feature is missing.

Awww, I don’t speak c++ at all. I just read it poorly enough to follow Bullet’s source code, vaguely.

Thank you all for clarifying all that!

I’m not particularly attached to Bullet. I picked this one because the Panda manual had many more pages for Bullet than for ODE, and because the built-in character controller seemed nice. Also, the tubes seem enthousiastic.

If I use ODE, how can I create a solid for the player, that always remain vertical, but can push and be pushed by other solids? I’m not asking for a complete source code, but anything that can point me to the right direction is welcome :slight_smile:.

Um… you could have told me that CCD is not exposed. Or maybe you did, and I forgot. Anyway, added CCD support for PhysX on the trunk. Hasn’t been much work.

Check our PM conversation on the state of Bullet bindings :wink:. It was you who told me that CCD was omitted ;D

The thing is, you probably should be ;D.

You see, Bullet is a much more robust solution. It’s more feature complete, it’s more suited for real time simulations. It has kinematic bodies (I have that implemented too, but it’s not the same) and it should be more stable. It has a lot of advantages over ODE.

That said, you need your needs. Here are your options:

  1. Bullet – CCD out of the box, aforementioned advantages for game physics, you need to write a character controller yourself. Good for high performance, complex physics scenes.

  2. PhysX – (1.8.0) no CCD or CCD in trunk, good character controller, very advanced and stable, has soft body, crappy license (if that’s of any relevance to you). Good for high performance, even more complex physics scenes, but only assuming you’d use trunk with the newly commited CCD – otherwise it’s not worth it IMHO.

  3. ODE – (assuming you’d use my code) CCD and character controller, both written in Python, which means they’re not nearly as fast as Bullet or PhysX (the advantage is that you can easily modify both). Additionally, ODE’s collision detection has limitations and its physics solver doesn’t support rolling friction. Suitable for writing an FPS/TPS with not too many moving parts.

That’s the state of physics simulation in Panda at the moment, from my point of view. Since enn0x has added CCD support, I’d assume PhysX might be your best hit right now, if you’re not bothered by the restrictive license. Otherwise, if all you need is a stable KCC and bullets/explosions throwing not too many boxes around, I guess you could go with my code.

Here’s a link to CopperODE if you wanted to take a look: [ODE Middleware)

You are right, Coppertop. I remember now. My appologies. I simply forgot about it.

I’d like to add another aspect to your comparison. The original post in this thread has been about “violent jitter” when moving around in a Wolfenstein3D level, and everything has been blamed on the “buggy” Bullet character controller. Well, the Bullet character controller might be incomplete, but it is not buggy. And I’m pretty sure that much of the “jitter” comes from bad normals for collision mesh triangles. Two adjacent triangles with significantly different normals cause problems. He probably just took the mesh he loaded, and fed it to the collision shapes.

There are different solutions for this problem, often called “welding”. Let’s have a look at how the various physics engines handle this:

1.) PhysX: Automatically applies welding (and a few other things) when cooking a mesh. Sidenote: when writing the PhysX wrapper for Panda3D I didn’t know much about such problems, and probably didn’t expose all of the parameters to control cooking.

2.) Havok: Does not automatically apply welding, but offers tool which do a very good job at welding, either during runtime or offline.

3.) Bullet: Has no tools for automatic wleding. At least I don’t know any. You have to provide the right normals yourself. Just to get it right: you could write tools (in Python) which do all this stuff, so it is possible to create good levels using Bullet. But there is no out-of-the-box support.

4.) ODE: Hmm, don’t know how ODE handles this, but I guess that ODE is similar to Bullet here.

I was also thinking about bad normals. But the jitter happens even against a big flat vertical wall, far away from its vertices. But maybe, my surface was double-sided?

Thanks a lot for teaching me the word “welding”. I was thinking about merging the vertice of the adjacent walls of my dungeon, now I know what to google!

To be fair, I ditched the physics out of my code for now; I don’t need it yet, there are other things I must write first. I let Panda manage my collisions with its Pusher and that’s very much okay at this stage. However, be sure that I’ll come back to you guys when I’ll put some physics again, you’re good :slight_smile:.

Oh, and btw, PhysX license is weird indeed :/.