Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

move_and_slide collides with edges between separate StaticBody3D #952

Open
Peter229 opened this issue Aug 21, 2024 · 14 comments
Open

move_and_slide collides with edges between separate StaticBody3D #952

Peter229 opened this issue Aug 21, 2024 · 14 comments
Labels
needs triage Something that needs investigation

Comments

@Peter229
Copy link

Tested using a capsule collision shape when running along a wall/anything with two or more static bodies if they are perfectly aligned you will get stuck or hitch where they align.

This is very obvious is you create a staircase like this and run along side it while running into it
image

The normal from get_last_slide_collision() is incorrect, assuming the rest of the collision information is incorrect

This does not happen with the default godot physics engine (Test in Godot 4.3 and Jolt 0.13.0)

@github-actions github-actions bot added the needs triage Something that needs investigation label Aug 21, 2024
@mihe
Copy link
Contributor

mihe commented Aug 21, 2024

Would you mind sharing that scene/project?

@Peter229
Copy link
Author

joltissueexampleproject.zip
Sure here you go, arrow keys to move, hold up arrow and run into the wall and you should see the issue.
I tend to try and go for 45 degrees running at the wall

Had to remove the addons folder as it made the file to big so you will have to add jolt yourself

@mihe

This comment was marked as resolved.

@Peter229
Copy link
Author

Godot.Engine.2024.08.22.-.11.02.57.04.DVR.-.Trim.mp4

Heres a video of me getting in in the test project I sent, it is way less consistent than in my main project
Here is also a video from my main project where it looks like it is detecting collision on edges:

Godot.Engine.2024.08.22.-.11.00.50.03.DVR.-.Trim.mp4

@mrezai
Copy link

mrezai commented Aug 22, 2024

I tested the shared project, by disabling physics/jolt_3d/collisions/use_shape_margins in project settings, sliding along the wall is much smoother.

@Peter229
Copy link
Author

Oh cool, yeah I just tried that and it is much better, especially sliding along the staircase

@mihe
Copy link
Contributor

mihe commented Aug 22, 2024

Yes, thank you for providing the project, I was able to reproduce the issue. It seems you beat me to the punch with figuring out part of the solution, but there's a bit of a story to tell here.

With the way you've set things up in that particular project, where you have your wall segments be separate StaticBody3D, I would indeed expect to run into issues like what you're seeing, where you collide with the edges of the separate bodies. This is typically referred to as "ghost collisions". You'll find a nicely succinct explanation of the problem in this blog post.

This is something you'll find happens with Godot Physics as well, although typically more with shapes like ConcavePolygonShape3D (aka the triangle mesh shape) where you'll find yourself colliding with the internal edges between the individual triangles. For whatever reason the collision detection algorithm used by Godot Physics for more primitive shapes like these is more resilient against this problem, so you won't see it much (if at all) in your particular setup.

This has already been addressed to some degree in this extension with the project setting physics/jolt_3d/collisions/use_enhanced_internal_edge_removal, which is a feature in Jolt that's meant to address this problem. The problem is that this only works on a per-body basis (hence "internal") so you won't see any benefit at all if you divide your wall into separate StaticBody3D like this. What you can do instead is to divide it into separate CollisionShape3D instead and use a single (or at least fewer) StaticBody3D.

What caught me by surprise a little bit is that your acceleration of the player (using move_toward) is playing some part in all of this. If you disable the acceleration and just use an instant on/off velocity you'll find that much of this problem goes away. I'm guessing it's because any momentary stop of the player's velocity can't immediately recover the next tick like you can without the acceleration, so perhaps it's just making the problem more apparent.

Another thing that caught me by surprise is the effect of the shape margins on this problem, specifically when using a single StaticBody3D. I was of the belief that they would be disregarded as part of this "Enhanced Internal Edge Removal" algorithm, and that the shapes would effectively be merged into one, but that doesn't seem to be the case.

The shape margins (called "convex radius" in Jolt) effectively round the edges of any convex shapes that have sharp edges, like BoxShape3D, CylinderShape3D and ConvexPolygonShape3D. This is a rough illustration of what happens:

image

This is a fairly common technique used as part of the collision detection algorithm that Jolt uses, which (from what I understand) serves as both a performance optimization and helps with accuracy as well.

You can indeed disable these margins globally through the physics/jolt_3d/collisions/use_shape_margins project setting, but you will then sacrifice on the above mentioned performance/accuracy everywhere. What you can do instead is to go into the BoxShape3D of your wall shape and set the margin for that shape specifically to 0, like so:

image

Anyway, I messed around with your project a bit to illustrate all of this: wall-segments.zip

If you click on the Root node in the scene and expand its Settings property you'll find some settings there that you can mess with to toggle the various parts of this. As you've found out already, just disabling shape margins altogether seems to have the biggest impact. Disabling the player acceleration similarly helps quite a bit, but presumably just masks the problem. Toggling the setup of the wall itself (bodies vs shapes) doesn't seem to have much of an impact at all, which again is surprising to me.

@mihe
Copy link
Contributor

mihe commented Aug 22, 2024

Another thing that caught me by surprise is the effect of the shape margins on this problem, specifically when using a single StaticBody3D. I was of the belief that they would be disregarded as part of this "Enhanced Internal Edge Removal" algorithm, and that the shapes would effectively be merged into one, but that doesn't seem to be the case.

@jrouwe I'd be curious to hear what your take is on this. I vaguely recall you mentioning something about mEnhancedInternalEdgeRemoval not doing well with rounded corners of some sort, but I can't seem to find it.

@mihe mihe changed the title Incorrect collision detection when using move_and_slide() move_and_slide collides with edges between separate StaticBody3D Aug 22, 2024
@Peter229
Copy link
Author

Thanks very much for the in depth analysis!

I understand how the acceleration code will be making it more obvious as move_and_slide also modifies the velocity which is the intended behaviour I want. I don't know why the final velocity after move_and_slide would be zero or so close to zero however as that should only really happen when colliding straight on with a wall.

I am surprised that the margins create shapes like you have drawn as I thought they would create an overlap like this which would result in a smooth collision?
image

The only thing I could modify in the test project that would make the collision smooth that I found myself was making all the walls overlap a small amount which would fix what you are demonstrating in the margins diagram.

Thanks again for help!

@mihe
Copy link
Contributor

mihe commented Aug 22, 2024

I don't know why the final velocity after move_and_slide would be zero or so close to zero however as that should only really happen when colliding straight on with a wall.

The significant loss of velocity is surprising, but I guess the slightly rotated contact normal results in it more or less wanting to slide backwards, which would translate into (nearly) stopping instead.

I am surprised that the margins create shapes like you have drawn as I thought they would create an overlap like this which would result in a smooth collision?

That's how other physics engines (like Bullet) typically implements them, from what I understand, which obviously makes the shape bigger than expected, which can be frustrating in other ways. Jolt does it a bit differently, where it first shrinks the shape by the margin and then "inflates" it again. You can see it mentioned here in its documentation.

The only thing I could modify in the test project that would make the collision smooth that I found myself was making all the walls overlap a small amount

Right, yeah, that's a good point. I suppose that's a fairly easy workaround as well.

@Peter229
Copy link
Author

I guess I just expected it to look more like walking along a bumpy wall

Ah I see how that works, yeah upsides and downside to both

Unfortunately the tools I am using to whitebox out all my levels makes this quite hard, luckily the margin option is only a one line change that only effects whitebox collision only

@mihe
Copy link
Contributor

mihe commented Aug 22, 2024

I will also say that setting the margin to 0 has been shown to produce some problematic collisions when you're dealing with something like a BoxShape3D/CylinderShape3D character that itself is also using a margin of 0. Obviously you're using a CapsuleShape3D though, which I believe should help you avoid this problem, but maybe @jrouwe has something to say about that.

It might be that it's instead better to set the margin of your whiteboxing to as small of a number as you can tolerate, rather than setting it to 0.

@jrouwe
Copy link
Contributor

jrouwe commented Aug 23, 2024

@jrouwe I'd be curious to hear what your take is on this. I vaguely recall you mentioning something about mEnhancedInternalEdgeRemoval not doing well with rounded corners of some sort, but I can't seem to find it.

This function uses Shape::GetSupportingFace which gives the original faces without convex radius, so in principle it shouldn't matter what the convex radius of the box is. (If I haven't made any mistakes that is)

W.r.t. to margin, I would indeed not set it to zero, but you can lower the default.

@mihe
Copy link
Contributor

mihe commented Aug 23, 2024

This function uses Shape::GetSupportingFace which gives the original faces without convex radius, so in principle it shouldn't matter what the convex radius of the box is. (If I haven't made any mistakes that is)

It sounds like there might be something weird going on then. I'll try and debug it and see if I can figure out what's happening exactly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs triage Something that needs investigation
Projects
None yet
Development

No branches or pull requests

4 participants