Migrating From PhysX SDK 2.x to 3.x

This guide describes how to upgrade applications that have an integration of PhysX 2.x to using PhysX 3.x.

Changed Actor Hierarchy

PhysX 2 supports one actor class, and ability to call any method on any instance of this class even if it wasn't applicable. For example, you were able to call isSleeping() on static actors which do not have any sleep logic. In PhysX 3, we decoupled actor into a hierarchy of specialized sub-classes. Due to these changes user code converted to 3.x will benefit from logical clarity, reduction in object sizes and performance improvements.

Collision Filtering

PhysX 2 supports multiple fixed function mechanisms for filtering pairwise shape collisions such as collision groups. Each 2.x multiple group tags can be created, specified as collidable with each other and assigned to shapes.

PhysX 3, supports user callbacks for collision filtering with a restriction that arbitrary memory cannot be accessed by filtering code so that it can be executed on PS3 SPUs or on GPUs with optimal performance. If performance is not a priority, similar functionality can be achieved via conventional callbacks (PxSimulationFilterCallback).

When migrating PhysX 2 code, note that we provide the class PxDefaultSimulationFilterShader in PhysX 3, which emulates a portion of PhysX 2 filtering behavior. Start by checking if this class is sufficient. As this is an extension class, the source code is available and may be extended or customized.

To migrate your fixed function PhysX 2 filtering code on your own, you need to be aware of its exact behavior and implement it as a callback or shader. Let us look at the precise 2.8 mechanisms and make some recommendations for porting:

virtual void NxScene::setShapePairFlags  (  NxShape &  shapeA,
  NxShape &  shapeB,
  NxU32  nxContactPairFlag      //0 or NX_IGNORE_PAIR
 )

virtual void NxScene::setActorPairFlags  (  NxActor &  actorA,
  NxActor &  actorB,
  NxU32  nxContactPairFlag
 )

The first function stored explicit shape pairs in a hash, and a lookup returned the bit indicating to filter or not. The second did the same for actor pairs. Because of the arbitrary size of the pair hash, implementing this mechanism as a shader with fixed memory is difficult in practice, but implementing as a callback should be trivial using a data structure such as the STL hash_map where Key is a struct holding the two pointers and Data is the bit flag.

Another scheme provided by PhysX 2 were collision groups:

virtual void  NxShape::setGroup (NxCollisionGroup collisionGroup)
virtual void NxScene::setGroupCollisionFlag  (  NxCollisionGroup  group1,
  NxCollisionGroup  group2,
  bool  enable
 )

This approach let the user assign shapes to one of 32 collision groups, and then let each pair of groups be assigned a boolean pair flag. This approach lends itself better to a shader based implementation. To do this, you should reserve a word of each shape's filterData (say word0) to hold the group index, and assign this as before. Next, define a matrix to hold the group pair bits, and a function to set it:

NxU32 groupCollisionFlags[32];

//init all group pairs to true:
for (unsigned i = 0; i < 32; i ++)
        groupCollisionFlags[i] = 0xffffffff;


void setU32CollisionFlag(NxU32 groups1, NxU32 groups2, bool enable)
        {
        NX_ASSERT(groups1 < 32 && groups2 < 32);
        if (enable)
                {
                //be symmetric:
                groupCollisionFlags[groups1] |= (1 << groups2);
                groupCollisionFlags[groups2] |= (1 << groups1);
                }
        else
                {
                groupCollisionFlags[groups1] &= ~(1 << groups2);
                groupCollisionFlags[groups2] &= ~(1 << groups1);
                }
        }

Unfortunately it is not possible to change this state after the scene is created. This is because if the matrix could change during simulation, it would force an arbitrary amount of existing contact pairs to be refiltered. In a large simulation, this could be an unacceptable amount of computation. Therefore the matrix must be initialized to its final state before the scene is created, like this:

PxSceneDesc desc;
...
desc.filterShaderData = groupCollisionFlags;
desc.filterShaderDataSize = 32 * sizeof(PxU32);
scene = sdk.createScene(desc);

Finally, you need to code the filter shader to access this data:

PxFilterFlags FilterShader(
                PxFilterObjectAttributes attributes0, PxFilterData filterData0,
                PxFilterObjectAttributes attributes1, PxFilterData filterData1,
                PxPairFlags& pairFlags, const void* constantBlock, PxU32 constantBlockSize)
{
                // let triggers through, and do any other prefiltering you need.
                if(PxFilterObjectIsTrigger(attributes0) || PxFilterObjectIsTrigger(attributes1))
                {
                                pairFlags = PxPairFlag::eTRIGGER_DEFAULT;
                                return PxFilterFlag::eDEFAULT;
                }
                // generate contacts for all that were not filtered above
                pairFlags = PxPairFlag::eCONTACT_DEFAULT;


                PxU32 ShapeGroup0 = filterData0.word0 & 31;
                PxU32 ShapeGroup1 = filterData1.word0 & 31;
                PxU32* groupCollisionFlags = (PxU32*)constantBlock;

                if ((groupCollisionFlags[ShapeGroup0] & (1 << ShapeGroup1)) == 0)
                        return PxFilterFlag::eSUPPRESS;
                else
                        return PxFilterFlag::eDEFAULT;
}

Material Indexes

PhysX 2 used so-called material indexes for stored materials. Material indices are not supported in PhysX 3.0, you'll have to use the object directly. This should be a rather trivial change, unless you are storing a lot of material indices and you want to avoid storing a full reference. In this case you should create your own index array data structure from which you can fetch the pointer before passing it into the API.

Continuous Collision Detection

PhysX 2 uses CCD skeleton meshes for CCD. PhysX 3 no longer needs this data so all skeleton related code can simply be removed.

Pose Description

In PhysX 2 pose was described using a simple matrix. Now the only way to describe a pose is to prepare a PxTransform structure that contains a PxVec3 for translation and a PxQuat for rotation. If the user code uses matrices natively, you will need to convert the matrices into a translation and a rotation component, and then convert the rotation matrix into a quaternion. See the class PxMat33 for helpers to facilitate this conversion, as well as the inverse.

Shape Description

PhysX 2 uses a geometry descriptor to set some required shape parameters (one descriptor for every type of shape, e.g. NxBoxShapeDesc). In PhysX 3, descriptors are no longer used - you should create a required geometry class object (e.g. PxBoxGeometry) and pass it to PxShape using a setGeometry method. This means that the application shape creation logic should be slightly modified. In most cases the new approach is more flexible and needs less code to implement.

In PhysX 2, objects that have different geometry (Box, Capsule, and Sphere) were objects of different classes - now they are all PxShape objects. That means that if you want to figure out which geometry is assigned to some object you should call getGeometryType method. That means that the old way to have every geometry type classes inherited from different shapes classes (e.g. NxBoxShape) will not work now - you will have all geometry type classes inherited from PxShape class and should find out which geometry type it actually has internally.

Joints

The D6 driveType in PhysX 2 no longer exists in PhysX 3. Now drive for D6 is always spring-like: if you want position drive you set the 'spring' value non-zero, if you want velocity drive you set the damping field non-zero, and if you set both you get a damped spring. Some specialized joints like NxJointDriveDesc, NxJointLimitSoftDesc (PhysX 2 names) now were moved to Extensions (see the extensions folder inside PhysX 3 include directory).

Also, if you have used the deleted NxSpringAndDamperEffector, you should now use a joint with a spring property.

Time Stepping

PhysX 2 SDK supported automatic substepping - the simulation attempted to automatically subdivide a single step into a variable number of fixed size simulation steps. This functionality is no longer supported because many users found the precise logic too opaque and had difficulty integrating it with real world applications to get the behaviors they needed. In PhysX 3 it is up to the user to choose the appropriate substep.

In PhysX 2 it was legal to call simulate with a timestep of zero to force the execution of various side-effects of simulation. PhysX 3 neither requires nor supports this.

Scene Queries

The API for scene query functions that return multiple intersections (e.g. PxScene::raycast(...)) has changed. In PhysX 3, raycast/overlap/sweep functions expect a pre-allocated buffer or a callback class as a parameter in order to return multiple intersections. If you do not know the maximum number of intersections in advance you can inherit from PxHitCallback and override processTouches virtual function to receive an arbitrary number of intersections via multiple callbacks using only a fixed size buffer. Please refer to the Scene Query section of the guide for more details and examples.

Raycasts

The interface for making raycasts was changed in PhysX 3. Now you should pass an origin (PxVec3) and a direction (PxVec3) instead of a NxRay that combined these fields in PhysX 2.

Overlaps

Routines like overlapSphereShapes, overlapAABBShapes, overlapOBBShapes, overlapCapsuleShapes are now all covered with PxScene::overlap (passing in a PxSphereGeometry, PxBoxGeometry or PxCapsuleGeometry as a first parameter).

Sweep Tests

PhysX 2 provides a linearCapsuleSweep that takes two points to define the capsule's two spherical ends. In PhysX 3 we have a general sweep() routine that takes a PxGeometry and an initial PxTransform position. Capsules defined in 2.8.x as two points should be converted to an initial transformation (PxTransform) that consists of PxVec3 for position and PxQuat for rotation. PxCapsuleGeometry's length is along the x axis in local space.

Compartments

PhysX 2 scenes supported scene compartments. A separate compartment could be assigned to simulating rigid bodies, deformables or fluids. The compartments could be simulated in parallel and the scene code contained some extra logic for interaction between compartments. Compartments were added as an afterthought to an SDK that was not originally designed to support interaction between multiple simulation technologies. This design deficiency was addressed from the ground up in PhysX 3 and comparments were no longer needed.

One missing detail is separate time steps are no longer directly supported in 3.x. A possible workaround is to create multiple PxScenes and step them at different rates. In this scenario the force exchange implementation would be entirely up to the user. Another possible approach is to simulate the entire scene using the minimum timestep formerly required for any of the compartments.

Deformables

PhysX 2 supported a wide range of deformable mesh simulation features such as environmental cloth, soft bodies, inflatable balloons and plastic deformation of rigid metal. For performance and code quality reasons, 3.3 temporarily stopped supporting many of 2.8 deformable features in favor of a much simpler and higher performance cloth simulation engine. In PhysX 3 dot releases, we will be incrementally adding back features such as environmental simulation. For the time being there is no substitute for many applications of PhysX 2 deformables.