Jumpy movement with fixed timesteps

Started by
24 comments, last by krippy2k8 11 years, 8 months ago
Iv read all the articles and cant find what i am doing wrong here. I am using OpenTK, with my own render loop.

My loop


public void Run() {
Initialize();
InternalLoad();
bool running = true;
double currentTime = 0.0d;
double newTime = 0.0d;
double frameTime = 0.0d;
double dt = 0.03d;
double accumulator = 0.0d;
double alpha = 0.0d;
Stopwatch timer = new Stopwatch();
timer.Start();
currentTime = timer.Elapsed.TotalSeconds;
while (running) {
RenderWindow.ProcessEvents();
if (RenderWindow.Exists && !RenderWindow.IsExiting) {
newTime = timer.Elapsed.TotalSeconds;
frameTime = newTime - currentTime;
currentTime = newTime;

if (frameTime > 0.25d) {
frameTime = 0.25d;
}

accumulator += frameTime;
while (accumulator >= dt) {
accumulator -= dt;
InternalUpdate((float)dt);
//Console.WriteLine("UPDATE");
}
alpha = accumulator / dt;
//Console.WriteLine(alpha.ToString());
InternalRender((float)alpha);
}
else {
running = false;
}
}
timer.Stop();
InternalUnload();
}


Interpolation of transforms for rendering

public override void Render(float alpha) {
Vector2 lerpTranslation = _nextTranslation * alpha + _prevTranslation * (1.0f - alpha);
Vector2 lerpScaling = _nextScale * alpha + _prevScale * (1.0f - alpha);
float lerpRotation = _nextRotation * alpha + _prevRotation * (1.0f - alpha);
GL.PushMatrix();
GL.Translate(lerpTranslation.X, lerpTranslation.Y, 0.0f);
GL.Rotate(MathHelper.RadiansToDegrees(lerpRotation), new Vector3(0.0f, 0.0f, 1.0f));
GL.Scale(lerpScaling.X, lerpScaling.Y, 1.0f);
base.Render(alpha);
GL.PopMatrix();
}


Anyone see a glaring mistake here? I get jumps every few milliseconds, its appears to jump forward then jump back, but that might be my eyes not perceiving the movement correctly. Sometimes very apparent jumps.
Advertisement
I don't see anything that looks too suspect there. What happens if you don't interpolate and just render at _prevTranslation each frame?
[sup]i think you pass to render alpha. Why? I dont know what internalupdate do, but i think render must not to have calculations dependant on time, all calculations must be done before, and with one time delta (dt), owervise why to chop accumulation to dt if you use alpha ...[/sup]
[sup]Must be: [/sup][sup]Update(dt); [/sup][sup]Render(); no alpha I think[/sup]

i think you pass to render alpha. Why? I dont know what internalupdate do, but i think render must not to have calculations dependant on time, all calculations must be done before, and with one time delta (dt), owervise why to chop accumulation to dt if you use alpha ...
Must be: Update(dt); Render(); no alpha I think


His game logic is updating at a fixed interval every 30ms and his render is doing a smooth linear interpolation between the transformations calculated in the update, so the animations still look smooth at high frame rates even though the game logic is only updated 33 times per second.

[sup]i think you pass to render alpha. Why? I dont know what internalupdate do, but i think render must not to have calculations dependant on time, all calculations must be done before, and with one time delta (dt), owervise why to chop accumulation to dt if you use alpha ...[/sup]
[sup]Must be: [/sup][sup]Update(dt); [/sup][sup]Render(); no alpha I think[/sup]

Interpolation between states is absolutely critical in a fixed simulation step method such as the OP posted, otherwise you will get significant jitter.

Re the original topic:
The line
[source lang="cpp"]float lerpRotation = _nextRotation * alpha + _prevRotation * (1.0f - alpha);[/source][/quote]

Seems suspicious to me. What happens if prevRotation = 6.266 (359°) and next Rotation = 0 (0°)... the interpolation should result in 359.5°, but instead will result in 179.5° which is probably wrong, and will probably cause a jump in rotation
oh , you are right , i just saw that dt is big...

[quote name='serumas' timestamp='1344931223' post='4969355']
[sup]i think you pass to render alpha. Why? I dont know what internalupdate do, but i think render must not to have calculations dependant on time, all calculations must be done before, and with one time delta (dt), owervise why to chop accumulation to dt if you use alpha ...[/sup]
[sup]Must be: [/sup][sup]Update(dt); [/sup][sup]Render(); no alpha I think[/sup]

Interpolation between states is absolutely critical in a fixed simulation step method such as the OP posted, otherwise you will get significant jitter.

Re the original topic:
The line
[source lang="cpp"]float lerpRotation = _nextRotation * alpha + _prevRotation * (1.0f - alpha);[/source][/quote]

Seems suspicious to me. What happens if prevRotation = 6.266 (359°) and next Rotation = 0 (0°)... the interpolation should result in 359.5°, but instead will result in 179.5° which is probably wrong, and will probably cause a jump in rotation
[/quote]

This is the Lerp function Gaffer shows to use, but rotation does not seem like it is an issue. The real jump is in the translation. Is there a better Lerp function to use? I am tempted to dump my project here, but its fairly large at this point.

I don't see anything that looks too suspect there. What happens if you don't interpolate and just render at _prevTranslation each frame?


This also seems to jump, if i remember, don;t have the code to try right now. But it seemed to show the same issue, while obviously being quite choppy with the low frame rate. I am using farseer physics to update positions, but i don't think that is the issue as i had this working perfectly in SLimDX, but when i moved to OpenTK, now my rendering is jumpy.
I would try setting the fixed interval to something like 5 seconds, so you can actually see how exactly the jumps are happening. It could be that the interpolation is doing nothing, or that you are using alpha instead of (1-alpha), but it will be much easier to see this in slow motion.


This is the Lerp function Gaffer shows to use, but rotation does not seem like it is an issue. The real jump is in the translation. Is there a better Lerp function to use? I am tempted to dump my project here, but its fairly large at this point.


Instead of storing the starting and ending rotations for the timestep, you store the starting rotation and the rotation delta - that is how much you want to rotate during that timestep. Then you Lerp across the rotation delta adding it to your original delta, so that the angle rolls over and you're not trying to interpolate in the wrong direction.



This also seems to jump, if i remember, don;t have the code to try right now. But it seemed to show the same issue, while obviously being quite choppy with the low frame rate.


That's what I figured. The problem then is in your update function, not any of the code you posted here.

This topic is closed to new replies.

Advertisement