An articulation is a single actor comprising a set of links (each of which behaves like a rigid body) connected together with special joints. Every articulation has a tree-like structure - so there can be no loops or breaks. Their primary use is modelling physically actuated characters. They support higher mass ratios, more accurate drive models, have better dynamic stability and a more robust recovery from joint separation than standard PhysX joints. However, they are considerably more expensive to simulate.
Although articulations do not directly build on joints, they use very similar configuration mechanisms. In this section we assume familiarity with PhysX joints.
Creating an Articulation
To create an articulation, first create the articulation actor without links:
PxArticulation* articulation = physics.createArticulation();
Then add links one by one, each time specifying a parent link (NULL for the parent of the initial link), and the pose of the new link:
PxArticulationLink* link = articulation->createLink(parent, linkPose); PxRigidActorExt::createExclusiveShape(*link, linkGeometry, material); PxRigidBodyExt::updateMassAndInertia(*link, 1.0f);
Articulation links have a restricted subset of the functionality of rigid bodies. They may not be kinematic, and they do not support damping, velocity clamping, or contact force thresholds. Sleep state and solver iteration counts are properties of the entire articulation rather than the individual links.
Each time a link is created beyond the first, a PxArticulationJoint is created between it and its parent. Specify the joint frames for each joint, in exactly the same way as for a PxJoint:
PxArticulationJoint* joint = link->getInboundJoint(); joint->setParentPose(parentAttachment); joint->setChildPose(childAttachment);
Finally, add the articulation to the scene:
The only form of articulation joint currently supported is an anatomical joint, whose properties are similar to D6 joint configured for a typical rag doll (see D6 Joint). Specifically, the joint is a spherical joint, with angular drive, a twist limit around the child joint frame's x-axis, and an elliptical swing cone limit around the parent joint frame's x-axis. The configuration of these properties is very similar to a D6 or spherical joint, but the options provided are slightly different.
The swing limit is a hard elliptical cone limit which does not support spring or restitution from movement perpendicular to the limit surface. You can set the limit ellipse angle as follows:
for the limit angles around y and z. Unlike the PxJoint cone limit the limit provides a tangential spring to limit movement of the axis along the limit surface. Once configured, enable the swing limit:
The twist limit allows configuration of upper and lower angles:
and again you must explicitly enable it:
As usual with joint limits, it is good practice to use a sufficient limit contactDistance value that the solver will start to enforce the limit before the limit threshold is exceeded.
Articulation joints are not breakable, and it is not possible to retrieve the constraint force applied at the joint.
Driving an Articulation
Articulations are driven through joint acceleration springs. You can set an orientation target, an angular velocity target, and spring and damping parameters that control how strongly the joint drives towards the target. You can also set compliance values, indicating how strongly a joint resists acceleration. A compliance near zero indicates very strong resistance, and a compliance of 1 indicates no resistance.
Articulations are driven in two phases. First the joint spring forces are applied (we use the term internal forces for these) and then any external forces such as gravity and contact forces. You may supply different compliance values at each joint for each phase.
Note that with joint acceleration springs, the required strength of the spring is estimated using just the mass of the two bodies connected by the joint. By contrast, articulation drive springs account for the masses of all the bodies in the articulation, and any stiffness from actuation at other joints. This estimation is an iterative process, controlled using the externalDriveIterations and internalDriveIterations properties of the PxArticulation class.
Instead of setting the target quaternion for the joint drive, it is possible to set the orientation error term directly as a rotation vector. The value is set as the imaginary part of the target quaternion, with the real part set to 0.
joint->setDriveType(PxArticulationJointDriveType::eERROR); joint->setTargetOrientation(PxQuat(error.x, error.y, error.z, 0));
This allows the spring to be driven with a larger positional error than can be generated by the difference between 2 quaternions. Obtain the same behavior as with target quaternions by computing the error from the target quaternion, link frames, and joint frames as follows:PxTransform cA2w = parentPose.transform(joint.parentPose); // parent attachment frame PxTransform cB2w = childPose.transform(joint.childPose); // child attachment frame transforms.cB2cA = transforms.cA2w.transformInv(transforms.cB2w); // relative transform if(transforms.cB2cA.q.w<0) // shortest path path transforms.cB2cA.q = -transforms.cB2cA.q; // rotation vector from relative transform to drive pose PxVec3 error = log(j.targetPosition * cB2cA.q.getConjugate());
When any of the joints in an articulation separate beyond a specified threshold, the articulation is projected back together automatically. Projection is an iterative process, and the PxArticulation functions PxArticulation::setSeparationTolerance() and PxArticulation::setMaxProjectionIterations() control when projection occurs and trade cost for robustness.
Articulations and Sleeping
Like rigid dynamic objects, articulations are also put into a sleep state if their energy falls below a certain threshold for a period of time. In general, all the points in the section Sleeping apply to articulations as well. The main difference is that articulations can only go to sleep if each individual articulation link fulfills the sleep criteria.