Just like Fixed Joints, we need a couple rigid actors.
PxRigidActor* pRA1,* pRA2;
I'll give them box shapes of unit length.
PxBoxGeometry geo(PxVec3(0.5,0.5,0.5));
PxTransform pform = PxTransform::createIdentity();
In our example one will be kinematic, to hold up the other.
pform.p = PxVec3(0,5,0);
pRA1 = PxCreateDynamic(*gPhysicsSDK, pform,geo,*defaultMaterial, 1.0);
pRA1->isRigidDynamic()->setRigidDynamicFlag(PxRigidDynamicFlag::eKINEMATIC,true);
pform.p = PxVec3(2,5,2);
pRA2 = PxCreateDynamic(*gPhysicsSDK, pform,geo,*defaultMaterial, 1.0);
Add them to the scene.
gScene->addActor(*pRA1);
gScene->addActor(*pRA2);
We will also need a couple transforms to represent the where the joint attaches to the two actors.
PxTransform local1 = PxTransform::createIdentity(), local2= PxTransform::createIdentity();
Creating the joint is done as before.
PxDistanceJoint* pJoint = PxDistanceJointCreate(*gPhysicsSDK, pRA1, local1 ,pRA2, local2);
and although not necessary this time we can set the collision flag.
pJoint->setConstraintFlag(PxConstraintFlag::eCOLLISION_ENABLED,true);
The distance joint may act as a string or a spring, connecting the two actors. There are three flags available for the distance joint.
PxDistanceJointFlag::
eSPRING_ENABLED
eMAX_DISTANCE_ENABLED
eMIN_DISTANCE_ENABLED
by default only the eMAX_DISTANCE_ENABLED is active. With the spring flag disabled the max distance is a hard limit for the joint. However if the spring flag is enabled then this becomes the distance at which the spring force becomes active.
Similarly a minimum distance can be set, but cannot exceed the maximum distance, the spring force will pull the actors to remain between the min and max distance limits.
Recall the Force equation for a spring:
F_spring = - k * x
where 'k' is the spring constant, and 'x' is the distance from the natural length, or in our case, the distance from the min or max limits.
The force experienced by the actors will need to be adjusted by a damping force
F_damping = - c * x'
where 'c' is the damping coefficient, and x' is the first derivative with respect to time of the distance from the natural length (the speed)
F_net = F_spring + F_damping - F_gravity
A spring experiencing a damping force will eventually stop at an equilibrium length (not necessarily the same as the natural length)
The magnitude of the damping coefficient should be chosen to fall into one of four categories. These categories are decided by the ability of the damping to stop the oscillation.
let z = c/sqrt(4mk);
- Un-Damped ( z == 0, so c must be 0)
Choose Un-Damped if you want the spring to oscillate back and forth forever.
- Under-Damped ( 0 < z < 1)
Choose under damped if you want some resemblance of a spring effect where it may oscillate back and forth a few times before coming to rest at an equilibrium state.
- Critically-Damped ( z ==1 )
Choose critically damped if you want the spring to slow perfectly to it's equilibrium.
- Over-Damped ( z > 1 )
Choose over damped if you want the spring to slow down a lot to start and very gradually approach equilibrium.
From left to right we have No Spring, Un-damped, Under-damped, Critically-damped, and Over-damped. The distance joint without a spring stops immediately at its maximum distance. For the rest, the spring does not begin applying a tension until they pass that maximum distance.
Notice that although critically-damped, the box overshoots it's equilibrium position anyway. This is because of the extra momentum generated before the spring was active. I will explain this further in a future post.
Setting the values are straight forward,
pJoint->setSpring(15.0f);
pJoint->setMaxDistance(3.0f);
pJoint->setMinDistance(1.0f);
pJoint->setDamping(0.5);
but are meaningless without the corresponding flag set.
pJoint->setDistanceJointFlag(PxDistanceJointFlag::eSPRING_ENABLED,true);
Hopefully this gives an preview of how distance joints are created and how the spring feature works.
Happy Coding!