NVIDIAGameWorks / PhysX-3.4

NVIDIA PhysX SDK 3.4
https://www.nvidia.com/
2.34k stars 275 forks source link

Issue with merging multiple contacts into one (patch). #114

Closed danielkrakowiak closed 4 years ago

danielkrakowiak commented 4 years ago

Hey, I have a height-field terrain and a convex road that emerges from below the terrain. Then I have a sphere that rolls on a heightfield towards the road. When it rolls on HF it generates a nice contact with near zero separation. Then as it rolls over the road, it detects another collision with the convex with 6 cm separation. Both of those collisions have the same normal.

However, instead of giving me two contacts (with 0 and 6 cm separation), PhysX seems to merge the two contacts into one (with 6 cm separation) which results in no force applied. Then a couple frames later, when separation with convex gets to 0, the force quickly grows and pushes the sphere up - flying. I expect the sphere to roll smoothly in that transition area between the terrain and the road.

Can I selectively disable merging contacts into patches? Or disable it in PhysX source code? Can I disable merging via onContactModify maybe? And why is PhysX using 6 cm separation instead of 0 when merging those contacts? That doesn't make sense to me...

I'm using a non PCM version of contact detection.

kstorey-nvidia commented 4 years ago

Hi

Would you be able to provide a PVD capture of the issue so we can try to make a repro locally?

There is some code merging contacts between the same actor pairs (and static actors are considered the same actor) but it should follow a scheme of choosing the deepest (most penetrated) contacts that form the largest surface area.

There are some work arounds you could try, but I'd really appreciate a repro so we can fix this issue.

Potential workaround:

(1) If you are not going to rebuild code, you could just make your road/terrain as a kinematic rigid body (PxRigidBodyFlag::eKINEMATIC). PhysX won't merge contacts between different kinematic actors (because they can each have different underlying velocities). Overall performance would be the same as if you disabled contact merging with static bodies. (2) You could disable merging of contacts. There's a define to do this in PhysX 4 but, for PhysX 3.4, you would need to hack this clause around line 1279 in DyDynamics.cpp:

if(startDesc->bodyA != desc.bodyA || startDesc->bodyB != desc.bodyB || startDesc->linkIndexA != PxSolverConstraintDesc::NO_LINK || startDesc->linkIndexB != PxSolverConstraintDesc::NO_LINK || contactCount + output.nbContacts > Gu::ContactBuffer::MAX_CONTACTS || manager->isChangeable() )

basically you could just replace this with a if(1) and it will not merge contact patches. However, be aware that doing this can really negatively impact performance if you have lots of multi-shape actors.

danielkrakowiak commented 4 years ago

Thank you for the great answer! I will experiment with those workarounds and I will try to create a clean repro in PVD.

Do you think it would be easy to add disabling merging contacts for selected actors or for selected shape types? Or maybe from onContactModify callback for selected contacts? I only care about all those contacts for shapes that simulate wheels (and I have a separate torus shape for that too). However when I change PhysX internal structs I typically experience crashes that seem hard to fix. Any hints maybe?

kstorey-nvidia commented 4 years ago

If you use contact modification, then the contact patches won't be merged. That is what this clause in that if statement means:

manager->isChangeable().

danielkrakowiak commented 4 years ago

Ok... I do modify all those contacts. I will look closer then to make sure that this is not a bug in my contact reporting. However, by reading PhysX code I got the impression that modified contacts are re-merged into patches after they were modified. But apparently I understood it wrong.

danielkrakowiak commented 4 years ago

I looked closer into my contact reporting code. I made an assumption that a single body gets only one contact reporting callback which is not true. So PhysX works correctly in the mentioned scenario and I'm sorry for confusion. And thank you very much for your answers which helped me greatly in understanding the problem.