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.
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!