Panda Bullet

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 ( bulletphysics.org/Bullet/BulletF … 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).

BulletWorld.attach(node) has the side-effect of setting the world’s gravity on the node. So if you have set a different gravity vector for this node before calling BulletWorld.attach then it will be overwritte. Try calling node.setGravity AFTER BulletWorld.attach(node) and it should work. If not something is wrong.

You are right. BulletManifoldPoint.getNormalWorldOnB returns a vector which is the difference of the contact point position in both body frames. Jus tlook at the old implementation for getPositionworldOnB in Line 133 of bulletphysics.org/Bullet/BulletF … ource.html .

I think naming is a bit misleading here, since it is not a surface normal but a contact normal. However, I think we should stick with the original Bullet namings in cases like this. It makes it easier for users since they can search for original Bullet information and transfer it.

The underlying Bullet class ( btManifoldPoint ) doesn’t have information about the surface normal AFAIK, so we can’t expose it.

So far I don’t know a good solution. but it seems that this is a commonly asked question ( bulletphysics.org/Bullet/phpBB3/ … f=9&t=3538 ).

Great, and thank you! I’ve made a note to get the source from the CVS repository for a new build (I’m using a home-built version of Panda at the moment).

Ahh, I see–I think that I had found at least some changes that seemed to not take effect unless done before attaching the relevant node, and so didn’t think to try calling “setGravity” after attaching the node.

Wow… I’m somewhat disappointed in Bullet’s developers on that point. I would have thought that getting the surface normal at a point of collision would be a fairly standard matter, whether the surface were a triangle mesh or a mathematical collision shape… o_0

Hum… That’s somewhat of a set-back; I’ll have to think further on this…

[edit] Ah, I’d forgotten that ray-casts seem to return a normal, which I would imagine to be the surface normal (after all, the “contact normal” should just be a normalised version of the ray vector). If that is indeed the case then, while rays are not ideal for my purposes, I think that I should nevertheless be able to use ray-tests… [/edit]

Thank you for all of your help! :slight_smile:

Please keep in mind that contact points get created a lot during a physics simulation. Bullet caps the number of contact points to 4 for every two bodies in contact, but imagine a few dozen dynamic objects sliding over a triangle mesh… Thus contact points should be as minimal as possible, but in CPU time and memory size.

The contact normal and distance are important informations for the solvers. The surface normal is not.

I would expect that there is some function somewhere which calculates on demand (!) the surface normal of a collision shape (with a given transform) at a given surface point. Probalby somewhere in the geometry utils. I just haven’t found it so far.

EDIT: I found a good presentation by Erwin Coumans about Bullet contact generation. I think even without time to understand the details it is worth having a look at:
bullet.googlecode.com/files/GDC1 … ontact.pdf

Hmm… Fair enough, although it seems to me that while surface normals might not be important for the internal calculations, they do have uses from the user’s perspective. Perhaps some compromise might be achieved–only generating surface normals when they are actually requested from a contact, for example–but that’s beyond the scope of this thread.

For my own purposes, it’s looking more and more like I’m going to end up falling back on ray-tests as I encounter more situations that call for surface normals, which is a bit of a pity–I rather like the spacial leeway provided by a three-dimensional collision shape–but not ruinous, I don’t think.

Has something changed in either the manifold data produced by contact tests or in the handling of the “getPositionWorld” (i.e. “getPositionWorldOnA” and “getPositionWorldOnB”) methods between Panda versions 1.8.0 and the 1.9 branch?

I’ve just returned to working on a project that uses Bullet collisions, and have found that it seems to have broken between my last putting it down and my picking it up again today. I’ve thus far tracked the problem to the z-values that I’m getting from the “getPositionWorld” methods, which seem to be always producing the same (very small) value regardless of the actual collision (on the z-axis, at least; I haven’t checked the other axes, since I’m not using them).

Hmmm… you are right, there seems to be a problem on the 1.9.x branch. I will try to find out what is going on.

Found it. It has been a very silly bug introduced by me a few months ago. I added a copy constructor and copy assignment operator, but forgot to actually implement the copy assignment operator. Fixed on the trunk now.

Ah, fair enough, and thank you! :slight_smile:

Hi enn0x,

great work!

Could you give me an update wich Bullet Version is in the latest stable 1.8.1Panda3d

I started to work with the 11_SliderConstraint.py (out of the samples) and there seems to be a couple of bugs:

pls correct me if I’m wrong. Upper Limit < than Lower Limit means no constraint ?!

Works for Linear Limit and Angular Limit;

but setting LowerAngular Limit to 0 and upper Angular Limit to 90 shows a 90° Wedge but the movement
is more like 170° the readout of self.slider.getAngularPos() varies between 1.57~pi/4 (90°) and -1.38 ( -79°)

PoweredAngularMotor seems to have no effect

setTargetAngularMotorVelocity has no effect except for beeing able to be read out with getTargetAngularMotorVelocity

setting forces also seem to have no effect

thanks
Martin

Sorry for the late response (again). I am travelling quite often this year, and usually don’t have my private development laptop with me.

I don’t know for sure, but I think 2.80 is the most recent Bullet version usable for the Panda3D 1.8.x branch. It’s quite outdated. Panda3D head supports 2.81. You can check which Bullet version you use by invoking get_bullet_version (directly from the pandq3d.bullet namespace).

Nope. I think the solver still tries to satisfy both limits, by applying large forces. Of course there is no stable state. Erratic movement should be the result.

Testing with my own build (Panda3d head, Bullet 2.81, 32bit) I get a 90deg debug rendering, and the solver correctly positions the linked body within this arc. Sorry, but can’t reproduce this here. Sidenote: the limits are not hard limits. Temporarily angles can be outside the range [lower/upper limit], e.g. if the initial angle is outside or applied forces are huge.

Hmmm… this works for me:

    slider.setLowerAngularLimit(0)
    slider.setUpperAngularLimit(360)
    slider.setPoweredAngularMotor(True)
    slider.setTargetAngularMotorVelocity(0.8)
    slider.setMaxAngularMotorForce(20.0)

Changing the target velocity changes the speed of rotation. I admit that we could have provided an automatic conversion of degree/second to rad/second…

I’m looking at modelling collisions of some fast-moving objects (swords, to be specific), and find myself uncertain of whether the continuous collision system offered by Bullet would work in my situation.

Specifically, the manual describes Bullet using a swept sphere for continuous collision detection, but doesn’t indicate whether this is just a broad-phase element, Bullet treats the object modelled as being spherical, or some other approach is used. What does it do?

To explain, I’m concerned that a spherical representation of my swords would likely not model them very well at all; I imagine that it would produce false-positives as a result of the sphere extending some distance away from the sword on all axes but the one that runs along the sword’s length, presuming a sphere of diameter equal to the length of the blade.

A sphere with the aprox. diameter equals the length of the sword, this is what I think Bullet will use as a collision shape for CCD. CCD after all is basically a so-called “sewwp test”, i.e. a collision test against a tube reaching from the position of the fast moving object in the previous frame to it’s position in the current frame. Sweep test can be done manually too, using the BulletWorld methods.

I think CCD is not the best approach for your case. CCD is good for small objects moving at a fast velocity, where the velocity is assumed constant in between two simulation frames. The engine doesn’t know a lot about the objects movement in between the two frames. A sword moves along an arc.

I have been thinking myself a few times about how to solve this particular problem, but never came up with a perfect concept. So far I think it would be best to do a single collision test at the start or end of the sword slash, and to use a limited number (maybe 3 to 5) small spheres (1/10th of the sword length?) which are distributed along the path which the tip of the sword will move. These small sphere could already be part of the initial collision model of the actor, but disabled via masks. Of course this assumes that the path of the sword tip is know ahead, but i think in most cases this is the case, since when hitting with the sword you probably will play a canned animation.

However, I never implemented something like this myself, so I just can tell you what I would try first. Please share your experiences when implementing such a feature for your game (code snippets or showcase).