Panda Bullet

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: … 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)



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

### I think that the inconsistency between this and the above method
### of setting the mask came about from my attempts to fix this issue.

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 ( … 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.)

Hmm… I might be that I didn’t update the manual because these filter algorithms are have not been in the 1.8.x series (only in the snapshot builds).

You can select from three different filter algorithms via the following config variable:

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

“mask” is tthe default.

“groups-masks” is described here: Panda Bullet

“callback” finally allows you to use your own callback object (e. g. PythonCallbackObject or C++ class derived from CallbackObject). You have to set it via world.setFilterCallback(cbo). Keep performance in mind though - Python callbacks are dead slow!

Ah, I see, and thank you. :slight_smile:

For my purposes I think that the original mask method is likely the best–at the moment I’m just preventing collisions between two shapes that belong to the same logical object. Of course, the other methods may come in handy at some later stage.

I have been playing around with filtering for BulletWorld.contactTest yesterday, but I ran into some predicaments, and so didn’t check in anything yet.

The problem ist that both BulletWorld.contactTest and BulletWorld.contactTestPair internally rely on the Bullet callabck class btCollisionWorld::ContactResultCallback ( … tml#l00407 ). As you already noticed this class is already prepared for filtering:

  • it provied public members to set a mask and group,
  • if has a virtual function needsCollision

Ok, I can’t use the mask and group directly. But since we have to derive from this class anyway (in order to implement btCollisionWorld::ContactResultCallback::addSingleResult) I can add my own filter information. Using the Bullet collision proxy object which corresponds to the parameter of BulletWorld.contactTest and a reference to the selected collision filter callback object internal to BulletWorld seems natural to me, and works fine.

However, needCollision only has one object, the “other” collision object. So this approach doesn’t work for the similar method BulletWorld.contactTestPair. Ok, I could move the filtering to addSingleResult, but this would be a hit on performance since filtering has to be done multiple times per object pair, and it is obviously not the way intended by Bullet developers. I checked if needCollision is called if invoking BulletWorld.contactTestPair, and no, it is not called (as expected).

So far I think that Bullet developers didn’t forsee the possibility that someone might want to use filtering for contactTestPair (but they did for contactTest), which seems strange.

This leaves me with two options:

  • Either consider both methods as “filtering is not an intended feature”, and leave it to the use to filter the results returned from BulletWorld.contactTest and BulletWorld.contactTestPair themselves,
  • Or add an optional parameter “use_filter=False” to BulletWorld.contactTest only.

Input is welcome, as always.

To my mind, it makes sense that contactTest should include filtering, but that contactTestPair should not: it seems to me that calling contactTestPair implies that the objects should be allowed to collide, and thus that filtering is not called for; one assumes that if the pair should not collide (as in the case in which they are filtered out) then the user would simply not call contactTestPair.

The only situation that occurs to me that provides a counter-argument is the case in which pairs are produced procedurally, as in an iterative situation, and thus in which pairs may come up that haven’t been specifically considered. In this case, however, I think that I’m content for filtering to be the responsibility of the user, since the business of producing pairs to test is already being handled by the user.

In the case of contactTest, however, the object in question is tested against everything else, and so it makes more sense to me that filtering be included–or, better yet, be optional, as you suggest.

On another matter (and my apologies if I’m starting to become a pest with regards to Bullet ^^; ), am I correct in believing that calling “setGravity” on a RigidBodyNode should override the effect of the gravity vector set in BulletWorld? That, in other words, I could call “world.setGravity(Vec3(0, 0, -9))”, then “someRigidBody.setGravity(Vec3(0, 0, 0))” and then have all objects except that last one fall? If so, then something odd is happening on my end: calling “setGravity” on my object doesn’t seem to have much effect, if any.

Is there a way to get the surface normal of a manifold point? In short, I have a situation in which I want to respond to contacts only when their normal has a z-value above a certain threshold (corresponding roughly to “floors”).

At the moment I’m using “contactTest” with a cylinder to generate contact points, but it appears that a manifold point’s “getNormalWorldOnB” method returns a vector with a direction corresponding to that of a vector found by subtracting the result of “getPositionWorldOnB” from that of “getPositionWorldOnA”, which in some cases doesn’t appear to correspond to the surface normal of the node being collided with.

I see that the ray-test results include a “hit normal”; does that correspond to the normal vector of the surface that the ray has collided with? If so, and there’s no way to get the surface normal from “contactTest”, then I might end up switching to ray-tests for my purposes, although this might make the feature that I’m attempting to implement less effective and intuitive.

Makes sense to me. Ok, just a slight modification to the public API. Bulletworld.contactTest has a second, optional parameter “use_filter” now. Default is FALSE. If set to TRUE then the same collision filtering algorithm is applied as used for physics simulation. Also I added a untility function BulletWorld.testFilter(node0, node1) which simply calls the filter function. Might be useful for testing filter settings during development, or before calling BulletWorld.contactTestPair.

I checked in the modification. The next buildbot build should pick them up.

Umm… I should mention that this works only if building with Bullet 2.81 or newer (using 2.82 currently).