Porting character controller to Bullet

Hi,

I’m trying to port my kinematic character controller from ODE to Bullet. It proved to be much easier than I anticipated in general, but I’ve hit something that looks like a bug. Or I just don’t understand something.

In order to get my collisions between the kinematic capsule and static environment, I use the world.contactTest query. It gives me all the contact data I need, including the normal and penetration depth and it works fantastic for one contact in a frame.

The problem starts when I have two or more contacts returned by the query. Take a look at this code:

mpQuat = self.movementParent.getQuat(render)
trans = mpQuat.xform(self.linearVelocity)

collisions = Vec3()
result = self.world.contactTest(self.capsuleNP.node())

for contact in result.getContacts():
    mpoint = contact.getManifoldPoint()
    normal = mpoint.getPositionWorldOnB() - mpoint.getPositionWorldOnA()
    
    if mpoint.getDistance() < 0:
        collisions -= normal * mpoint.getDistance()

trans *= self.timeStep
trans += collisions

This is a part of my update method and it’s an almost exact copy of the ODE counterpart.

The problem is that whenever there’s more than one contact, all their manifold points contain the same exact positionA, positionB and distance. If my prints aren’t mistaking me, the values come from the first contact in the list returned by getContacts(), for which they are correct. Obviously, as so they’re rarely correct for the rest of the contacts.

This results in the controller passing through walls or going back and forth in a corner.

This is the code I use to develop this, it’s based on the Character sample for Panda’s Bullet: dl.dropbox.com/u/196274/bulletKCC.zip

Thanks in advance

I decided to try and find out if the correct manifold points are even generated anywhere. It looks like they are – it’s just that the data that goes into the contact query response seems incorrect. This is the brute force hack that works:

for mf in self.world.getManifolds():
    if not (mf.getNumManifoldPoints() > 0 and (mf.getNode0() != self.capsuleNP.node() or mf.getNode0() != self.capsuleNP.node())):
        continue
    
    if mf.getNode0() == self.capsuleNP.node():
        sign = 1
    else:
        sign = -1
    
    for mpoint in mf.getManifoldPoints():
        normal = mpoint.getPositionWorldOnB() - mpoint.getPositionWorldOnA()
        if mpoint.getDistance() < 0:
            collisions -= normal * mpoint.getDistance() * sign

Ok, had a quick look at this promblem and I think I know where I made the mistake. But I need some time to dig deeper and verify.

This is music to my ears :slight_smile:

No rush, the brute force approach allows me to keep going forward, so once the contact query is fixed I can just replace the code.

Btw, would it be possible to make a method in Ghost Node similar to getOverlappingNodes, but one that would return contact data, instead of just nodes?

Thanks for the response.

EDIT:
Ok, so I’ve practically finished porting it. Aside of all the features of my ODE KCC, I’ve also added a slope limiter. I will release the first version as soon as the problem with the contact query is resolved.

Also, I have another question. Right now, my Bullet KCC is not integrated well. Is it possible to allow it to be treated as a node and added using world.attachCharacter()?

I said I THINK I found it. Actually I’m a bit confused now. Using the latest Panda3D SDK buildbot version I get the same issue as you describe. Using my own build of the current Panda3D CVS head I do not get this. The most probable cause is that I am using a different Bullet version than the buildbot machine. I have to investigate with rdb. In the meanwhile I will PM you a download link to my libpandabullet.dll. Would be nice if you can test if the problems are gone using this dll.

Everything else, well, one step each time. I really appreciate your work, since I think that the incomplete character controller which comes with Bullet is probably the biggest drawback of Bullet.

That’s why I decided to port mine. In fact, it was much easier than I anticipated.

I know, but I believe in you ;D

Oh crap… It looks like the problem’s gone on the newest development build. Which is awesome.

Now I am not just a little bit confused, but really confused. Yesterday I asked rdb about the Bullet versions which are used on the buildbot machines, and he told me that currently it is 2.78 (r2378). And I still have the problem you described with the latest Windows build of the Panda3D SDK.

I tested compiling (on Windows) using Bullet 2.80, and it works without modifications, and the problem is gone. This is why I wanted to suggest upgrading the buildbot machines to Bullet 2.80 SP1 (r2531), but only after I have tested compiling on Ubuntu myself.

Hmm… this is a bit strange. I will dig deeper. But I won’t be back with results before end of the month.