Thursday 3 July 2014

Getting Started : PhysX - Fixed Joints

Introduction to PhysX Joints

PhysX provides a number of options for the types of joints which may be created. I will work through the creation of each pointing out aspects which might be of interest.

The basic formula for creating any joint is the same. We need access to the PxPhysics singleton factory, at least one rigid actor, and the transform from each actor to the point where the joint is formed.

    Px[Type]Joint* Px[Type]JointCreate(
        PxPhysics& physics,
        PxRigidActor* actor0, const PxTransform& localFrame0,
        PxRigidActor* actor1, const PxTransform& localFrame1);

As mentioned, only one of the two actors needs to be defined. It is possible to create a joint by attaching one side to a point in world space (in which case a NULL pointer may be passed for the actor).

Fixed Joint

Arguably the simplest case, and perhaps the most unused, a fixed joint provides no freedom of movement. It's most useful feature is that it can be broken while experiencing an applied force. After creating a fixed joint I explain how to choose appropriate values for the break force and torque.

First we need our shapes and actors, we can start with some boxes of unit size.

    PxBoxGeometry boxGeo(PxVec3(0.5,0.5,0.5)); //Dimensions are for half-length

    PxRigidActor *pRA1, *pRA2;
    PxTransform kform = PxTransform::createIdentity();

    kform.p = PxVec3(0,3,0);
    pRA1 = PxCreateDynamic(*gPhysicsSDK, kform ,boxGeo,*defaultMaterial, 1.0);
    pRA1->isRigidDynamic()->setRigidDynamicFlag(PxRigidDynamicFlag::eKINEMATIC,true);

    kform.p = PxVec3(1,3,0);
    pRA2 = PxCreateDynamic(*gPhysicsSDK, kform , boxGeo,*defaultMaterial, 1.0);

I have set one of the actors to be kinematic so it will remain suspended despite gravity, while the other will be held up entirely by the strength of the joint. Since the boxes they are of unit length, and are one unit apart, the surfaces will be in contact.

It should also be noted that the joint is formed between the two actors and not the shapes themselves. If the shape isn't centered on the actor, or the actor contained multiple shapes then we might want to consider different local frames.

    PxTransform local1 = PxTransform::createIdentity(),
        local2= PxTransform::createIdentity();

    local1.p = PxVec3(0.5,0,0);
    local2.p = PxVec3(-0.5,0,0);

    PxFixedJoint* pJoint = PxFixedJointCreate(*gPhysicsSDK, pRA1, local1 ,pRA2, local2);

I have moved the position of the local frame to be the same distance as the half-length of the box. This way the joint exists at the edge of the box and not within it. Leaving the position at (0,0,0) will center the joint on the middle of the actor causing the two actors to draw together until they overlap. Moving the local frame further from the origin will force the actors to start further apart. I have made it so that the joint end positions fall exactly on the surface of the box.

For a fixed joint there are two important modifiers to consider. First is the break force, which defines the force and the torque at which the joint will break. These are set to a maximum value by default, but there are some cases in which you would want actors to break apart.

    pJoint->setBreakForce(fForce, fTorque);

In this example the weight of the actor is a force of its own which could break the joint. A box of unit size, and of unit density will have a unit mass.

    mass = 1.0f;

and if we set gravity to a convenient number,

    gravity = PxVec3(0.0f, -10.0f, 0.0);

then the shearing force on our arrangement is

    Force = mass*gravity = 1.0 * -10.0 = -10.0

so in order for one box to not break the joint we need a minimum break force of 10.0.

We also need to consider the torque of the actors themselves. In the simple case like this, where the applied force (due to the weight of the object) is already perpendicular to the axis of the joint the torque calculation is simple.

    Torque = length x force = |length|*|force|*sin(90deg) = |length|*|force|

the length of the lever arm is measured from the joint to the actor, which is also the magnitude of the position vector of the local frame.

    length = |localPose2.p| = |(-0.5,0,0)| = 0.5

    Torque = length * force = 0.5 * 10.0 = 5.0

These are example calculations of the minimum force and torque required to suspend a box of unit size and density off the side of a fixed actor. Further estimations should be made to accommodate for collisions with other actors as well.



The other important modifier is the constraint flag. In particular the default setting is that objects constrained by a joint are allowed to pass through each other. The only constraint is the one enforced by the joint itself. In some cases it may be better for actors connected by a joint to be allowed to interact and collide with each other.

    pJoint->setConstraintFlag(PxConstraintFlag::eCOLLISION_ENABLED, true);

Best of luck finding uses for fixed joints.
Happy Coding!

No comments:

Post a Comment