Using a fixed physics timestep in Unreal Engine, free the physics approach

Using a Fixed Timestep for the Physics Engine

Hi, I’ve wanted to implement a for my game that is not tied to my game framerate, because of a few improvements it has for the kind of physics I needed.

Normally the physics engine is tied to the actual game framerate (up to a specific framerate, in which the physics simulation starts to run slower). That means that if your framerate is lower, you will have a longer tick in the physics engine as well. The longer the ticks are, the more inaccurate the physics engine is, and the more it has to guess. This causes at very low framerates problems like two things hitting together and flying suddenly at the speed of sound, etc. Now, Unreal has a solution for this, there is the physics substepping which can, if your framerate is low, divide a single game tick into a few physics ticks, so that effectively fixes that problem.

The main reason I’ve wanted to use a fixed timestamp is to have very consistent physics that I can almost call deterministic. If the Delta Time between each physics frame is always the same, then the two identical physics simulations will give the same results, unlike non-fixed timestamps, which have differing framerates that will bring different results each time. There is still probably a bit of variance because of floating point inaccuracies, but it’s probably so small that I’ve noticed nothing of the sort.

This also gives you full control over your physics framerate, more than you would have even with substepping.

If it’s so good, why didn’t Epic implement this themselves?

As Epic Developer says, they debated this internally, wether to use a fixed timestamp, or a semi-fixed timestamp like they use today, they decided to use a semi-fixed timestamps for a number of reasons.

  • With a fixed timestep, since the physics tick is different than the game tick, this can introduce a latency of up to 1 physics frames. For example, if the game runs at 60fps, and the physics runs at 75fps, for each game frame, the physics must process 1.25 ticks per game tick. But you can’t process a quarter tick, so what it does it is keep the extra time in a timebank that once it goes over 1 frame, you process that frame as well, so that means your physics simulation is in the past anywhere from 0 frames to less than 1 frame. This is probably negligible unless you are running at a very low physics framerate. I’ve also heard this can introduce some weird visual artifact but I’ve experienced nothing of the sort.

  • With a fixed timestep, you can’t use the game DeltaTime on the tick function for physics operations, since that DeltaTime is different than the physics DeltaTime. What you need to do instead is use the FCalculateCustomPhysics delegate instead of your tick function. Example Here.

There may be more drawbacks that I do now know about, but for me its worth these two.
I also do not know what happens if the physics engine can’t do all those physics ticks in the time its allocated.

How to implement this:

First of all, this uses the Unreal Substepping system. So for this to work you need to go to your Physics settings (Edit->Project Settings->Physics) and enable the Substepping option. Also, to disable this fixed timestep, you can just disable the substepping and go back to the normal system.

Open your Engine code project (can’t use a binary build, need to change the engine for this), and go to a file called PhysSubstepTasks.h, there go into the implementation of FPhysSubstepTask::UpdateTime.
This method gets called every frame and receives a UseDelta value, which is the game tick DeltaTime, and sets the amount of substeps required to be done, and the DeltaTime for these substeps. Just comment everything in it, and replace it with what were gonna do below.

What you want to do is add to the FPhysSubstepTask class a float value, called ExtraTimeBank in my case, which will store the extra that needs to be calculated. Initialize it to 0 in the constructor.
In the UpdateTime method you want to have a float value that will signify the frame rate the physics will run at, I just used the MaxSubstepDeltaTime value from the physics options so I could change it from the editor.



float FPhysSubstepTask::UpdateTime(float UseDelta)
{
	UPhysicsSettings * PhysSetting = UPhysicsSettings::Get();
	float FrameRate = PhysSetting->MaxSubstepDeltaTime;


After that divide the UseDelta by the FrameRate, and floor that to find the amount of frames we want to calculate now, and the value past the point on it is the amount of frames we want to add to the timebank



        float ExtraSteps = UseDelta/ FrameRate;
	uint32 AmountOfSubsteps = FMath::FloorToInt(ExtraSteps);
	ExtraSteps -= (float)AmountOfSubsteps;

	//Add to the time bank
	ExtraTimeBank += ExtraSteps * FrameRate;

And then check if the timebank has frames that can be filled in it, if so, take it.



	uint32 TryGetExtraFrames = FMath::FloorToInt(ExtraTimeBank / FrameRate);
	ExtraTimeBank -= (float)TryGetExtraFrames * FrameRate;

	AmountOfSubsteps += (float)TryGetExtraFrames;

Then set the class’ NumSubstep and DeltaSeconds to the values you got, and return the division of them as the function requires.



	NumSubsteps = AmountOfSubsteps;
	DeltaSeconds = FrameRate * AmountOfSubsteps;

	SubTime = DeltaSeconds / NumSubsteps;
	return SubTime;

Compile the engine, and now when you start it, with Substepping enabled you can have a fixed timestep for your physics engine.
Change the framerate of the physics engine by changing the Max Substep Delta Time in your Physics settings (0.016666 is 60fps etc)

If you want to fast forward the physics engine for some reason, just increase the UseDelta time the function receives by the amount of time you want to fast forward. The UpdateTime method gets called from FPhysScene::SubstepSimulation.

I thank 0lento and OmaManfred for helping me find all this out.

5 Likes

Cool!
Would be nice to have this as a PR on github with a #define to conditionally enable it.

1 Like

Agreed!

Thanks for this, Snowcrash5. I know a lot of people are after this!

Nice work.
Though wouldn’t it be better to do it in the function that calculates the delta time so that the fixed step is also used in non-physics functions/the whole engine?

The problem is that physics time doesn’t match render time anymore, so visual representations of physics objects are out of phase with the rest of the game. This causes stuttering, but the good news is that it’s easily avoidable. The solution is to interpolate the visual representation between the current and last physics states. For that you need to store an extra transform (position, rotation) per physics object which represents the previous step’s state. Right before each substep, store off the current state. When all steps have completed for the current game frame (might be 0, might be several), lerp/slerp between the previous & current step data. The lerp fraction is determined by “Leftover physics time” / “Fixed time step” (ExtraTimeBank / PhysSetting->MaxSubstepDeltaTime in your example). Now every game frame is guaranteed to have updated visual transforms for every physics object, even if there were no physics steps run.

Once you do that, you can have physics running at a very low rate and still have perfectly smooth visual movement.

If you run your physics fast – like 144 Hz, or even 250 Hz – then the “frame latency” ends up being less than the graphics frame latency, and you’re fine.
If you’re worried about the 0-1 frame jitter “time bank” then you can render using forward-predicted positions of entities, or even render using backwards-predicted positions if you’re also worried about the possibility that a foot might sink an eighth of an inch into the ground when running …

What happens if you use this on, let’s say, rts game. Server on Intel and Client on Amd/PS4…
Would simulation results be the same on both server and client?

And what if you go further and implement fixed point math, such as the Q format?!

No, they won’t be the same. Precise behavior about floats is just way too complicated to understand IMO.

A good starter read:

He has plenty more posts on floats if you want to dig deeper.

Fixed point should work fine, as that’s just integer math under the hood, no? Although seems like a pretty large task to write your physics engine in ints

Basically what could happen is that you start doing more physics steps because your total frametime starts lagging but when you add more work to it, it’ll lag even more and at some point it just can’t keep up, starving the CPU (at least in theory).

I’d still keep the “Max Substeps” parameter around and use it to limit max steps you can calculate between frames. If you can’t do the work within max substep amount using fixed timesteps, you could then just split the frametime with your max substeps and use it like substeps work by default (only as failsafe). You could also change the Max Substeps to have little more headroom, especially if you want to run your physics at slightly higher framerates.

To keep fixed timesteps, delay the simulation time until the rendering catches up (ie less time will have passed in the game than real time). If it is a multiplayer game, you will also need to freeze the server and wait, or else disconnect clients that can’t keep up.

As far as determinism, it can be done in a floating point physics engine but not in PhysX currently. Contrary to what some have suggested, floating point is atomically deterministic on a single client. The result of a sin operation will always be the same in a single thread unless you do some funny things. The problem is that different chipsets and floating point modes of operations have slightly different results for the same operations. In theory you can force a specific IEEE standard but it can be expensive if a chipset doesn’t support it natively and you have to emulate. I think some runtime operations in Java can enforce certain floating point standards, for example. The second problem is that the physics engine itself might have race conditions, especially if it is using parallelization.

@a-tocken, I replied to you in this thread, just to keep the discussion in a single place.

I’ve submit a pull request for activate simulation fixed delta and enhanced determinism directly in the project settings

I’ve followed thus tutorial but my project physics still work really bad.

60 to 120 fps is okay but lower 60 fps physics has critical problem.moving slower than higher fps.

I’m using SetPhysicalVelocity() in my physical movement component.

Can someone explain SubStepping Settings in Editor-Physics,Frame?

Here is my setup and is buttery smooth, I really cannot believe what a differance it made, so happy!!!

1 Like

For chaos?
No doubt chaos is the probelm itself…

On physx you barely have issue even with the regular setup. However, this is an interesting option… for switch/lower end 30fps stuff.

As always, if you build your games with physics considerations in mind (ei: making sure your speeds and size of collisions cannot possibly cause a “miss” between frames) you wouldnt really even need to sub-step stuff…

Hey there, sorry for necro. I am trying very hard, however I am unable to get these values from the physics substep task, as the engine always kicks me out saying I cannot include this and that (even tho I used all the required modules) Is there any way to extract these values in the substep task? Any examples that would be working?

Is anyone else not seeing any changes with physics? Moreover, looking at the UE5 source code, I don’t see any place where FPhysSubstepTask::UpdateTime is called, or where FPhysSubstepTask is instantiated. Does anyone know where this class gets used?

I know this is an old thread, but it seems to be a resource for information about (more?) determinism in UE.

I want to add that the posted method is not the typical method to do fixed physics timestep, because it creates a very rigid connection between physics and rendering, and it does not work well for slower physics timesteps.

The typical method to use a fixed physics timestep, is to do rendering based on some kind of interpolation between the previous physics frame, and the most recent physics frame. The simplest form of this is to do something like:

render_data = LERP(physics_step_minus_1, physics_step_last, % from minus_1 to last)

This allows you to render at absolutely any FPS (lower or higher than the physics step) with no jerky time discontinuities, because it is always interpolating a rendered position based on the actual time of the rendering, independent of physics calculation.

To understand this in the extreme, imagine these two systems running physics at 1fps, and rendering at 60fps. The OP’s posted solution will only move physics objects at 1fps, while the method above will move objects every frame according to the LERP, but the physics detail resolution will be at 1fps.

The drawbacks of doing this more accurate method include: (a) you have to keep 3 copies of the physics results, cur, minus_1, and the LERP, (b) you have to calcuate the LERP, (c) there is discontinuity between the LERP function and the actual physics motion, which can be visible when FPS and physics-tick deviate, (d) the delay of rendering is between 1 and 2 Physics steps (not 0 and 1), becuase you can only interpolate between two known physics results, and you have to spend the next “physics step” interpolating during rendering because you won’t have a new one.

These are likely some of the reasons that Epic didn’t include fixed timestep support in UE.

Hi there, could you go into more detail on how to do this? I’ve managed to implement ops method into 4.27. However I am fairly new to c++ and have no idea how to achieve an interpolated result like you describe, this is the only thing I need to do in c++ for my blueprint game so I would appreciate the help.

I’m not familir with UE C++, so I can only help by describing the technique for you in abstract. I suspect doing something like this is very complicated and non-trivial in UE, because it will touch many data-paths (physics, rendering, animation state).

In a system with decoupled simulation and rendering, and a low-rate fixed timestep simulation (like Starcraft 2), you have three (or four!) sets of “state” for each object that include orientation and animation-state.

Let’s assume 10fps physics, and 60fps rendering

  1. sim-state-next (calculated at 10fps)
  2. sim-state-minus-1
  3. sim-state-minus-2
  4. render state (interpolated between #2 and #3 at 60fps)

What you end up with is:

sim-state-minus-2  --------- sim-state-minus-1 --- (now) --- sim-state-next
                         /\
                          +------ rendering this moment

The simulation (physics) will run when the 10fps (10hz) timer has indicated a new physics step is due, and it will calculate a new simulation step based on the old step and mob actions…

However, during the time you write to sim-state-1/2, you can’t render interpolate, so if there is any chance the simulation step calculation can take longer than the rendering frame (which is likely if you want to support 144hz rendering), you can’t overwrite sim-minus-1 and sim-minus-2 until you are finished calculating the next simulation step. This leads to a triple buffering solution above, where you calcualte into sim-state-next, and copy into 1/2. If you know you can finish the simulation state calculation during a render frame (or you are willing to hold up the render frame because of it), you can collapse #1 and #2 above, but I don’t recommend it, because the simulation is calculated infrequently and this can lead to fps “hitches”.

In addition to interpolating between orientations (position/rotation), it’s also necessary to interpolate animation paths and states. This requires calculating the current animation state as a delta in time from sim-state-minus-2, which requires copying any animation state calculations, initiations, and creations through the triple buffering (cur → minus-1 → minus-2)

As for doing this in UE, some of the things you’ll need to look at include:

  1. fully separating the physics and actor AI loops from the rendering loop
  2. setting up the double-buffered “sim-state-1” and “sim-state-2” history for each sim object
  3. copying from sim-state-next → sim-state-1 → sim-state-2 at the right time
  4. changing rendering orientation and animation to be based on sim-state-2 → sim-state-1 interpolation, instead of rendering from “current” like UE does now

One way to do this, such as what is being done in Stormgate, is to turn off UE physics and AI code and create your own totally new simulation and physics system that handles all of this… and then just copy whatever you’d like UE5 to render into the “current” state. If you do this, you either won’t be using blueprints, or you’ll have to find your own way to compile and/or execute blueprints.

you can see the stormgate folks talk a little about this in their tech reveal: