Jump to content
  • Advertisement
Hashbrown

Understanding how a fixed time step game loop works, but having trouble grasping interpolation in the render function

Recommended Posts

Posted (edited)

I believe I got most of the theory covered, I'm just having trouble understanding how interpolation in the rendering loop works. Everything seems to work even when my timestep is at 1 fps, the character movement is interpolated smoothly regardless of the 1fps, but I want to really understand what's going on.

Below I'll explain as brief as possible what I understand so far:

Game Loop

while (true) {
    // Time Calculation
    double now = glfwGetTime();
    float delta = (now - previous);
    previous = now;

    if (delta >= 0.25f) delta = 0.025f;
    accumulator += delta;

    // Physics Update
    while (accumulator >= step) {

        UpdatePlayer(step);

        accumulator -= step;
    }
  	// Render
    float alpha = (accumulator / step)
    RenderPlayer(alpha);
}

The physics update makes sure my simulation's physics is corrected in the case that the loop is having trouble catching up. For example, let's say I want to move my character 1 unit per frame. Let's also say:

- PC1 is able to move the character 2 units in 2 seconds (2 frames).
- But PC2 lags behind and it takes 2 seconds to complete 1 frame.

dt.jpg

 

Based on what I understand, the slow computer will stay in the physics update one more update in order to catch up within that frame, essentially leaving the character in the same position like the quicker computer within the same time-frame.

In other words: PC1 only needed 1 physics update per frame, but PC2 needed 2 updates within 1 frame. Am I right about that?

 

Update Player

void UpdatePlayer (const float step) {
    
    previousState = currentState;

    currentState.velocity.x += (currentState.force / currentState.mass) * step;
    currentState.velocity.y += (currentState.force / currentState.mass) * step;
    currentState.velocity.z += (currentState.force / currentState.mass) * step;

    currentState.position.x += (previousState.velocity.x + currentState.velocity.x) * 0.5f * step;
    currentState.position.y += (previousState.velocity.y + currentState.velocity.y) * 0.5f * step;
    currentState.position.z += (previousState.velocity.z + currentState.velocity.z) * 0.5f * step;
}

I'm not getting into numerical integration but I did want to share it just in case. I'm actually using Velocity Verlet integration I found in this interesting article. The following part is where I'm having trouble:

 

Render and State Interpolation (having trouble understanding this)

void RenderPlayer (const float alpha = 1.0f) {
    vec3 interpolated = Interpolate(previousState.position, currentState.position, alpha);
    
    // Matrix Calculations
    player.transform.UpdateModel(interpolated);
    mat4 mvp = camera.projection * camera.transform.view * player.transfomr.model;

    // Upload to GPU and Render
    shader->UploadMVP(mvp);
    mesh->Render();
}

I believe I understand why we're interpolating, but still confused. Let's say my physics loop is running at 1 frame per second, I can interpolate between positions and render at a smooth rate. So 1fps won't be visually noticeable, which is awesome and very useful! I also understand that the alpha value is a percentage of how far we are from the next frame.

But when I print out some numbers, I notice that after interpolation, the currentState.position is at the right position, but when I check the interpolated position we're rendering to, it's always behind the current state. Is that normal?

Current State position: 2.000000 | velocity 1.000000
interpolated at render: x: 1.499536

I understand we're calculating a percentage of how far we are to the next frame, but shouldn't the interpolated positions match the currentState.position at some point? I'm afraid of rendering my player at an incorrect position. I'm having trouble wrapping my head around this concept still.

Hopefully this all makes sense, and if you read this far, thanks for reading!

 

Edited by Hashbrown

Share this post


Link to post
Share on other sites
Advertisement
59 minutes ago, Hashbrown said:

In other words: PC1 only needed 1 physics update per frame, but PC2 needed 2 updates within 1 frame. Am I right about that?

Yes.

59 minutes ago, Hashbrown said:

But when I print out some numbers, I notice that after interpolation, the currentState.position is at the right position, but when I check the interpolated position we're rendering to, it's always behind the current state. Is that normal?

Yes. You would typically render by interpolating between the previous and current states, so the render would in 99.9% of cases be behind the current state (unless you hit the tick bang on). In certain games you *could* also consider extrapolating beyond the current state, but beware, here there be dragons.

Share this post


Link to post
Share on other sites
12 hours ago, lawnjelly said:

Yes.

Yes. You would typically render by interpolating between the previous and current states, so the render would in 99.9% of cases be behind the current state (unless you hit the tick bang on). In certain games you *could* also consider extrapolating beyond the current state, but beware, here there be dragons.

Thanks for taking the time to answer my question Lawn, I really appreciate it. I feel like I passed a huge test at school :) I can move on to other topics now. Thanks again!

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!