jrouwe / JoltPhysics

A multi core friendly rigid body physics and collision detection library. Written in C++. Suitable for games and VR applications. Used by Horizon Forbidden West.
MIT License
6k stars 374 forks source link

Kinematic `BoxShape` sensor versus `MeshShape` fails to report contacts #1138

Closed mihe closed 1 month ago

mihe commented 1 month ago

Related to godot-jolt/godot-jolt#897.

There's a scene with a kinematic BoxShape sensor (using mCollideKinematicVsNonDynamic) that's moving around and supposed to be overlapping with a cylinder-shapes MeshShape, but the overlap between them (as reported by the contact listener) keeps flipping depending on the location of the sensor, even though it looks like it should always be reported.

Here you can see it in action (the project of which you'll find here):

https://github.com/jrouwe/JoltPhysics/assets/4884246/6f3e553b-a1ee-46b7-aa14-b5668e8f2d2f

I don't see any real pattern as to when it decides to not report the contact.

Here are snapshots of the scene shown above, with the failure case and successful case respectively:

As far as I can tell the issue is that every single triangle collision results in a back-face collision, which gets discarded/ignored. Enabling back-face collision using a decorator shape that overrides mBackFaceMode results in everything working as expected.

jrouwe commented 1 month ago

Hmmm, I think this is actually expected behavior:

image

The definition of 'back facing' is that the center of the box is behind the face. In this top view of snapshot_bad.bin you can see that the center of the box is behind all faces. The reason for this choice is that if you were to treat all of these as contact points then you would get contact normals pointing in all directions and the body would effectively be stuck. MeshShapes are not great sensors as they don't have an inside and an outside, if the shape would have been a CylinderShape or a ConvexHullShape then it would have worked.

As a solution, sensors could perhaps always do a double sided check, but the problem is that you can make an object a sensor in the ContactListener callback, which is after the collision detection has taken place. Also it would be quite a behavioral change. Basically, I don't have a good suggestion.

mihe commented 1 month ago

As a solution, sensors could perhaps always do a double sided check, but the problem is that you can make an object a sensor in the ContactListener callback, which is after the collision detection has taken place.

I feel bad for even asking this, but could this perhaps be made into a per-body flag instead then? It wouldn't necessarily have to be sensor-specific. Maybe something like AlwaysCollideWithBackFaces?

jrouwe commented 1 month ago

I feel bad for even asking this, but could this perhaps be made into a per-body flag instead then? It wouldn't necessarily have to be sensor-specific. Maybe something like AlwaysCollideWithBackFaces?

Is this not what JoltCustomDoubleSidedShape does?

mihe commented 1 month ago

Oh right! I could of course just wrap every sensor in that decorator shape. For some reason I thought that wouldn't work on compound shapes, but there's no reason why it wouldn't.

mihe commented 1 month ago

Alright, well, that of course worked like a charm.

I do think this is a little bit strange still, and arguably not the behavior one would expect, but I can see the predicament you mentioned with regards to ContactListener. It's also a fairly specific issue as well I guess, since it pretty much requires using mCollideKinematicVsNonDynamic to begin with.

Anyway, I'll go ahead and close this. Thank you for the help yet again!