Panda PhysX

To avoid further confusion: here is a full example of using PandaPhysX from C++. The example is roughly equivalent to the Python sample “01_Basics.py”. A simple scene with a ground plane and a falling box is created, plus the debug renderer.

enn0x

#include "asyncTaskManager.h"
#include "genericAsyncTask.h"
#include "pandaFramework.h"
#include "pandaSystem.h"

#include "PhysEngine.h"
#include "PhysSceneDesc.h"
#include "PhysScene.h"
#include "PhysDebugNode.h"
#include "PhysMaterial.h"
#include "PhysBoxShapeDesc.h"
#include "PhysPlaneShapeDesc.h"
#include "PhysBodyDesc.h"
#include "PhysActorDesc.h"
#include "PhysActor.h"
#include "PhysController.h"


PandaFramework g_framework;
WindowFramework *g_window;

PT(AsyncTaskManager) g_taskMgr;
PT(ClockObject) g_globalClock;

PT(PhysScene) g_scene;
PT(PhysDebugNode) g_debugNode;
PT(PhysActor) g_planeActor;
PT(PhysActor) g_boxActor;


AsyncTask::DoneStatus runPhysics( GenericAsyncTask* task, void* data )
{
  g_scene->do_physics( g_globalClock->get_dt() );
  return AsyncTask::DS_cont;
}


void createScene()
{
  PhysSceneDesc sceneDesc;

  sceneDesc.set_gravity( LVector3f( 0.0f, 0.0f, -9.81f ) );

  g_scene = PhysEngine::create_scene( sceneDesc );
  g_debugNode = g_scene->get_debug_node();
  g_window->get_render().attach_new_node( g_debugNode );
}

void createPlane()
{
  PhysPlaneShapeDesc shapeDesc;
  PhysActorDesc actorDesc;

  shapeDesc.set_plane( LVector3f( 0.0f, 0.0f, 1.0f ), -2.0f );

  actorDesc.add_shape( shapeDesc );

  g_planeActor = g_scene->create_actor( actorDesc );
}

void createBox()
{
  NodePath np;
  PhysBoxShapeDesc shapeDesc;
  PhysActorDesc actorDesc;
  PhysBodyDesc bodyDesc;

  np = g_window->load_model( g_window->get_render(), "box.egg" );
  np.set_pos( LPoint3f( 0.0f, 10.0f, 0.0f ) );

  shapeDesc.set_dimensions( LVector3f( 0.5f, 0.5f, 0.5f ) );

  bodyDesc.set_mass( 10.0f );

  actorDesc.set_body( bodyDesc );
  actorDesc.set_name( "Box" );
  actorDesc.add_shape( shapeDesc );
  actorDesc.set_global_pos( LPoint3f( 0.0f, 0.0f, 4.0f ) );

  g_boxActor = g_scene->create_actor( actorDesc );
  g_boxActor->attach_node_path( np );
}

int main( int argc, char *argv[] )
{
  g_globalClock = ClockObject::get_global_clock();
  g_taskMgr = AsyncTaskManager::get_global_ptr();
  g_taskMgr->add( new GenericAsyncTask( "Runs the physics engine", &runPhysics, (void*) NULL) );

  // FRAMEWORK
  g_framework.open_framework( argc, argv );
  g_framework.set_window_title( "My Panda3D Window" ); 
  g_window = g_framework.open_window();
  g_window->enable_keyboard();
  g_window->setup_trackball();

  // SCENE
  createScene();
  createPlane();
  createBox();

  // MAIN LOOP
  g_framework.main_loop();
  g_framework.close_framework();
  return 0;
}

Thanks for the help. I appoogize for overseeing this stupid mistake.

Still, debug node prolem remains - even when using your code.

g_pDebugNode = g_pPhysScene->get_debug_node();

This line will actually be run through normally. Upon entering panda’s main loop, however, the application will shut down immidiately, without any messages or exceptions thrown.

window->get_render().attach_new_node(g_pDebugNode);

This line will cause an exception in PointerToBase.I

Of course, the first problem only occurs (is visible) when the second line is not active. Since I do not know where to search for the problem, I’m kind of lost here. I don’t know what information to supply either, since I do not get any error messages.

Strange. I have compiled and run the example from above on a Windows
maching, and it (1) doesn’t crash, and (2) renders the debug geometry. I’m pretty sure the problem is somewhere else, maybe you still have mistakes in your code or your project setting are bad.

First hinT: VC has a built in debugger as far as I know. Try using the debugger to find out where the problem ist. Another NULL pointer access?

Another hint: posting just two lines doesn’t help much. As you have seen it is easy to oversee mistakes, because they are made somewhere else. The best chance to get help is if you pack up your project files and source code in such a way that others can download it and compile it.

enn0x

Strange indeed. I set up a new project, created Main.cpp and copied your code (“01_Basics.py” imitation from earlier in this thread) into it. I linked the project against

libp3framework.lib
libpanda.lib
libpandafx.lib
libpandaexpress.lib
libp3dtool.lib
libp3dtoolconfig.lib
libp3pystub.lib
libp3direct.lib
libpandaphysx.lib
PhysXLoader.lib
NxCharacter.lib

This project is clean of all external code (e.g. by me) and I did not modify the source in any way. Yet I still get the error when accessing the scene’s debug node:

  g_debugNode = g_scene->get_debug_node();
g_window->get_render().attach_new_node( g_debugNode );

The first line will - by itself, second line commented - cause the application to terminate instantly, without any messages what so ever.

Inspecting the variables upon crash the debugger tells me the g_window variable holds (apparently) valid data while the g_scene and g_debugNode only hold a PointerToBase and PointerToBase respectively which both only hold a pointer to void. I don’t know if this is supposed to be or if the debugger cannot obtain more detailed information.

Further confusing is the fact that only accessing the scene’s get_debug_node() method by itself will cause strange behaviour. The application will run through the statement without any special messages but upon encountering panda’s main loop statement it will terminate instantly. This will happen even if I only call the method, not even assigning its return value to a variable - less to speak of actually doing something with it.

Deactivating/commenting both lines will have the project work just fine so I would expect the problem to be only with the scene’s debug node.

I’m using VS2008 on WinXP with Panda’s windows standard build.

You’re not making your build in Debug mode, are you? If you’re using the standard Panda3D libraries, you have to make your build in Release mode, or it will crash at inexplicable places.

David

Nop, I’m building in Release mode.

I am using VC2008 too, but from the command line and using scons as a build system. anyway, here are the command lines I got for compiling and linking the example (main.cxx, no header file). Please check if you are using different compiler/linker flags. VC should display what commands it executes.

Hmm… you are using 0.4.7 (just to make sure)? And did you compile PandaPhysX yourself? If so, did you use the scons file or did you setup a VC project yourself?

enn0x

cl /Fomain.obj /c main.cxx /TP /nologo /MD /EHsc /wd4275 /wd4005 /DWIN32 /D_WINDOWS /DWIN32_VC "/IC:\Program Files\Microsoft Visual Studio 9\VC\include" "/IC:\Program Files\Microsoft SDKs\Windows\v6.1\Include" "/IC:\Program Files\Panda3D-1.6.2\python\include" "/IC:\Program Files\Panda3D-1.6.2\include" "/IC:\Program Files\NVIDIA Corporation\NVIDIA PhysX SDK\v2.8.1\SDKs\Physics\include" "/IC:\Program Files\NVIDIA Corporation\NVIDIA PhysX SDK\v2.8.1\SDKs\PhysXLoader\include" "/IC:\Program Files\NVIDIA Corporation\NVIDIA PhysX SDK\v2.8.1\SDKs\NxCharacter\include" "/IC:\Program Files\NVIDIA Corporation\NVIDIA PhysX SDK\v2.8.1\SDKs\NxExtensions\include" "/IC:\Program Files\NVIDIA Corporation\NVIDIA PhysX SDK\v2.8.1\SDKs\Foundation\include" "/IC:\Program Files\NVIDIA Corporation\NVIDIA PhysX SDK\v2.8.1\SDKs\Cooking\include" /IC:\Development\PhysX\test\include

link /nologo /DEBUG /OUT:main.exe "/LIBPATH:C:\Program Files\Microsoft Visual Studio 9\VC\lib" "/LIBPATH:C:\Program Files\Microsoft SDKs\Windows\v6.1\Lib" "/LIBPATH:C:\Program Files\Panda3D-1.6.2\python\libs" "/LIBPATH:C:\Program Files\Panda3D-1.6.2\lib" "/LIBPATH:C:\Program Files\NVIDIA Corporation\NVIDIA PhysX SDK\v2.8.1\SDKs\lib\Win32" /LIBPATH:C:\Development\PhysX\test\lib libpanda.lib libpandaegg.lib libpandaexpress.lib libp3dtool.lib libp3dtoolconfig.lib libp3framework.lib PhysXLoader.lib NxCharacter.lib libpandaphysx.lib main.obj

And here is the scons file:

import os

PANDADIR = os.environ['PROGRAMFILES'] + '/Panda3D-1.6.2'
PHYSXDIR = os.environ['PROGRAMFILES'] + '/NVIDIA Corporation/NVIDIA PhysX SDK/v2.8.1/SDKs'
VCDIR    = os.environ['PROGRAMFILES'] + '/Microsoft Visual Studio 9'
SDKDIR   = os.environ['PROGRAMFILES'] + '/Microsoft SDKs/Windows/v6.1'
PPDIR    = 'C:/Development/PhysX/test'

EnsureSConsVersion( 1, 0 )
VariantDir( 'built', 'source', duplicate=0 )

env = Environment( ENV=os.environ )
env.Decider( 'MD5' )

# Visual Studio 8.0
#
env.Append( PATH    = [  VCDIR + '/VC/bin' ] )
env.Append( PATH    = [  VCDIR + '/Common7/IDE' ] )
env.Append( CPPPATH = [  VCDIR + '/VC/include' ] )
env.Append( LIBPATH = [  VCDIR + '/VC/lib' ] )
env.Append( CPPPATH = [ SDKDIR + '/Include' ] )
env.Append( LIBPATH = [ SDKDIR + '/Lib' ] )
env.Append( PATH    = [ SDKDIR + '/Bin' ] )

# Python
#
env.Append( CPPPATH = [ PANDADIR + '/python/include' ] )
env.Append( LIBPATH = [ PANDADIR + '/python/libs' ] )

# Panda3D
#
env.Append( CPPPATH = [ PANDADIR + '/include' ] )
env.Append( LIBPATH = [ PANDADIR + '/lib' ] )
env.Append( LIBS = [ 'libpanda' ] )
env.Append( LIBS = [ 'libpandaegg' ] )
env.Append( LIBS = [ 'libpandaexpress' ] )
env.Append( LIBS = [ 'libp3dtool' ] )
env.Append( LIBS = [ 'libp3dtoolconfig' ] )
env.Append( LIBS = [ 'libp3framework' ] )

# PhysX
#
env.Append( CPPPATH = [ PHYSXDIR + '/Physics/include' ] )
env.Append( CPPPATH = [ PHYSXDIR + '/PhysXLoader/include' ] )
env.Append( CPPPATH = [ PHYSXDIR + '/NxCharacter/include' ] )
env.Append( CPPPATH = [ PHYSXDIR + '/NxExtensions/include' ] )
env.Append( CPPPATH = [ PHYSXDIR + '/Foundation/include' ] )
env.Append( CPPPATH = [ PHYSXDIR + '/Cooking/include' ] )
env.Append( LIBPATH = [ PHYSXDIR + '/lib/Win32' ] )
env.Append( LIBS = [ 'PhysXLoader' ] )
env.Append( LIBS = [ 'NxCharacter' ] )

# Panda PhysX
#
env.Append( CPPPATH = [ PPDIR + '/include' ] )
env.Append( LIBPATH = [ PPDIR + '/lib' ] )
env.Append( LIBS = [ 'libpandaphysx' ] )

# Flags
#
env.Append( CPPDEFINES = [ 'WIN32', '_WINDOWS', 'WIN32_VC' ] )
env.Append( CCFLAGS = [ '/MD', '/EHsc', '/wd4275', '/wd4005' ] )
env.Append( LINKFLAGS = [ '/DEBUG' ] )

env.Program( 'main.cxx' )

enn0x,
How can I implement croutching with a PhysController?

Reduce the height of the controller, e. g. PhysCapsuleController.setHeight(). You might have to adjust the offset of your ‘visual’ character model (aka Actor), since the visual models usually have their origin between their legs, while the physcial controller has it’s origin in the center of the body.

enn0x

PhysCapsuleController.setHeight() makes my PhysController fall through the floor, even when setting it to its current height. I guess the capsule gets removed and then replaced with a new one, I’ll probably have to make the controller jump before changing the height.

It seems that the radius is also changing even though I’m not calling a setRadius. If I use setRadius after or before setHeight I get some weird results, the radius becomes more, even though I am also setting it to its supposed current radius. I see that you did not implement croutching in the controller sample. After adding self.controller.setHeight(factor) to the doCroutch function, the controller also falls through the ground, but if I jump first and then croutch the radius also changes. Could this be a bug?

Yes, there is a bug. setHeight() doesn’t set the height, but the radius.

Trying to place the controller exactly on the height of the ground will result in it randomly falling through the ground. Try setting it a bit above the ground. Depending on the ground slope you might want to set it even higher.

enn0x

I’m simulating a whole bunch of boxes falling into a container. They nicely fall down and begin stacking in some random order just like one would expect but there is also some odd event happening: they won’t settle down completely.

Every once and then one of the boxes suddenly leaps up and falls down again, just like something has hit it from beneath. At that point in time, the boxes have alrdeady started to settle down and are barely moving at all. It’s unlikely one of the boxes on the bottom of the stack could be moving that fast as to push/hit other boxes completely ouf of place again - not to speak of making them fly up.

From my experiences with the physics engine I guess this is due to some “internal” collision of the boxes - meaning their physical shapes overlap instead of collide - which will result in a strong force pushing hem away from each other, just as putting two actors in a scene with overlapping coordinates and bodies. At least it looks pretty similar.

Unfortunately, I still can’t use the pandaphysx debug mode as it will crash the application immidiately upon initialization of the mode. I’ll get to that problem one of these days. Until then, I hope you can give me some advice on what is happening here and how I can analyze/solve the problem. Is there a way to set something like a “penetration depth” for actors so those boxes will collide immidiately upon contact ? Although I guess they are already doing exactly that.

The boxes will eventually come to rest but it does look kind of odd until then.

Maybe these parameters will help:
Box count: 4x4x50
Mass: 1 - 10 (random for each box)
DynFrict: 0.4
StatFrict: 0.4
Rest: 0.01 (even this low a restituion will not prevent “late bouncing”)
Shape: 1x1x1 up to 5x5x5 (random for each box)

This is a problem inherent to computer physics (note: physics not physx). It can’t be solved in a physical correct way. The best you can do is to “cheat” and use tuning factors to get better results. All physics engine offer various tuning factors. This is what you could try with PhysX:

  • Modify the skin width. The PhysX SDK has a nice chapter about skin with and what it is for. This is the most important factor, since the skin is a region where shapes can interpenetrate.
  • Increase solver iteration count (not sure if this is wrapped…).
  • Use smaller timesteps/substeps.
  • Tune sleep thresholds (e.g. energy threshold).

Be aware that all tuning has downsides too. So you might gain in one aspect but loose in another. It depends on your scene.

enn0x

I have yet another problem, this time with PhysCapsuleShapeDesc. Whenever I try to create an actor with a capsule shape my application’s heap gets corrupted. If I replace that one line with just any other kind of shape it’s all fine. I checked everything else but it seems like it really is a problem with the capsule shape.

I figured the bug with the capsule controller you mentioned might be causing the trouble but then again I don’t have any collision problems with the capsule (so far). The run-time will just tell me there’s a heap corruption but is still able to continue (no crash!). I don’t get this …

The setHeight/setRadius bug? Nope, this can’t cause any memory problems.

You could help me by setting up a small Python script that reproduces your problem.

enn0x

Question for enn0x and also for Panda3D gurus out there:

I have a set of animated characters (22 total), and i’m attaching kinematic PhysActor objects (boxes) to each joint of each of those characters. Each character has 20 joints, so there’s 440 joints total. Since the movement of joints is controlled by animation, i have this function that is called once every frame:

    def moveJointActors(self):
        for actor,nlist in self.jointActors.iteritems():
            for jnp,cnp in nlist:
                cnp.setGlobalMat(jnp.getMat(render))

jnp - is a joint NodePath
cnp - is the corresponding PhysActor object

So basically, it just takes the position/rotation of a joint and applies it to the corresponding PhysActor.

For some reason, this appears to be really ineffective - i checked with pstats, and it takes over 8 ms to do this operation, which is way too long (I’m trying to keep the entire frame time under 17 ms, to maintain 60 fps). Is the approach i’m taking with moveJointActors a fundamentally wrong way to do what i’m trying to do?

Without any measuring by myself: seems right. 440 transforms from C to Python to C is a bit of work. Synchronization from PhysActor --> NodePath is done automatically, but NodePath --> PhysActor not.

If nobody else has an idea: my suggestion would be to extend PhysScene with a list of registered (kinematic) Actors for which a NodePath --> PhysActor sync should be done automatically when calling doPhyscis (or a new method, e. g. updateKinematic). I don’t want to promise any number for performance increase.

Should not be to much work. I could try to do it this weekend. Are you on Windows?

enn0x

that’d be awesome!
and yes, i’m on windows.

tried to implement your suggestion, and got everything to build and work correctly, it seems, but no real speedup :frowning: . I’ll wait for your version. Thanks.

Here it is. For updating the kinematic actors I use actor.moveGlobalMat(), and not actor.setGlobalMat(). This way is recommended by the PhysX manuals. I have not done any performance tests, so please tell me if there is a speedup. PStats should have a PhysX category now, with some subcategories, to give additional info.

Please notice that this is an experimental release. Also my Linux box died, so this time there are only binaries for Windows. I have not been able to test the code on Linux.

http://enn0x.p3dp.com/libpandaphysx_0.4.8.zip

  • Fixed a bug with PhysCapsuleController.setHeight/setWidth.
  • Fixed a bug with character heading.
  • Getting rid of NxCharacter.dll by linking this library statically (Windows).
  • Adds methods to move kinematic actors (moveGlobal*)
  • Adds util to update kinematic actor transforms once a frame.
  • Adds support for pstat.

Built for Panda3D-1.6.2

enn0x