Smallest distance between two rigidbodies

Does PhysX have a built-in way to query the distance between the collision shapes of two rigidbodies?

I found the point-shape distance query in the PxGeometryQuery class, but nothing else. ComputePenetration seems to only return measurements if a penetration occurs, not measurements even if there is no penetration.

Seems I can get a fairly accurate result by doing a closestPoint query from the center of each RB’s convex hull to the geometry of the other one, and then from there finding which of the two distances is smaller, and then doing a final closestPoint query from the point on the geometry of the first closest result back to the geometry of the other RB…and getting the distance between those two points. Here’s an illustration in case anyone would find this method useful:

Only problem is that the closestPoint query returns 0 when geometry is intersecting, meaning it doesn’t yield helpful results in the hulls are already intersecting…

Would calling PxGeometryQuery::sweep with a large inflation value and PxHitFlag::eMTD | PxHitFlag::eNORMAL | PxHitFlag::ePOSITION do what you want? You may need to provide a sweep direction and epsilon distance to avoid some validation checks complaining about illegal sweeps.

The sweep with MTD flag will return the MTD between the shapes if they are initially overlapping (that’s the direction + normal to define how to move the shapes to make them be disjoint/just touching). You should get an impact point as well. If you set an inflation that is relatively large, it should detect the closest point between the disjoint shapes (if they are disjoint), find that its below the inflation amount and return to you an MTD defining the direction between the closest points and a distance. What you will actually get is a distance. If it is negative, this distance defines how penetrated the shapes are. However, this distance will have factored in the inflation amount but, if you were to add the inflation amount to this, it should tell you how separated the objects are (if the distance + inflation is positive) or how much they actually overlapped (if the distance + inflation is still negative).

Thanks for that explanation…I’ll give it a shot!

So…I implemented what you described and I think I found a physx bug in the sweep process. When sweeping (specifically spheres) the MTD position returned seems to be wrong when inflation>0…it’s almost like all other actors besides the one I’m sweeping with get inflated, when the expectation would be that the sweep geometry is the only one that should be inflated. I got the same results when using box shapes, but not when using convex shapes. This image describes my results:

In the meantime, I implemented the sweep test as a broadphase cull and used the method described in my first post to get actual distance measurements and get roughly the same performance as if I was using the MTD sweep test alone (ie, it’s a lot faster).

I think this is more of a convention issue than a bug.

The convention for putting the impact point on the target object makes some sense from the perspective of a sweep because this method is written to sweep the sweep object against the target object and find the distance to move and impact point that it hits the target object at. If the shapes were initially disjoint, the impact point on either shape should coincide and it doesn’t matter which shape got inflated. In fact, in the implementation, neither shape gets inflated - it’s the Minkowski sum of the 2 shapes that’s inflated.

If you know that the impact point will always be on the surface of the inflated target object (not the sweep object), then you can use the normal, distance values and inflation amount to compute the equivalent point on the other shape if that’s what you want.

For example, if you would like to get the impact point on the surface of the uninflated shape B (the closest point), it should be possible to compute that from the information provided like this:

closestPointOnTarget = impactPointOnInflatedTarget - normal*(inflation)

If you want the closest point on the sweep shape, you can compute that from the closestPointOnTarget as below:

closestPointOnSweep = closestPointOnTarget + normal * distance

If you want the point on the surface of inflated A, which is what I think you expected from this function, you could also compute that. That’s likely to be something like this:

impactPointOnInflatedSweepObject = impactPointOnInflatedTarget + normal*(distance-inflation)

Please note that I didn’t try this and there’s a pretty good chance that the convention for the direction of the normal means that cases of “- normal * x” may need to be interchanged with “+ normal * x” and vice-versa to get the desired results. However, there should be enough information returned by this method for you to get the information you require without using your root-finding approach.

I guess the reason I see it as a bug is because the results are not consistent across geometry types.

For example, when I sweep against the ground plane, the impact point is returned on the plane. When I sweep against spheres/boxes, the impact point is returned on the sweep object. When I sweep against convex shapes, the impact point is returned on the hit object, etc.

So instead of being able to reverse the normal and calculate the proper point universally, I have to write a bunch of different cases to compensate for the inconsistent results. I guess that’s not a horrible alternative to doing the extra closestPoint checks, but it just feels a bit messy.

OK. The inconsistency sounds like something we should aim to improve. I’ll add a defect about this.