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

Optimize Convex Collision #66294

Merged
merged 1 commit into from
Oct 13, 2022

Conversation

reduz
Copy link
Member

@reduz reduz commented Sep 23, 2022

Implements the Gauss Mapping optimization to SAT convex collision test.

  • Described here by Dirk Gregorius.
  • Requires adding of face information to edges in MeshData
  • Took the chance to convert MeshData to LocalVector for performance.

Next Steps:

NOTE: This is a draft, it has not been tested yet.

@reduz reduz requested review from a team as code owners September 23, 2022 10:41

for (uint32_t i = 0; i < ch.edges.size(); i++) {
edge_faces[i] = -1;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was going to say we had a fill() method for this, but I see it was added to 3.x in #60426 but not yet added to 4.x. Might be worth adding this at the same time as it is fairly common? 🤔

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#60426 is a backport of a master PR so it should be in master too?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#60426 is a backport of a master PR so it should be in master too?

It wasn't included in the original as far as I can see. I don't think it is present in LocalVector in 4.x?

@KoBeWi KoBeWi added this to the 4.0 milestone Sep 23, 2022
@reduz reduz force-pushed the optimize-convex-collision branch 2 times, most recently from 92e87d3 to 2d9046f Compare September 23, 2022 22:28
@peastman
Copy link
Contributor

This implementation still involves nested loops over edge_count_A and edge_count_B, which means the cost is still at least O(n^2) in the number of edges. It reduces the cost compared to the old implementation by avoiding calls to test_axis(), but even in the best case there's still a lot of work being done in the inner loop (four calls to xform(), two to normalized(), four to dot(), and assorted other miscellaneous operations). For large meshes, I believe this will still be much too slow to be usable.

Have you tried benchmarking it and comparing to the implementation in #63702? For medium to large meshes, I believe that one will be faster by orders of magnitude. Its speed is essentially independent of the size of the meshes, aside from the dependence that comes from the calls to test_axis().

@reduz
Copy link
Member Author

reduz commented Sep 25, 2022

@peastman My issue with #63702, as I mentioned before, is not performance related but precision related. For throwing stuff into a pile of bodies these sort of approximation algorithms work fine, but for game related collision where you need extremely precise collision responses, they can be troublesome and fail in specific situations and corner cases. This has been my experience back in the day with GJKEpa and MPR, and its the current experience with Bullet in Godot 3.x.

This is IMO the main reason why, besides Godot, engines like Unity or Unreal, and production physics engines like PhysX or Havok (or the hundreds of ODE based simulation engines) also use SAT based collision algorithms. Again, it's not the performance, its that approximation based algorithms have unexpected corner cases. I still intend, if the amount of vertices beyond a certain threshold, to fallback into GJKEpa (which is already implemented and works) because I assume at that point the user is not looking for precise collision, but it should just not be the default even if its faster.

@reduz
Copy link
Member Author

reduz commented Sep 25, 2022

@peastman Let me explain the problem in a bit more detail. Its mostly about sizes and precision. If you have a box and a sphere of the same size and they collide, its probably be ok with an approximation. If you want the box to fall over a very large sphere (say a planetoid in a game), then the lack of precision will be a lot more noticeable and the collision will jitter. This is the main issue with iterative solvers that work in minkowski sum space.

Bullet sort of makes up this in large part because of enforced margins, because GJK is a lot more precise (and faster) than EPA or MPR.

@peastman
Copy link
Contributor

If you want the box to fall over a very large sphere (say a planetoid in a game), then the lack of precision will be a lot more noticeable and the collision will jitter.

That's a great suggestion for test. Here's a video showing how MPR handles it. (I had to add .txt to the name so github would let me upload it.) A cube of size 1 (represented as a mesh with 8 vertices) strikes and rolls down a sphere of radius 100 (represented as a mesh with 4986 vertices). As you can see, the collision handling is flawless, no jittering at all.

Remember that MPR is not an approximation. If you converge it to machine precision (which is very cheap, just a few extra iterations), the result is exact.

movie.m4v.txt

@reduz
Copy link
Member Author

reduz commented Sep 25, 2022

@peastman I think we are talking about different things. I already stated that with convex polyhedra the result is exact, but for this case we already have EPA implemented and I prefer to use this than MPR as optimization as it makes no sense to support both.

The problem is when you use MPR/EPA against continous surfaces (spheres, capsules), or convex polyhedra with margin (which we use for depentration in character controllers). In that case, the result is not always exact.

@peastman
Copy link
Contributor

Ok, it's your call! Just remember you have that code sitting around, in case you get tired of dealing with all the problems of GJK-EPA in the future. :)

The problem is when you use MPR/EPA against continous surfaces (spheres, capsules), or convex polyhedra with margin (which we use for depentration in character controllers). In that case, the result is not always exact.

EPA is an approximation, but I believe MPR is still exact in that case (assuming you converge to machine precision).

core/math/convex_hull.cpp Outdated Show resolved Hide resolved
core/math/convex_hull.cpp Outdated Show resolved Hide resolved
servers/physics_3d/godot_collision_solver_3d_sat.cpp Outdated Show resolved Hide resolved
Copy link
Contributor

@fabriceci fabriceci left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested with https://github.com/fabriceci/Godot-Physics-Tests.

No regression found and noticeable performance improvement:

Screenshot 2022-10-12 at 17 26 47

Implements the Gauss Mapping optimization to SAT convex collision test.

* Described [here](https://ubm-twvideo01.s3.amazonaws.com/o1/vault/gdc2013/slides/822403Gregorius_Dirk_TheSeparatingAxisTest.pdf) by Dirk Gregorius.
* Requires adding of face information to edges in MeshData
* Took the chance to convert MeshData to LocalVector for performance.
@reduz reduz force-pushed the optimize-convex-collision branch from 2d9046f to 71d2e38 Compare October 13, 2022 17:08
@akien-mga akien-mga merged commit 46a1b92 into godotengine:master Oct 13, 2022
@akien-mga
Copy link
Member

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants