Panda Bullet

Hi enn0x,

Thanks for that, it clears up some issues I was having. I was originally using angular velocity to rotate the character controller as shown in the demo but the problem for me was syncing the rotation with mouse movement, since I rotate my camera and character using the mouse X co-ordinates:

AsyncTask::DoneStatus camera_task(GenericAsyncTask* task, void* data) {
		
		dt = task->get_elapsed_time() - mytime;
        // handle mouse look
        MouseData md = window->get_graphics_window()->get_pointer(0);
		int x = md.get_x();
        int y = md.get_y();
         
		if(window->get_graphics_window()->move_pointer(0, centX, centY))
		{
			camera.set_p(camera,camera.get_p(camera) - (y - centY) * sensY * dt);
			playerNP = player_np.get_h() - (x - centX) * sensX * dt;
			player_np.set_h(playerNP);
		}

		playerController->moveY(player_np,dt,posY);
		playerController->moveX(player_np,dt,posX);

    mytime = task->get_elapsed_time();       
    return AsyncTask::DS_cont;
}

So maybe there’s a trick to that. I guess I have to calculate how many degrees a second the camera is rotating, though it varies because of the mouse movement. As you can see I’m just using set_h here, playerController_ is just a thin wrapper around a BulletRigidBodynode which is kinematic. The problem is the the coordinates are not local for Bullet so it gets confusing pretty quickly.

Thanks,
Zobbo

Hi enn0x,

I’m actually kicking myself now, it was easy to get the rotation working with angular velocity, it’s just a case of keeping track of the mouse movement X+/- and then increasing or decreasing the character angular velocity by small amounts if the mouse X axis moves or setting it to 0 if there’s no relative movement. That’s good because it will be handy for adjusting mouse sensitivity and of course my axis’s will be the right way around in Bullet.

For now the character controller should be enough to be getting on with, but I’ll probably take your advice and implement my own. But one step at a time… :smiley:

One thing that I’m not clear about is that you seem to imply the coordinate system can be changed, is this set in code or the prc? I remember a similar hint in the manual when introducing the scene graph but it didn’t explain how to change the default (excluding setting the up axis in the bullet character controller that is).

Cheers,
Zobbo

The Bullet character controller retrieves it’s up axis via the Panda3D core function “get_default_up_axis()”.

To change it you have to override the config variable “coordinate-system” ( panda3d.org/manual/index.php … _Variables ). ZUp, the default, is what I would recommend. Other values are not tested well.

Hi enn0x,

Thanks, I’ve left everything as default for now and it seems to be working ok so far.

Cheers,
Zobbo

Does bullet support force fields, or is that only a feature in the Blender Game Engine?

Nope, force fields are not supported out of the box.
However, they are easy to implement. You need to register the which objects enter and leave the region of your force field. Each frame add a force to every object inside the field, maybe depending on the position of the object.

I’ve just encountered a problem: at certain points in my code I’m calling RigidBodyNode’s “setTransformDirty” method; when run from the IDE, using a home-compiled CVS version of Panda (albeit one that hasn’t been updated in a while, I think), this works as expected, but when using a version compiled into an installer via packp3d and pdeploy (using versions downloaded separately, I think) I get an error indicating that the method does not exist.

Is this a result of pdeploy downloading and making use of a different version of Panda, presumably one that lacks the “setTransformDirty” method? What might I do about this (aside from removing my use of the method)?

[edit] A small update:
I’m trying a version built using packp3d_dev and pdeploy_dev, as downloaded from runtime-dev.panda3d.org/; at the moment I don’t know whether it’s working, as I’ve hit another problem with that version (discussed in this thread).

This functionality is only available in the Panda3D development branch. The 1.8 / 1.8.1 released don’t have it. So I suppose this is a version mismatch problem. When running from the SDK you get the 1.9 (development) libs, while when using pdeploy you get the 1.8.1 libs. But I’m only guess here, since packp3d/pdeploy is a part of Panda3D where I have zero knowledge.

nods Fair enough–that’s as I somewhat expected.

Thank you for the answer. :slight_smile:

Now, I suppose, is to hope that someone has an answer for me in my other thread, regarding my issue in running a built version made using those development builds (or, perhaps, waiting for 1.9 to be released).

I’m still stuck with regards to making a distributable build, but an idea occurred to me: Enn0x, given willingness to build from source code, is it feasible to get the new features of Bullet into a build of 1.8, and especially into a stand-alone, installer-based distributable version? (Offhand I recall that I’m using the “setTransformDirty” method and the filtering features added to things like ray-casts (which you may recall my asking after previously)–but it’s possible that I’m missing something else that’s not available in 1.8 )

What I have in mind is this:

  • Download the source for 1.8
  • Copy the latest dev. files for Bullet over those in the 1.8 source.
  • Build 1.8.
  • When creating a distributable version, instead of specifying that it depends on Bullet, download the dev. version of the Bullet library and have it include that as an ordinary file in the appropriate place.

Is that likely to work? Does the distributable version rely on being aware that Bullet is being used (so that it knows to look for the library file, for example), and if so, is there a way of spoofing that? (One contingency that comes to mind is installing the game onto a system, replacing the Bullet library there, and then zipping up the game’s directory and distributing that–this is for prototype feedback, so it doesn’t have to be pretty, and can probably tolerate some issues.) Does any of the new Bullet functionality rely on anything from the dev. version of Panda (some new method in NodePath, for argument’s sake)?

[edit] Experiments thus far seem to suggest that it’s not as simple as I’d hoped. I’ve managed to get as far as a black screen, but seem to be tripping up when I attempt to import a Bullet class; I’m not yet sure of whether this is the result of some interdependency with Panda (or some other module), a mistake in my (modified) xml files, a problem with simply boxing up the installation file into a zip and moving it to a new machine, or some other issues…

I’ve a bit of an issue with getting Bullet to accommodate my scene graph and am currently seeking some kind of a solution for it. Basically, my game has a scene graph, where top-level structure is called “Region”. Regions have Neighbour nodes, which point to other Regions. Thus, the coordinates between Regions are relative and there can be multiple paths from an entity to root node such as Render.

The graph could look something like this:

       Render
       |
A      D
|     /|
|   E  |
| /    |
B      F
|      |
|      |
C      H

‘A’ and ‘D’ are the top-level regions. ‘E’ is a neighbour node from ‘D’ that points to content of ‘A’ or ‘D’. Nodes ‘B’ and ‘F’ are merely to hold the direct contents of the region nodes. ‘E’ could point straight to ‘F’ and this is actually an intentional possibility in the game design and the source of some of these issues.

‘C’ and ‘H’ could be both renderable and collidable, with children nodes to handle both cases.

With Bullet, the effect I seem to get is somewhat similar to only one path to top-node being taken and sometimes it looks like nodes ended up duplicated somehow. The following code example showcases this: pastebin.com/rpFpQkcX There, change Line 35 from “node_B.reparentTo(render)” to “node_A.reparentTo(render)” to observe the difference between the two. To me, the natural cause seems that unlike what ends up to renderer (node_A vs. node_B), there’s no similarly changing intermediate root node with BulletWorld. Hence, BulletWorld has no frame of reference and no way to actually know which path to common top node it needed to use.

Far as I know about Bullet’s inner world – which is very little – these kind of multiple parent -things may not be very supportable by it. However, would they be, I’d be very excited to hear how!

But if it regardless turned out that Bullet can’t be made to bend well to my case, I see the following four options:

A) Create a BulletWorld per-region. - This is my least favorite choice, since it’d mean I have to manually select Regions that rays from camera can collide with, I’d have to manually handle moving objects between regions, the regions would also need to overlap so that they can affect each other, etc etc. Basically it’d mean I am doing things as if the P3D scene graph didn’t exist at all.
B) Manually transform RigidbodyNodes and do collisionPairTests. - Would be very performance-heavy and need some intermediate, manual optimizations.
C) Cook up custom collisions. - Yeah, right…
D) Switch to P3D’s own collisions. - Also problematic, since only Sphere is supported as the “From” shape and my objects don’t fit Spheres nicely. Building multiple spheres per-object would lead to either over-use of spheres or to uneven collision surfaces. One possible way would be implementing Box-to-Box and Polygon-to-Polygon collisions myself… But I don’t know the codebase very well.

None sounds very charming to me!

So… Any thoughts/ideas? :slight_smile:

I think your particular scene graph layout is not supportable by the Panda3D Bullet module. The reason is the synchronisation mechanism between Bullet and the Panda3D scene graph. Bullet does not have a hierarchical object structure - all coordinates are absolute. Now, when synchronizing I use something like this:

NodePath np = NodePath::any_path((PandaNode *)this);
CPT(TransformState) ts = np.get_net_transform();

… and vice versa.
This means there is no way of “offsetting” individual worlds.

To make it even worse, Bullet does not provide a way of getting the world instace from a body instance. It is only possible to ask is the body is added to a world. I once considered using special scene graph properties to mark regions of the graph which belong to a world, in order to find the owning Bulletworld instance, but I dropped this idea for sake of usability.

Sorry, but multi-world setups have not been part of the design considerations.

Yeah, I suspected that and got it pretty much confirmed some time ago. To me, it strikes that Bullet is not particularly well designed to be modular and usable by applications that divert from Bullet’s desired way of doing things. This seems evident not only in cases where Bullet’s absolute world coordinate and structuring system does not fit one’s needs, but also when you’d like complicated customization of collision responses and collision pairing.

Thus it seems that I am forced to either use P3D’s in-built collision mechanics and improve upon those, or whip out my own. It’s a decently time-consuming task, but accurate physics I can well skip…

Regardless, thank you for your input. :slight_smile:

Is there any way to find a bullet node by name? (I have checked the API pages for BulletWorld and BulletHelper, but I’m hoping that I missed something somewhere–I am pretty tired today.)

To explain, I have a level that I’m exporting from Blender via YABEE; Bullet collision geometry is then being generated via BulletHelper. However, at a slightly later stage in the process of starting the level, I want to search for certain collision objects and associate them with instances of certain of my own game-classes (making them the collision objects for those instances).

As things stand, for the sake of flexibility, I would rather not do this in the code that produces the Bullet collision geometry: that code is run for all levels, while I want to perform this action in one specific level, and on top of that I want to leave open the possibility of later doing similar things without adding case after case to the general level code.

(I suppose that I could keep a dictionary of all (or perhaps specified) collision objects, using their names as keys, but I’m hoping that there’s a solution to this already available.)

Does the usual method of finding nodes not work?

root.find("**/myName")
root.findAllMatches("**/+BulletRigidBodyNode")

It’s possible that I’m doing something wrong, but it doesn’t seem to, and looking over the output of “.ls()” doesn’t seem to show the relevant nodes. :confused:

However, they do appear to be being loaded into Bullet, as the BulletDebugNode does seem to produce bounding boxes for them.

I’ve done a little more testing, and have more results:

I placed some print-statements in the section of code that uses BulletHelper, both to check that it was running before the level-specific code (it does seem to be), and to check that I was producing RigidBodyNodes as expected (I do seem to be).

I also placed some print-statements in the level-specific code; at the moment I have it printing the result of a “render.findAllMatches” search for BulletBodyNodes, as well as the number of RigidBodyNodes in the BulletWorld object.

Both the printouts near BulletHelper and the result of “BulletWorld.getNumRigidBodies” indicate far more bodies than are being returned by “render.findAllMatches”.

However, looking at which objects are being returned by “findAllMatches”, I notice that they seem to all be bodies to which I’ve already kept references, such as those in my character controller and certain automatically-assigned level objects. Could there be an issue similar to that with Actor, in which not keeping a reference causes the object to be cleaned up, albeit here leaving the Bullet-side body still present?

All right, I think that I’ve found the problem: I had been assuming that BulletHelper would handle the relevant parenting, despite the fact that I had to attach the Bullet bodies myself. As a result, the Panda-side NodePaths were unparented and thus effectively unsearchable (and presumably cleaned up automatically).

However, this prompts another question: since collision has seemed to have been working as expected, is there any disadvantage other than searchability to allowing these Panda-side NodePaths to go unparented? (I’m worried, for example, that something might not be properly cleaned up without them.) My thought at the moment is to leave things as they are, and simply mark collision objects of interest for (possibly temporary) storage for use by my level-scripts…

Sorry to multi-post, but I’ve encountered the following error:

 File "/home/ian/Documents/My Game Projects/Adventuring/Adventuring/Player.py", line 1069, in handleInput
ceilingResult = bulletWorld.contactTest(self.ceilingDetector.node(), use_filter = True)
AssertionError: proxy at line 73 of panda/src/bullet/bulletContactResult.cxx

The code in question generally works; I’m afraid that I’m not quite sure of what I did that resulted in the error popping up. :confused:

This was encountered in Panda 1.9, home-built from the source on Git; the version should be fairly recent, but may be missing newer commits.

This means that the node you passed as argument to bulletWorld.contactTest is a Bullet object (since it has a collision object), but this collision object for some reason has no broadphase proxy (obj->getBroadphaseHandle returns NULL).

What information can you give about this node?

Ah, your response prompted a thought, and I believe that I’ve found the problem (which was a mistake on my side):

As it happens, I have two versions of the collider in question, one used when crouching and one used when standing. (Both are ghost nodes.) When the player crouches, the “standing” collider is removed from and the “crouching” one added to the bullet-world, and vice versa when the player stands again.

The line of code on which this crash happens, however, assumes that the “standing” collider is being used, which is not necessarily the case. A quick test confirms that crouching before this test is performed does seem to produce the crash. I imagine that, somehow, crouching was initiated (whether by an errant button-press or one of the points of code that automatically initiate crouching) just before the collisions that produced the crash previously.

I believe that I have the issue fixed now!

My apologies, and my thanks for your time! ^^;