Advertisement

Questions about fixed timestep game loop

Started by June 19, 2020 03:28 PM
3 comments, last by Juliean 4 years, 5 months ago

I am at the part where I am trying to implement a fixed timestep game loop

I have read articles like:
https://gafferongames.com/post/fix_your_timestep/
https://dewitters.com/dewitters-gameloop/

And I understand the basics as follows:
1. Calculate the current frame's delta time
2. Add the delta time to a “update time” counter
3. While you have enough “update time” left in the counter update your game logic and minus the target timestep / FPS amount
4. Calculate a interpolation value and pass it to the render method

My confusion sets in and everything kind of falls apart with step 4. I understand I should be calculating the interpolation value to more or less “smooth out” the render from Frame A to Frame B. But I don't really understand how it should be done or how it should be applied

For example, if my logic looks like this

//Timestep
double timestepInMS = 1000.0 / 60.0;

//Game loop
void gameloop() {
	previousTime = nowTime;
	nowTime = Timer.now();
 //Return "now time" in milliseconds
	dt = nowTime - previousTime;
	
	updateTime += dt;
	
	while (updateTime >= timestepInMS) {
		updatePlayer();
		updateTime -= timestepInMS;
	}
	
	//=== interpolation value ???
    //interpolationValue = updateTime / timestepInMS;
    
	render();
}

//Logic update
void updatePlayer() {
	if (keyboard.isKeyDown('D') == true)
		player.position.x += 5.0;
}

//Render update
void render() {
	player.draw() //Put the player's sprite vertices into a GPU buffer
}

From this point, I don't really understand where to use the interpolation value. If I'm just placing vertices of a quad into a vertex buffer in my player.draw() where does the interpolation value get used? Everything dealing with position and other related logic was done in the playerUpdate() method.

Where am I going wrong with all of this?

noodleBowl said:
From this point, I don't really understand where to use the interpolation value. If I'm just placing vertices of a quad into a vertex buffer in my player.draw() where does the interpolation value get used? Everything dealing with position and other related logic was done in the playerUpdate() method.

In order to use the interpolation step (which by the way is totally optional) you have to keep two versions of your world-state: One for the current frame, and one for the last. Then, you would use the alpha-value in your drawing-routines to calculate the “now” position, based on current and last.

void draw(double alpha)
{
     Vector3 vNowPosition = lerp(vCurrentPosition, vLastPosition, alpha);
}

This means copying over the state before you call your fixed update.

void prepareUpdate()
{
	vLastPosition = vCurrentPosition;
}

And if you really wanna do it right, you need have different methods for updating the position, depending on whether an object moves or teleports. In case of a teleport, you also need to assign your last-position; otherwise you end up with frames between current and target position (which is usually wrong).

I do think the results of this interpolation can be noticable, especially when you think about being able to render at higher rate monitors without also updating more often; but it can also put quite a burden while developing. You have to decide which values can be interpolated and which can't (ie. you cannot interpolate a Texture); you have to now differentiate between moving a value and force-setting it; you have to make sure that calcuations for different objects stay relative to one another during the interpolation or else you have visible stuttering; etc…

You should try to make a minimal example using only positions and see if the results are really worth it for you.

Advertisement

@Juliean
That makes a lot more sense.

In the example you provided you lerped between previous position and current position, I assume I would need to lerp / interpolation for things like rotation as well right?

If I choose not to do the interpolation step, can I assume the worst thing that would happen is that the render for game objects / their animations could be jittery or skip if I took too long to do a logical update?

noodleBowl said:
In the example you provided you lerped between previous position and current position, I assume I would need to lerp / interpolation for things like rotation as well right?

Yes, you would interpolate between rotation, and scale when talking about transforms as well. Also there are lots of other things that you could interpolate too, like alpha-values for fades; colors when doing blend-effects, etc…

noodleBowl said:
If I choose not to do the interpolation step, can I assume the worst thing that would happen is that the render for game objects / their animations could be jittery or skip if I took too long to do a logical update?

If you don't do the alpha-step and your implementation of the rest of the update-loop is correct, then the worst thats going to happen is that the movement doesn't look as smooth when playing without VSync or updating at intervals not matching your monitors rate. Thats because the alpha-interpolation is only there to create distinct values for when rendering multiple times between the same update-loop, and not for when your update takes really long (in which case you will render less often than updating).

In my engine I have the option to turn the interpolation on and off on the fly, so I can see the difference. Its noticable, mostly on camera-movements, but its not like things look out of place without it. Think of it as the cherry on top.

This topic is closed to new replies.

Advertisement