godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.13k stars 93 forks source link

Implement support for using different physics update rates at the same time #439

Open 2plus2makes5 opened 4 years ago

2plus2makes5 commented 4 years ago

Describe the project you are working on: 2.5d metroidvania

Describe the problem or limitation you are having in your project: The map is big with lots of rooms having lots of physics bodies and areas detecting collisions, emitting signals and other things so it's really heavy, obviously i'm doing optimizations but i think it would make a lot of sense(for me at least) to have different physics update rates for each node. My idea is that the physics related to things that need the maximum precision like collisions between characters would be updated every frame(60fps if in the settings we chose 60fps), while all the other things that do not require the maximum precision would be updated less frequently(30fps for example) .

Describe how this feature / enhancement will help you overcome this problem or limitation: Areas and bodies that do secondary things would have a lower impact on the game improving performance while character collisions and signals would retain the necessary precision.

Show a mock up screenshots/video or a flow diagram explaining how your proposal will work: I thought of a simple numeric field where we specify after how many physics frames the node skips a frame, 0 or negative would be the default vale meaning that the node would never skip a frame(60fps if in the settings we chose 60fps), 1 would mean skipping 1 frame after 1 one frame(30fps), 2 would mean skipping a frame after 2 frame(40fps) and so on.

Describe implementation detail for your proposal (in code), if possible: I don't know the core implementation of the physics, but i think that when a counter counting how many frames passed from the last skip reaches the chosen value the node would skip the physics frame code and the counter restarts.

If this enhancement will not be used often, can it be worked around with a few lines of script?: I guess we could disable the physics process and/or edit physics layers and masks from code, but doing it for more nodes would be a hassle.

Is there a reason why this should be core and not an add-on in the asset library?: I may be wrong but this seems to me like something to do at core level, i'm not against an add-on though.

Calinou commented 4 years ago

See also https://github.com/godotengine/godot-proposals/issues/236 and https://github.com/godotengine/godot/issues/24769.

2plus2makes5 commented 4 years ago

I'm in for an option for semi-fixed timesteps, but i think that it's the exact opposite of what i'm suggesting.

My proposal is just to add the ability to impose to some nodes to automatically skip a physics frame once in a while(hence running at a lower fps) depending on a value we set, for example if the global physics framerate is 60fps then default framerate for every node would be 60fps, but we could decide to make some nodes update at 30fps, others at 40fps and so on.

In my mind the implementation of this idea would change nothing to the end users, they would keep on using only the global physics delta that remains fixed and the same for every node, even those who must skip a frame once in a while, all the users would need to do is to set a value.

lawnjelly commented 4 years ago

I used this method in my frogger game, I ran the main player at 60 tps and the AI characters at 10 tps. However, what makes that situation different is that I wasn't using physics (or at least, not godot physics or bullet).

There are 2 aspects here:

  1. Enabling some of your objects to update every 2nd / 3rd physics tick (_physics_process)
  2. Ticking the physics engine in this way

You can already do (1) manually, by calling your own custom TickUpdate function yourself at the intervals you desire. Just have a central node that handles _physics_process, and use it to call your own manual functions in other parts of the game at intervals. It might be nice to have some in built support for this, but it's not very tricky to implement.

The problem with (2), is using a third party physics engine (like bullet), we are basically stuck with the feature set that bullet has, we are exposing the feature set. If there is no support for this feature in bullet, it becomes very difficult to even attempt to implement. I know next to nothing about bullet but I wouldn't be at all surprised if it is not supported, because stepping objects at different rates within the same simulation can potentially be quite problematic in terms of resolving collisions.

You could alternatively have different physics spaces for objects at different tick rates, but again the problem comes on the boundary. What do you do when an object from one space has to interact with an object in another? It is not straightforward. However it could be possible to some extent if someone had the interest to experiment in this area. There are a lot of edge cases though.

It may be better to push the bullet project to have some kind of support for this upstream, if it doesn't already have it, and then we would be in a position to expose it.

girng commented 4 years ago

My proposal is just to add the ability to impose to some nodes to automatically skip a physics frame once in a while(hence running at a lower fps) depending on a value we set, for example if the global physics framerate is 60fps then default framerate for every node would be 60fps, but we could decide to make some nodes update at 30fps, others at 40fps and so on.

Can't this be done with timers, or a counter being increased by delta, and executing after xxx time, then reset it to 0? Then, you can just put that code you want executed in that if block

2plus2makes5 commented 4 years ago

Sorry if i reply more than a month later but for more than 2 weeks i was without internet and i totally forgot about this.

This mechanism can definitively be implement by code and i admit that didn't think about the problem of adding this to a third party physics engine like Bullet, but if it would be possible to have this directly in Godot and usable with the simple change of a setting's value it would be more simple, flexible, widespread, without all the possible errors or inconsistencies that could come by implementing this by ourselves for various different classes and more people would use it.

About what would happen between entities updated with different update frequencies, it would happen absolutely nothing, think of a value that has to pass from 0 to 40:

normal frequency: 0->10->20->30->40 halved frequency: 0------>20------->40

when the one with normal frequency is at 10 the one with halved frequency is still at 0, when the first is at 20 the second is at 20 too and so on.

Obviously this generate collision problems if not used correctly, but this mechanism should be used for things that are secondary, static or far from the player, think of those games that animate distant characters at a low framerate and closer one at normal framerate, this would be something similar but on the physics level(and probably implemented in some way in those games).

AndreaCatania commented 4 years ago

You may be interested in this: https://github.com/godotengine/godot-proposals/issues/671

Giwayume commented 4 years ago

I had this same idea, mainly because I've seen it implemented in AAA games.

For example, in Bloodborne, enemies that are far away from the player clearly run their animations at a discounted frame-rate (maybe 15fps) compared to enemies nearby (30fps+) in order to save on computation power.

Would be nice if the engine could have some sort of layer concept for different frame-rates, like a 30 fps physics layer would pass a 2x higher delta value into _physics_process than a 60fps physics layer.

addmix commented 5 months ago

This feature seems to me as a necessity for XR, allowing hands to update at a high rate, and normal game physics at a normal update rate, especially with the lack of multithreading in scene tree functions.

Calinou commented 5 months ago

See the above comment:

The problem with (2), is using a third party physics engine (like bullet), we are basically stuck with the feature set that bullet has, we are exposing the feature set. If there is no support for this feature in bullet, it becomes very difficult to even attempt to implement. I know next to nothing about bullet but I wouldn't be at all surprised if it is not supported, because stepping objects at different rates within the same simulation can potentially be quite problematic in terms of resolving collisions.

I don't know if Jolt in particular has any support for using multiple physics update rates in the same project.

aloiscochard commented 4 months ago

@Calinou I have a project where I had to do that, because I have a fluid simulation and the "normal simulation", I want the fluid simulation to run at a lower rate.

I could do that with Jolt by starting two different instances of the engine, it is working well and totally thread-safe.

Calinou commented 4 months ago

I could do that with Jolt by starting two different instances of the engine, it is working well and totally thread-safe.

This essentially means having to run two instances of the physics engine at once, which likely comes with its share of issues and inefficiencies.