Use contact manifolds instead of single contacts for collisions #90
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Currently, each collision only uses one contact. When a box is on the ground, the contact point oscillates between the corners, which can often cause significant instability and positional drift.
This PR changes this behaviour by computing multiple contact points using contact manifolds. This allows all four corners of a cube to be in contact at the same time, which essentially eliminates drifting, closing #85.
Comparison
Before:
2023-07-19.21-10-34.mp4
After:
after.mp4
As you can see, the cubes now land in a much more stable way, drifting is almost nonexistent, and explosions or small jumps are significantly reduced.
Caveats and future work
Small jumps
Edit: Fixed this for convex colliders, but non-convex colliders are still buggy. Read my comment below this post.
Despite drifting being essentially removed and explosions being heavily reduced, there are still occasional jumps, which might be because the constraint only uses the initial penetration depths (from Parry) instead of computing them based on the current state, which would cause the applied correction to be too large.
This seems to be mitigated by manually computing the penetration depth based on contact points computed at the current state, just like the XPBD paper recommends:
However, this causes problems with trimesh colliders, so I didn't add it yet. This will have to be investigated later.
Non-convex colliders
These changes only fix convex-convex collisions, and non-convex colliders (like trimeshes) still have the old behaviour. Read my comment below this post.
Performance
As you might expect, using multiple contact points instead of one can be more expensive, but the difference seems to actually be quite small.
Parry supports reusing the previous contact manifold to speed up the computation, so it could even be faster than the old method if implemented correctly. I didn't implement this yet due to facing more problems, but it will have to be tried again, as it should give a significant performance boost.
API change
Collisions are no longer just singular contacts, so I added a
Contacts
struct for a collision between two entities. It contains the entities and aVec<ContactManifold>
, where each contact manifold contains the entities, a normal, and the contacts, which are represented asVec<Contact>
.This is quite a few added layers, so it would be nice to add simple methods to e.g. get all contacts as a flat structure or to compute the deepest contact.