rapier icon indicating copy to clipboard operation
rapier copied to clipboard

Multiple gravity sources

Open FlyingRatBull opened this issue 4 years ago • 4 comments

Games with multiple sources of gravity must implement it on their on at the moment. A fitting implementation would safe a lot of time and also speed up those games up.

However IMO implementation of this should have to encompass a refactor of the gravity system into separate possible implementations a user can chose from:

  1. None (No gravity) This could speed up games without gravity a little
  2. Simple (single source) Current gravity implementation
  3. Nearest (multiple sources, affected by strongest) Objects get influenced by only the strongest source (See below)
  4. In the future: N Body (most accurate, slowest)

Case 1: None

This would just be an empty implementation, hence slightly improving performance.

Case 2: Simple

This is the current implementation - so only refactoring would be needed to fit the new structure.

Case 3: Nearest

This could be implemented as a decorator before Case 2, to chose the strongest gravity source for the current object before applying it.

Performance

With appropriate structures in place, this implementation could carry an CPU impact as low as O(1) with an O(n) - O(n³) impact on memory (n = number of sources).

Potential implementation

  • Upon gravity source definition/change:
    • Build a 3D1 XYZ-array (CPU: O(n*m); Mem: O(m) with n = number of source and m = total size of array)
    • The size of each dimension could be provided by the user (lower -> less memory usage; higher -> more accurate determination of strongest source)
    • For each point in the array, calculate and store the index of the strongest gravity source for this point in space
  • When calculating gravity:
    • Look up appropriate gravity source in array (CPU: O(1))
    • Apply same gravity calculation as with Case 2

The goal would be, to keep the size of the array as small as possible (to reduce cache impact) while providing an accurate enough result.

1: If all gravity sources are on the same plane in one/two dimensions a 2D/1D array could be uses to reduce memory impact and improve cache locality.

Case 4

This could be a future feature if the need for it arises - the new structure would support it already though.

FlyingRatBull avatar May 11 '21 15:05 FlyingRatBull

Interesting, but I assume most people don't want to pay the price of something they do not need. in particular because this looks like a very specific solution to a specific sort of game.

the fact that it is so easy to simulate custom gravity using forces manually makes me wonder how much sense it makes to put this into the core of rapier. this could be easily layered on top, right?

extrawurst avatar May 11 '21 16:05 extrawurst

I agree with you on not letting the users pay a price for something they don't need. But if done right, the they wont and the price to be payed will even go down for people which don't use gravity.

I also agree with the aspect of the core of rapier, but current custom implementations would be slower than an internal one. Additionally rapier continuously calculates gravity which is not used/needed in that case. A good middle ground would be to create a trait for a gravity system and only provide the None/Simple cases from above. This way the impact on the core is minimal while also providing the ability to replace it with more complex systems.

By the looks of the code I can only guess as to how big the performance impact of doing gravity calculations outside of the core would be, but with a lot of code hinting to particular orders of steps I think the trait variant could also prevent a few issues with said custom implementations.

FlyingRatBull avatar May 11 '21 16:05 FlyingRatBull

I implemented a version with gravity calculation extracted into a trait: Diff

Are there any benchmarks which can actually be run to compare results against and get the impact this has?

I'm happy for every pointer/optimization/comment on the code :slightly_smiling_face:

FlyingRatBull avatar May 14 '21 17:05 FlyingRatBull

As someone who needs more complex gravity than rapier provides, I'd prefer that rapier's interface not be complicated with these extensions. It is very easy to apply your own gravity forces, computed in whatever manner best suits your application.

Ralith avatar Jul 18 '21 01:07 Ralith

My use case: My game has no gravity, but I made the player object have magnetic parts that cling to the nearest metal surface (with simplified physics of only considering nearest metal object, at least for now).

I wanted to offer this here, if others like me stumble on this issue:

This is pretty easy to DIY for small scale projects.

My apply_magnetism Bevy function is about 50 lines and loops through every magnet, for each uses rapier_context.project_point to find the nearest metallic point, with a QueryFilter picking only colliders marked as metallic. I compute the force and update ExternalForce for the entity that contained the magnet.

It's pretty simple. I haven't worried about performance yet, and doubt it'll ever matter for my project, but I wonder how many objects you need before precomputing a lookup table is worth it. (Also, technically I could have moving metal parts! No need for those at this time.)

(The only part I'm really worried about is how Bevy only lets an Entity have one ExternalForce, and how ugly that might get if I need to implement multiple forces later. Might seem to sum all forces in the same handler, instead of them being neatly modular, or make MagneticForce etc that then get summed into one ExternalForce, more wastefully.)

tv42 avatar Nov 17 '22 20:11 tv42

Closing this as not planned. Users can easily implement custom gravities on top of Rapier. Thank you @tv42 for sharing your solution!

sebcrozet avatar Jan 01 '23 17:01 sebcrozet