Collision detection and response between Kinematic Actor and Rig....

Hi everyone,

I have two actors in my simulation. The first one is a kinematic actor (Capsule) representing the haptic device. I set its position in real time with the transforms of the haptic device through setKinematicTarget(). The second actor is a RigidStatic Actor, which is a triangle mesh.

I got to know that there is no interaction or collision between kinematic actor and static actor. However, it is possible to request contact information for them.

I’m able to get contact report from the callback function and everything works fine. But I have several questions:

  1. About the contact positions, are those positions on the shapes of the actor or the bounding volumes of the shapes? For example, my kinematic actor is a capsule, and my static actor is a triangle mesh, are the contact positions exactly on the capsule and the triangles where they collide, or on the bounding volumes of the capsule and the triangle mesh?

  2. I tried to change the static actor to a sphere and a box to understand the contact positions. For capsule to sphere collision , I always get one contact position no matter what, why? For capsule to box collision, there are at most two contact positions. For capsule to triangle mesh collision, it seems it returns all the contact positions on all the triangles that the capsule collides with.

  3. What is the internal face index that the contact report returns?

  4. Is it possible to get impulses at the same time? In my case, I can only get contact positions, I tried to output the impulses vectors, but they are all zeros. So, is it possible to get impulses between kinematic actors and static actors?

  5. I was trying to get the exact first one contact position when the kinematic actor collides with the static actor by raising the flag “PxPairFlag::eNOTIFY_TOUCH_FOUND”. However, what I got was not one contact position, but several. Is it possible to get the contact position at first collision?

  6. The contact report can also return normals at contact positions. It’s says that the direction of the normal is pointing from the second actor to the first actor. How to decide which one is the first/ second?

  7. The reason that I ask about the first contact position and the normal is because I want to implement my own collision detection and respond between the kinematic actor and the static vector. In order to do that, I need to know the contact position and contact normal at first collision to implement the sliding of the kinematic actor over the static actor rather than penetrating it.

  8. Or is there any other better way to implement the collision detection and response between kinematic actor and static actor since there is no interaction or collision between kinematic actor and static actor in PhysX ?

  9. I also got to know that the Character Controller is Kinematic. And I played with some samples in PhysX, the character (represented with a standing capsule) is able to slide against other objects or heightfield without penetrating any objects . It says that the behavior of the character is implemented with the ‘collide and slide’ algorithm. So, in my case, is it possible to represent the haptic device with a Kinematic Character instead of a Kinematic actor so that I don’t have to implement the collide and slide algorithm between a kinematic actor and static actor by myself?

Thanks in advance for your help!

A kinematic actor has infinite mass. A static actor has infinite mass. Therefore, it’s impossible to simulate their interactions using the equations of motions because you would be trying to solve a collision between two infinite mass objects. Regardless of the velocities involved, the answer would always be infinity. As there’s no physically-correct way to simulate this, PhysX does not support it. We do, however, provide enough information in the way of contact points and scene query functionality that the application could resolve these collisions in a non-physical way if required.

PhysX generates a manifold of contacts that it generated that frame. These were all generated from the configuration of the shapes so there isn’t a concept of the “first” contact. The touch found event tells you that the pair of objects were not colliding until this frame.

If you want just one contact point that tells you how to get out of penetration, you can compute this using either:

PxGeometryQuery::computePenetration

or by performing a sweep with eMTD flag.

Both will, in the case of penetration, return a normal and distance that will translate the objects out of penetration. With the sweep, you will get a witness point (contact point). In the case of computePenetration, you won’t get a witness point.

You could alternatively use sweeps to ensure that the shapes never become penetrated - this is how the kinematic CCT works.

A final option would be to constrain a dynamic actor to your kinematic actor using a PxD6Joint spring to drive it to match the pose of the kinematic actor. This will respond to collisions and give you impulse values while following the kinematic target where possible. You will need to tune your spring and damping values to give you the best results.

Hope this helps

Hi kstorey,

Thank you so much for your detailed advises! It helped a lot!

The simulation I’m trying to implement is a medical surgery simulation, which involves a surgical handle interacting with a static object (patient’s mouth). The handle should move inside the mouth smoothly without penetration. I want the collision detection and response to be as smooth as possible (sliding inside the mouth with no jitters).

So, as you suggested, there are two ways to implement the collision detection between kinematic actor and static actors: Sweeps and Joint spring.

For sweeps, as you said, it will return witness point, normal at first collision and penetration. But, with these information, I need to implement my own collision response, right? Like, how to make the kinematic actor slide over the static actor. You said that the kinematic CCT uses sweeps to ensure the shapes never become penetrated. The sweeps only take care of the collision detection, how is the collision response implemented? Is it available for me to use on my kinematic actor?

For the joint spring method, the only thing I need to do is to constrain a dynamic actor to my kinematic actor? The physX will take care of the collision detection and response of the dynamic actor against the static actor?

With these two methods, which one do you think will be more robust and smooth and achieve a better result for my case?

Thanks again for your help! I really appreciated!

Hi Kstorey,

Btw, why are my post not visible unless I log into my account? They are not visible to the public. Is my account considered as spam by mistake? If that is the case, could you help me remove from the spam list?

Thanks!

I don’t know why your post disappeared. I got a notification email, came to reply - it was gone. It’s back now.

If you use sweeps, you would have to implement your own collision response. You could take a look at the CCT code - that basically just deflects the motion of the character along surfaces. However, the character controller has simplified linear-only velocity (the capsule doesn’t rotate as a result of collisions), whereas you would likely want both linear and angular velocity when simulating medical surgery, so it doesn’t solve the same problem you are attempting to.

If you were to use the joint and dynamics, then PhysX would handle everything for you - you would just need to tune the joint springs to make them follow your controls accurately while diverging if following the target would result in penetrations. Depending on how strong the spring is and how many solver iterations you use, there may still be some penetrations. If the kinematic target and the dynamic object become very separated, the spring force could become quite noisy and result in jitter so you likely need a fairly large damping value on the spring to compensate for this.

The joint-based approach is likely to be the quickest way to get you off the ground. I couldn’t say if it will end up being the best approach but it’s been used a lot in VR games to allow players to grasp objects but not be able to push them through the environment.

Using either contacts, sweeps or MTD queries and then resolving the collisions yourself will be a lot more involved. It will give you full control over collision response but it will be more challenging to implement. This could potentially end up with the best results but I’d suggest giving the spring approach a try first because you should be able to get that working fairly quickly.

Thank you for taking the time to answer my questions. You saved me a lot of time digging into the documentation! I’ll try both methods to see which one works better.

Hi Kstorey,

I have implemented the PxD6 joint as you suggested. Everything works fine but I’m still not very satisfied with my solution. And there are not enough samples related to D6 joint, so I implemented the code all from my understanding.

For the kinematic actor, I first constrained a dynamic actor to it as follows:

joint = PxD6JointCreate(*gPhysics, kinematicActor, PxTransform(PxVec3(0, 0, 0)), dynamicActor, PxTransform(PxVec3(0, 0, 0)));

Both of the actors are same size capsules and have same global poses. I set the joint at their center.

When there is no collision, I want the pose of the dynamic actor to be the same as that of the kinematic actor. When collision happens, I unlock the joint. So in the onContact() callback function, I free the x,y,z translational degree of freedom when PxPairFlag::eNOTIFY_TOUCH_FOUND | PxPairFlag::eNOTIFY_TOUCH_PERSISTS as follows, and set the “freeJoint” flag as “true”.

for (PxU32 i = 0; i < nbPairs; i++){
     const PxContactPair& cp = pairs[i];

     if (cp.events & (PxPairFlag::eNOTIFY_TOUCH_FOUND | PxPairFlag::eNOTIFY_TOUCH_PERSISTS)){
	PxSceneWriteLock scopedLock(*gScene);

	const PxSpring& spring = PxSpring(150.0f, 10.0f); 

	joint->setMotion(PxD6Axis::eX, PxD6Motion::eLIMITED);
	joint->setMotion(PxD6Axis::eY, PxD6Motion::eLIMITED);
	joint->setMotion(PxD6Axis::eZ, PxD6Motion::eLIMITED);
	joint->setLinearLimit(PxJointLinearLimit(0.01f, spring));

	freeJoint = true;

	break;
    }
}

I want the dynamic actor to always match the orientations of the kinematic actor, so I locked the rotations.

Then, in the stepPhysics() function, I first update the pose of the kinematic actor by setKinematicTarget(). And if the “freeJoint” flag is “true”, it means there have collisions, so I do a scene query sweep for the dynamic actor against static actors in the scene until there is no collision:

updateKinematics();

if (freeJoint){
   PxSceneReadLock scopedLock(*gScene);

   //-------------do sweep------------------------
   PxTransform kinPos = kinematicActor->getGlobalPose();
   PxTransform dynPos = dynamicActor->getGlobalPose();

   PxVec3 dir = kinPos.p - dynPos.p;
   PxReal dist = dir.magnitude();
   dir = dir.getNormalized();

   PxShape* shape = NULL;
   dynamicActor->getShapes(&shape, 1);
   PxCapsuleGeometry dynGeo(shape->getGeometry().capsule());

   PxQueryFilterData objType = PxQueryFilterData(PxQueryFlag::eSTATIC);
   PxHitFlags hitFlag = PxHitFlag::ePOSITION;
   PxSweepBuffer hit;
   bool isCollision = gScene->sweep(dynGeo, PxTransform(dynPos), dir, dist, hit, hitFlag, objType);

   if (!isCollision){
	joint->setMotion(PxD6Axis::eX, PxD6Motion::eLOCKED);
	joint->setMotion(PxD6Axis::eY, PxD6Motion::eLOCKED);
	joint->setMotion(PxD6Axis::eZ, PxD6Motion::eLOCKED);

	freeJoint = false;
   }
}

gScene->simulate(timeStep);
gScene->fetchResults(true);

The above code works fine so far. But I have a few questions.

My first question is how to set proper values for the spring. A large stiffness value can make the dynamic actor follow the kinemactic actor closely, but wobble around the kinematic actor. A large damping value can avoid wobbling, but cannot make the dynamic actor follow the kinematic actor closely. I tried to limit the linear motion of the dynamic actor by setting PxJointLinearLimit(0.01, spring). Even though I set the distance to 0.01, the dynamic actor can still move very far away from the kinematic actor when it’s wobbling around the kinematic actor with a high speed. The ideal case is that the dynamic actor can follow the kinematic actor as close and fast as possible with no wobbling. Can this be achieved? Actually my code above can avoid the wobbling problem in an indirect way. By only unlocking the joint when collision happens, the wobbling problem can be avoided because the dynamic actor is blocked by the static object (when moving the dynamic actor in the bowl). However, when sliding the kinematic actor around the sphere, the dynamic actor still wobbles around because there is no object can block it and slow it down (as shown in the attachment picture).

The second question is, do I need a joint drive (PxD6JointDrive drive())? Since the pose of the kinematic actor is fed by the haptic device. And the dynamic actor can be driven directly by the kinematic actor. So I guess not?

The third question is, is the way I’m locking and unlocking the joint right? Is it allowed to unlock the joint in the onContact() callback function and lock the joint in the stepPhysics() function before simulate()? Do I need to to lock the scene every time before setting the constraints of joint? PxSceneWriteLock scopedLock(*gScene)

The fourth question is, in order to achieve best joint behavior, it says that I can increase the iteration count:

dynamicActor->setSolverIterationCounts(4 position iterations, 1 velocity iteration);

how to set proper values for position and velocity iterations? just by increasing them? the larger the better? Also, do I need projection here to achieve a better behavior?

joint->setProjectionLinearTolerance(0.05f);
joint->setConstraintFlag(PxConstraintFlag::ePROJECTION, true);

Also, currently I’m testing with simple triangle meshes (like the sphere and the bowl), my actual model consists thousands of triangles, I’m afraid the simulation speed would drop.

As for the alternative method you suggested, the sweep, you said there is an implementation of the collision detection and response of the CCT in the physX code. Could you tell me where it is? is it in the “SampleCCTActor.cpp” → “defaultCCTInteraction()” function?

I’m looking forward to getting the answers from you. Thanks again for your help!

I’d recommend the not using limits but instead using a drive. The limit you defined will only keep the object within 1cm of your target and it will basically oscillate around this. A drive will exactly follow the pose you require. Depending on the drive stiffness, you may have some oscillation because it is a PD-style controller but, if set stiff enough, it will follow exactly.

The appropriate spring value is dependent on the mass of your dynamic objects being attached to the kinematic. However, it’s an implicit spring so it won’t become numerically unstable if you set it too high - it will just become as stiff as a hard constraint. If you set a very high stiffness value, it will follow perfectly until an obstruction is reached. However, if the target and dynamic pose separation becomes large due to collisions, you may see some jitter and instability. This is where tuning damping and setting a maxForce may be required.

If you don’t want to have any freedom with the orientation, then feel free to lock those axes. Drives are defined on a per-axis basis. Alternatively, the drives will do a very good job of matching both position and orientation but, when you press hard on a surface with your instrument, it will naturally resist motion and also rotate slightly. The ideal angular torque spring stiffness/damping values could be different from the linear spring stiffness/damping values) and you could tune each separately to get different effects. Simple set-up code for all dofs free with identical joint drives for each axis is below:

joint->setMotion(PxD6Axis::eX, PxD6Motion::eFREE);
joint->setMotion(PxD6Axis::eY, PxD6Motion::eFREE);
joint->setMotion(PxD6Axis::eZ, PxD6Motion::eFREE);
joint->setMotion(PxD6Axis::eTWIST, PxD6Motion::eFREE);
joint->setMotion(PxD6Axis::eSWING1, PxD6Motion::eFREE);
joint->setMotion(PxD6Axis::eSWING2, PxD6Motion::eFREE);

joint->setDrive(PxD6Drive::eX, PxD6JointDrive(150.f, 10.f, PX_MAX_F32));
joint->setDrive(PxD6Drive::eY, PxD6JointDrive(150.f, 10.f, PX_MAX_F32));
joint->setDrive(PxD6Drive::eZ, PxD6JointDrive(150.f, 10.f, PX_MAX_F32));
joint->setDrive(PxD6Drive::eTWIST, PxD6JointDrive(150.f, 10.f, PX_MAX_F32));
joint->setDrive(PxD6Drive::eSWING, PxD6JointDrive(150.f, 10.f, PX_MAX_F32));

In this example, I’m using the same spring stiffness/damping values you chose and set maxForce to be PX_MAX_F32.

There is a 4th parameter to PxD6JointDrive, which controls whether this is a force or acceleration spring. An acceleration spring is mass normalized, which means that the same spring values produce the same effect regardless of the mass of the bodies provided the mass/inertia ratio between the bodies is the same.

You can set a drive target pose or drive target value but they both default to identity matrix and zero velocity, which is precisely what you want it to do in your particular case because you basically just want a compliant constraint that attaches your instrument to a kinematic target).

If you are using compliant constraints, you don’t want to enable joint projection.

Generally-speaking, increasing position iterations is the best bet. When simulating springs, position and velocity iterations are equivalent.

Thank you so much for your help! By using drive, it works perfect!