Panda Bullet

HI enn0x,

I had to roll back to 2.8.0 to get it to compile FWIW.

Thanks,
Zobbo

Ah, right. I remember:

If you compile the Panda3D 1.8.1 code then you have to use Bullet 2.8.0.
If you compile the current Panda3D CVS HEAD code then you can use Bullet 2.8.1.

Actually we had support for Bullet 2.8.1 in CVS HEAD long before the Panda3D 1.8.1 release. But the 1.8.x releases (from the CVS release branch) have to stay ABI compatible with the 1.8.0 release, and so can not pick up all the new features.

If you need Bullet I recommend using the CVS HEAD. There are several fixes and improvements which are not on the release branch.

Thanks enn0x, I’ll take a look at that.

Cheers,
Zobbo

Hi,

Are the bullet world callbacks working from python currently? My damage handling function never gets called after collisions, with the following:

callback = PythonCallbackObject(self.checkImpacts)
self.world.setContactAddedCallback(callback)

Similarly I get nothing from setTickCallback. And setFilterCallback gives me the following error:

:bullet(warning): filter algorithm is not 'python-callback'

This is with the latest windows i386 auto build.

About filtering: The warning given by Panda3D is intended as a hint, that you have to configure the right filter algorithm:

from pandac.PandaModules import loadPrcFileData
loadPrcFileData('', 'bullet-filter-algorithm callback')

The warning is misleading. We renamed from ‘python-callback’ to ‘callback’ when switching from pure Python functions to Panda3D CallbackObjects (in order to support C++ callbacks too). I fix the warning in CVS.

About contact add/removed: You have to do three things in order to get these events.
First, you have set the right config option:

from pandac.PandaModules import loadPrcFileData
loadPrcFileData('', 'bullet-enable-contact-events true')

Seconds, you have to listen for contact events, e. g.:

  def ...setup...:
    self.accept('bullet-contact-added', self.onContactAdded)

  def onContactAdded(self, node1, node2):
    print 'contact added:', node1, node2

Third, you have to tell Bullet for which objects it should generate contact events. Creating events for every object would be a DOS-attack on the event system:

    self.box = BulletRigidBody(...)
    self.box.notifyCollisions(True)

Tick callbacks are - so far - implemented only halfway. I try to finish this step around next weekend.

Found a free hour this weekend; World tick callbacks are implemented now.

Thank you, good sir! I am now getting accurate collision feedback.

I have one more question: For a (rigid) body using a compound shape, how do you get the particular primitive shape instance that was hit in a raytest or collision?

For contact events you can evaluate the numbers given by data.getPartId0/1 and data.getIndex0/1 (there has been a bit of confusion about what Bullet actually provides here, depending on the shape type).

For raycast results I am not aware of a direct way to get this information. Raycasts are implemented via the btCollisionWorld::RayResultCallback structures, and I didn’t see any relevant members in the Bullet API for this struct or structs derived from it.

Yeah it is looking like getIndex returns the appropriate child shape index for a compound shape and the appropriate triangle index for a trimesh shape. (The use of PartId seems a bit more elusive though.)

As far as getting shape information from raytests, I found this on the bullet physics forums:

Is that applicable to Panda Bullet?

Good research. The “addSingleResult” methods are implemented by Bullet itself, but they are virtual, so I can override them. I have to call the base class implemenation (provided by Bullet), and then add the additional stuff (here: store the part information in our callback objects).

I have check in code for both BulletAllHitsRayResult and BulletClosestHitRayResult. I don’t think the additional call level will slow down existing code significantly.

Excellent, thanks again enn0x!

This feature will enable fast and accurate localized hit detection on single body objects. Particularly useful for combat vehicle simulations in games.

Given a near-entirely kinematic world (that is to say, very little is driven by physics), would I be likely to see much benefit from implementing a character controller in Bullet rather than Panda’s internal physics system?

To be a little more specific, I’m working on a project that allows the player to wander around a level (in the vein of Roaming Ralph), and am wondering whether it might not be wise to drop my current work-in-progress Panda-physics controller and start a new Bullet-based controller. I’m hesitant, however, to build an entirely new controller on the off-chance.

I intend (at the moment) to have very few physics-driven interactions; I might want ropes. On the other hand, I’m doing a fair bit of ray- or segment- testing (my NPCs test line-of-sight against the player, and I use a segment to detect objects that the player wants to interact with, for example). Collision with the ground might involve either ray- or segment- testing or a simple capsule shape.

One thing that comes to mind is that I might be able to use fewer collision shapes, given that Bullet (I believe) allows one to use a capsule as a kinematic object.

So, in the situation that I’ve described above, does it seem wise to switch to Bullet?

I’m not sure if it makes sense to switch to Bullet in a nearly entirely kinematic world:

  • Yes, Bullet does have capsule collision shapes. But Panda3D has a built-in capsule shape too: CollisionTube

  • I recall having hear drwr talk about ropes with Panda3D’s internal physics system. I might be wrong, but you could have a look at direct.showutil.Rope import Rope

  • The KCC which comes with Bullet is exposed to Python, but it is very incomplete. I would not recommend setting up on the original Bullet KCC. Coppertop has done some work a new KCC for Bullet ( New Bullet Character Controller ), but I do not know what the current state is.

So if you feel like experimenting a bit you could check out coppertop’s KCC. If it works for you out of the box then I would consider switching. If not I would stick with what you already aleady have.

Bullet’s collision system and Panda3D’s internal collision system do not interact, so if you consider switching you will probably have to rewrite all your code which handles collision and interaction.

There is indeed a capsule shape in Panda’s collision system, but it doesn’t function as an “from” shape; in fact, I think that (ray/line/segment tests aside) spheres are the only available “from” shape, which I’ve found to be somewhat of a nuisance at times.

I recall spotting that, but haven’t played with it before – should I expect similar performance from it as from a Bullet rope?

I’d actually been thinking of building my own (based on what I’ve done thus far with my Panda-based controller), but the controller that you’ve linked me to looks interesting; thank you, I’ll take a look at it, I believe. :slight_smile:

That’s pretty much my reason for hesitating to switch. ^^;

Thank you for the advice. You’ve given me somewhat to think about, at least. :slight_smile:

I’m currently attempting an implementation involving a kinematic object, and find myself uncertain of something:

I believe that kinematic objects don’t respond to forces, but does this extend to linear velocities assigned via “setLinearVelocity”?

What I’m attempting to do is use “setLinearVelocity” to update the object’s internal velocity and thus – hopefully – have its position automatically update. At the moment this doesn’t seem to be working, and I’m unsure of whether this is because kinematic objects ignore their velocity values entirely or whether I’m doing something incorrectly. A quick test indicates that converting the object to a dynamic object – by simply commenting-out the calls to “setKinematic” and “setLinearVelocity” – causes the object to fall as expected, so Bullet seems to be correctly initialised and updated.

I am afraid this is not possible. For kinematic objects Bullet polls the application each frame for the current intended transform state. See section “Kinematic Bodies” here for example: bulletphysics.org/mediawiki-1.5. … tionStates

This means for kinematic objects you have to compute the right transform yourself, and set it via node.setTransform each frame. If you don’t need rotation this is not complex: new_pos = old_pos + dt * lin_vel

If you want to tinker with the Panda3D Bullet code you could start here: BulletRigidsBodyNode.cpp, function transform_changed.

Ah, I see, and thank you.

I don’t have a problem with the way that it works (as I now understand it); it’s simply not as I had expected it to work, and I wanted to be confident that I hadn’t messed something up on my end, I believe.

Should contact tests (in the sense of the “contactTest” method) respect bitmasks?

My expectation is that it would, but at the moment it doesn’t seem to be doing so–but, still being fairly uncertain in my use of Bullet, I’m not sure that I’m not doing something incorrectly.

Code excerpts:

MASK_COLLIDER = BitMask32(1)
MASK_FOOT = BitMask32(2)

# Elsewhere...
self.collider = self.manipulator.attachNewNode(BulletRigidBodyNode())

### (Shape creation omitted for brevity)

self.collider.setCollideMask(MASK_COLLIDER)

Common.getWorld().bulletWorld.attachRigidBody(self.collider.node())

#Elsewhere again...
### Another, similar node named "self.foot" is created
### (said creation omitted for brevity), and it's mask set.

self.foot.node().setIntoCollideMask(MASK_FOOT)
### I think that the inconsistency between this and the above method
### of setting the mask came about from my attempts to fix this issue.

#Finally...
result = Common.getWorld().bulletWorld.contactTest(self.foot.node())
### The results produced seem to indicate that "foot" produces contacts
### with "collider", despite having non-matching masks.

Good point.

So far the contactTest method does not respect any collison masks present. It falls back on the default implementation in btCollisionWorld::ContactResultCallback::needsCollision ( bulletphysics.org/Bullet/BulletF … tml#l00422 ).

Overriding this virtual method would be easy. However, I wonder how I should oveeride it. Currently we offer three different collision filtering mechanism in BulletWorld, and I think we should apply the same filtering mechanism here which is selected by the user in BulletWorld.

However,I don’t want to duplicate all three implementations within our callback object. and re-using the implementation inside BulletWorld is not straightforward.

I need to think about this. Input is welcome of course.

Ah, I see…

You say that there are three filtering methods; the “filtering” section of the manual only mentions BitMasks – what are the other two?

Looking at the page that you link to, it looks as though Bullet has some means of applying filters (“m_collisionFilterMask”)–is there a way to integrate our filtering (at the least the BitMask method) with that, perhaps by overriding “setIntoCollideMask” in BulletBodyNode?

(As for my own project, for the moment I’ll just perform the comparisons on my end after getting the contact results, I believe; it’s likely rather less efficient, but it should do the trick, I believe.)