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

[WIP] Add semi-fixed timestep and physics time stretching for global timescale #30798

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

lawnjelly
Copy link
Member

@lawnjelly lawnjelly commented Jul 24, 2019

Fixes #24769
Fixes #24334

The main change in this PR is adding the option in project settings->physics to choose between the old fixed timestep and a new path for semi-fixed timestep. With semi-fixed timestep users can either choose a high physics fps and get the benefit of matching between physics and frame times, or low physics fps and have physics effectively driven by frame deltas.

There is also a minor refactor to the main::iteration function, notably moving the physics tick into a separate function, as well as a major refactor to main_timer_sync, separating the common components of timing (timescaling, limiting max physics ticks) from the details of the timestep functionality themselves, which are separated into 2 classes, MainTimerSync_JitterFix (the old fixed timestep) and MainTimerSync_SemiFixed.

There is also an added option to allow the existing global time_scale to change the speed of the game without affecting the physics tick rate (i.e. giving consistent physics at different timescales).

Fixes godotengine#24769
Fixes godotengine#24334

The main change in this PR is adding the option in project settings->physics to choose between the old fixed timestep and a new path for semi-fixed timestep. With semi-fixed timestep users can either choose a high physics fps and get the benefit of matching between physics and frame times, or low physics fps and have physics effectively driven by frame deltas.

There is also a minor refactor to the main::iteration function, notably moving the physics tick into a separate function, as well as a major refactor to main_timer_sync, separating the common components of timing (timescaling, limiting max physics ticks) from the details of the timestep functionality themselves, which are separated into 2 classes, MainTimerSync_JitterFix (the old fixed timestep) and MainTimerSync_SemiFixed.

There is also a modification to allow the existing global time_scale to change the speed of the game without affecting the physics tick rate (i.e. giving consistent physics at different timescales).
@andyfreer
Copy link

@lawnjelly doesn't this also fix #25068?

@lawnjelly
Copy link
Member Author

@lawnjelly doesn't this also fix #25068?

Nope, this PR goes with the ease of use approach, and simply adds hard coded semi-fixed timestep as an option in addition to the default fixed in the project settings.

One alternative approach as I mentioned in that issue is allowing the timestepping to be customizable from script, which could be used to implement different timesteps and delta smoothing. This could also be potentially be used to allow manual stepping for network games.

On the other hand, in practice, for single player games having fixed timestep and semi-fixed (and delta smoothing) has most of the common approaches to timestepping covered. As using semi-fixed with a long timestep effectively leaves the physics being stepped by the frame delta, which is the last of the most common 3 methods, especially when used in conjunction with delta smoothing (this can be used for example to give 60 ticks per second physics on a 60fps monitor, and 144tps physics on a 144fps monitor, tying physics update rate to refresh rate).

Having customizable timestepping could be useful for network games but on the flip side may be too complicated for most users making single player games. With networking there is also the issue that exactly what to rewind and restep (on client and server) may be very game dependent, and the need for a history buffer.

@andyfreer
Copy link

andyfreer commented Nov 16, 2019

@lawnjelly thanks for the explanation. Since my comment I've ported your smoothing-addon to C# so i'm familiar with your addition of Engine.GetPhysicsInterpolationFraction to the code.

Personally i'd be more interested in the option for manual control of Physics stepping than matching the fixed step to the frame delta (especially for Networking)... from experience in Unity with complex physics like deep joint-chains with a lot of forces applied, fixed timestep is something to control independently of frame delta (which can vary wildly with high frequency monitors like you mention) because increasing fixed timestep to high levels can have a large performance impact or result in different behavior and often needs balancing independently of framerate... another thing missing in Godot is manual setting for solver iterations which can be a key part of tuning complex physics setups, I raised an issue on this. Also in Godot seems like timescale changes aren't fully applied fully to the fixed step (can't remember where I saw this) but that seemed like an issue too for example in slow-mo sequences or generally to keep everything balanced.

So personally I think this PR is good as an option but I think it would also be great to have the option of customizable timestepping... I don't think history buffer etc is in-scope at the engine level for that or that it's a problem that new users won't understand/use it as it's optional.

@lawnjelly
Copy link
Member Author

I'll try and have a go at posting something on this at godot proposals (I've been lazy on this because I am working on other things now 😁 ). Speaking for myself, I have no huge preference for either hard coded or customizable, or both, or indeed no abilities in this direction and sticking with fixed timestep only.

It is really boils down to the mission statement for Godot - what are the aims. Is it to provide a highly focused engine that is good for single player, or something more adaptable? There is no right or wrong answer, just a question of where people want to take it (and especially reduz).

When we talked about timestepping a while ago he mentioned that he thought stepping the physics in sync with the refresh rate was a good way to go as an alternative to fixed timestep interpolation, but no one had implemented it. That is part of the reason I made this PR - it pretty much enables exactly this (especially if used in conjunction with delta smoothing, which would be a separate PR). If you set semi-fixed timestep to a low frequency (say 10tps), you will effectively get frame delta based physics stepping.

Personally although semi-fixed is the default in some engines (e.g.): 👽
https://forums.unrealengine.com/community/community-content-tools-and-tutorials/87505-using-a-fixed-physics-timestep-in-unreal-engine-free-the-physics-approach

I myself prefer fixed timestep with interpolation for production games, even though it requires a little more thought, because of the more deterministic behaviour (which makes it far easier to prevent timing bugs, which can delay / prevent a game shipping). Semi-fixed is fine for some types of games though, and is more beginner friendly in the sense that there is no need for interpolation.

@aaronfranke
Copy link
Member

@lawnjelly Is this still desired? If so, it needs to be rebased on the latest master branch.

@lawnjelly
Copy link
Member Author

@lawnjelly Is this still desired? If so, it needs to be rebased on the latest master branch.

Yes, we need to have a full discussion about timestepping for 4.x at some point. This PR handles most of the options, there may be one more to add, auto-changing the fixed timestep rate to the frame rate. Also @zmanuel 's jitter fix changes would need to be applied in here (I'm not sure if they have been merged yet).

So this PR won't take a lot of tweaking to work in 4.x, but would be better to wait until we've had the discussion first before finalizing.

@lawnjelly lawnjelly changed the title Add semi-fixed timestep and physics time stretching for global timescale [WIP] Add semi-fixed timestep and physics time stretching for global timescale Jul 1, 2020
@lawnjelly
Copy link
Member Author

Thank you very much. This is fixing something that has been bogging me for days. Hopefully some friendly soul has time to review this PR, something like this would be very useful.

We did actually bring this up in the physics review meeting, it's been pushed back to Godot 4.1 or later to look at interpolation and timestepping strategies.

@Calinou
Copy link
Member

Calinou commented Nov 7, 2020

In the meantime, you can use the smoothing-addon for physics interpolation. This should fix most visible stutter/jitter issues.

@YuriSizov
Copy link
Contributor

I've turned it into a draft since it's still in progress and would not be revived any time soon (and by the time "4.1 or later" comes it would likely need to be reworked).

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