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
6.72k stars 447 forks source link

Large incorrect CollideShapeResult::mPenetrationDepth from mesh-capsule collision #940

Closed dan5sch closed 8 months ago

dan5sch commented 8 months ago

While testing my integration of Jolt into a custom codebase (I'm using CharacterVirtual and static triangle-mesh geometry for player movement), I discovered that walking or jumping with air control into certain walls would cause the player to fly backwards by up to several meters. Example video:

https://github.com/jrouwe/JoltPhysics/assets/44180328/de1744b5-df51-42f0-8735-6ee29227eb03

After reading the CharacterVirtual implementation and with further testing, I discovered that on the frames where the character is being pushed backwards, CharacterVirtual::ContactCollector::AddHit is receiving a CollideShapeResult with a large mPenetrationDepth that corresponds to the magnitude the player is pushed backwards. On the affected frames, these penetration depths range from 0.15 to as large as 16.

For debugging, I implemented a headless test like HelloWorld that reproduces the scene geometry and movement seen in the video (walking into the corner and jumping), available in this repo. It prints the player's non-upward position and movement delta per frame. Output snippet here, highlighting the affected frame:

...
  pos.xy: (37.5428, 36.4352) delta.xy: (0, 0)
  pos.xy: (37.5428, 36.4352) delta.xy: (0, 0)
  pos.xy: (37.5428, 36.4352) delta.xy: (0, 0)
  pos.xy: (37.5428, 36.4352) delta.xy: (0, 0)
  pos.xy: (37.5428, 36.4352) delta.xy: (0, 0)
> pos.xy: (41.6086, 36.4352) delta.xy: (4.06578, 0)
  pos.xy: (41.6086, 36.4352) delta.xy: (0, 0)
  pos.xy: (41.5229, 36.4859) delta.xy: (-0.0857544, 0.050766)
  pos.xy: (41.4371, 36.5367) delta.xy: (-0.0857544, 0.050766)
  pos.xy: (41.3513, 36.5875) delta.xy: (-0.0857544, 0.050766)
  pos.xy: (41.2656, 36.6382) delta.xy: (-0.0857544, 0.050766)
...

Notes:

jrouwe commented 8 months ago

Thanks for the effort in making this repro! I can reproduce it locally but it is going to take some time to analyze this (these kinds of issues are very hard).

jrouwe commented 8 months ago

I managed to move your repro case to the Samples app so that I can debug it in MSVC (attaching it for future reference):

SimpleTest.zip

After a long debugging session it turned out to be a problem that I ran into before where inside the GJK algorithm a degenerate triangle was not detected as such and caused a wrong contact point. In this case it reported a penetration of 4 meter so the character got pushed out by 4 meters in 1 frame. Increasing the epsilon makes the problem go away (unfortunately I don't see a better way).

Could you try out #946 and tell me if this fixes all of your issues?

dan5sch commented 8 months ago

it turned out to be a problem that I ran into before where inside the GJK algorithm a degenerate triangle was not detected as such

To be clear, do you mean that the meshes in the repro were hitting what can be described as a degenerate case in the GJK algorithm, or that the meshes literally contain degenerate triangles? Unless I've made a silly mistake, the latter shouldn't be true.

Regardless, I tested #946 in the repro and in my actual application at all the known affected locations in the scene, and the high penetration / character-push issue no longer occurs. Thanks for digging into this!

EDIT: I don't know if you prefer reporters to close issues, but that's the button I clicked.

jrouwe commented 8 months ago

or that the meshes literally contain degenerate triangles

No, your mesh didn't contain any degenerate triangles that I encountered. The problem is that GJK built an internal representation of the overlap between the triangle and the capsule that consisted of a degenerate triangle.

Thanks for testing!