NVIDIAGameWorks / PhysX

NVIDIA PhysX SDK
Other
3.19k stars 808 forks source link

trA and trB undefined in PxsCCDPair::sweepAdvanceToToi and gjkRaycastPenetration returns that closestA is origin #507

Closed pkusilence closed 2 years ago

pkusilence commented 2 years ago

When CCD_ANGULAR_IMPULSE is set to 1, the solver needs localPoint to calculate impulse.

I tried methods below but no one could give a satisfying result:

  1. PxTransform trA = atom0->getPose();

  2. PxReal clampedToi = PxClamp(minToi, 0.0f, 1.0f); trA.p = clampedToi ccds0->mCurrentTransform.p + (1.0f - clampedToi) ccds0->mPrevTransform.p; trA.q = ccds0->mCurrentTransform.q; PxTransform shape0ToBody = atom0->getCore().getBody2Actor().getInverse() ccds0->mShapeCore->transform; trA = trA shape0ToBody.getInverse();

And there are two test: (moving towards X+) a. a box collides with another one face-by-face. b. a box collides with a slope (20deg).

The No.1 method turns out that the localpoint is not stable enough for every test a. The No.2 method seems work well for test a. However for test b, the No.2 method sometimes gives a totally wrong direction of localpoint: For example, mCurrentTransform.p.x =439, mPrevTransform.p=358, mTOI = 0.88, but the contact point has a mMinToiPoint.x = 358. Follow the method 2 and give a local point x = -64, which is not possible for a object moving towards X+. In this case, the mMinToiPoint is exactlly equal to ccds0->mPrevTransform.p, which is strange. And It is found that gjkRaycastPenetration returns origin as closestA.

So how should I fix these problems?

pkusilence commented 2 years ago

The latest problem occurs in GuGJKRaycast.h, Line 199 writes getClosestPoint(Q, A, B, closestP, closA, closB, size);

but when size == 4, this function does nothing, and closA remains zero.

kstorey-nvidia commented 2 years ago

If GJK raycast gets into that code with a tetrahedra (size 4), that means that the origin is already inside the tetrahedra. Unfortunately, there is no meaningful information that can be extracted in that state from GJK because it means that the shapes are overlapping. To get meaningful information in this state, we would need to run the EPA algorithm to compute the penetration depth and normal for a pair of overlapping convex shapes.

pkusilence commented 2 years ago

Should gjkRaycast return false for size 4 case ? It is still confusing that it also gives a valid toi (lambda) belongs to (0, 1)

kstorey-nvidia commented 2 years ago

It needs to return true because the shapes are touching, otherwise initially-overlapping shapes would be ignored by CCD or the scene query sweep code. As initial overlaps occur relatively frequently, this would probably cause bugs if we treated this case as a non-hit. It would force the user to do an overlap check to find initial overlaps, then also run the sweep to find the TOI.

The GJK algorithm can only tell you the distance between two shapes and the closest points on the surface of the separated shapes. If the shapes are initially overlapping, it can only determine is that the distance is 0, but it isn't able to calculate the penetration depths. Given a starting point of two disjoint shapes, the algorithm should reliably give you the closest points on the shapes at the TOI.

When there are initial overlaps, there isn't a lot the CCD system can do because we are already past the point at which the collision begins and it can't reverse time. All the CCD system can do at this point is apply forces to push the shapes apart, allow the shape to step forwards a small, safe amount of time and hope that the discrete simulation is able to resolve the penetrations next frame. Once the shapes are separating, the CCD system should ignore the collision.

pkusilence commented 2 years ago

Thanks for reply. The good news is that after setting restOffset to 1 cm, the size 4 case does not appear again.

I found that the inflation parameter in CCD for geometries other than capsule / sphere is always zero. So all these problems are caused by numerical errors.