Download

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 fixed physics timestep 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 Ori Cohen 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.

2 Likes

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

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?