Advertisement

Fixed timestep with interpolation - 2D movement jitter/stutter

Started by August 13, 2023 07:52 PM
29 comments, last by skinmarquee 1 year, 3 months ago

Gnollrunner said:

Crowbone said:

I've checked/logged the frame-rate before; when the program starts up, it's around 39fps then it maintains at 60-61 fps (VSync on) (jittering is still present).

I don't think it makes a difference i.e it doesn't get any better when logging is removed (jittering is still there time to time)

Are you sure it's really maintaining 60-61 the whole time? It seems like it only jitters two or three times. Try to isolate those spots. I had a similar problem. In my case it turned out to be deleting meshes in the render thread due to LOD. Could it be some sort of collection that periodically kicks in? Does it happen in the same spot on every run?

Yes, I logged the FPS and fixed updates per second, it starts off low then stays in the range 59-61.

I'm not sure what you mean by collection?

It doesn't occur in the same spot each time, it's all dependent on the frame time so it's random I guess.

kwikc said:

I think that the red block moving in the youtube video can be considered as smooth. I have a test unit written in DirectX 9 having the similar lag when running under windowed mode, but basically perfectly smooth when running in exclusive full screen mode.

I also experienced such lag when playing AAA titles in full screen. They may be caused by different reasons according to the techniques used anyway.

It's only smooth sometimes but there is noticeable shaking.

Going back to your original post, you said something about running physics at 60fps, yet letting the render speed vary. I remember considering this for my code but deciding against it. I was going to do physics in a separate thread, but figured there was no point in rendering a frame if nothing has changed. It could be your jittering is a quantization issue between the rendering and physics.

Maybe you should try just basing the physics on the frame render time. This works for me. The only other thing I might add is a minimum frame time.

Advertisement

Crowbone said:
Out of interest, for your game which rendering library do you use? I'm going to test out the same code with other libraries just to rule that out.

I'm using my own implementation of a rendering library, which is based on using the plain APIs, primarily DirectX11 at that point. So that won't easy for you to test out unfortunately…

Though from the video, I'm really not 100% convinced about the lag. It does seem a bit jagged, but only when I stick my face up to the screen, from afar I would say its perfectly smooth. Just for comparison, I've made my own test with a moving rectangle, and made my own video for you to compare (link down below because tihs forums software is the worst):

Not sure if the video 100% is correct, as my monitor is 160hz and the framerate obviously much lower. Though I got to say, after viewing my own case and comparing with the video, is also is way better. Never did a coloured rectangle as a test before, but my result is 100% smooth, no noticable jitter or lag at all, no matter the viewing distance. So maybe there is some issue in your example after all, even if I originally was not convinced by the video.
Not sure how I can further help you find the difference, though. As I said comparing rendering library won't be an (easy) option, and I could show you my game-loop code but it's a lot more complex with additional features.

https://gyazo.com/b873578c259dc8885441f0065d4701b2

Gnollrunner said:
try just basing the physics on the frame render time. This works for me.

I don't recommend this. I did this for a long time, but when I switched to a fixed physics time step the stability of the simulation substantially improved. A fixed step has much lower jitter in the collision response and stacking for some reason. I think there are some errors in the numerical integration that cancel out when a fixed step is used, but which propagate when the step is variable.

Aressera said:

I don't recommend this. I did this for a long time, but when I switched to a fixed physics time step the stability of the simulation substantially improved. A fixed step has much lower jitter in the collision response and stacking for some reason. I think there are some errors in the numerical integration that cancel out when a fixed step is used, but which propagate when the step is variable.

I'm doing this in 3D. Not only do I do continuous collision detection, I actually build the geometry around the player as he moves, most of it with a couple dozen octaves of noise functions. It's still plenty fast and smooth. The only problem was deleting old meshes (due to LOD) in DirectX, so I just moved that to another thread.

In any case what exactly do you do if the physics isn't done before the next frame? Display the same frame twice?

I'm guessing whether this is suitable or not largely depends on the specifics of what you are doing, but I would think moving a box in 2D would be fine.

Gnollrunner said:
In any case what exactly do you do if the physics isn't done before the next frame? Display the same frame twice?

You can extrapolate the object positions forward in time using the current velocities. My physics engine has two interpolation strategies: interpolate between current and previous step (like in OP), or extrapolate forward from current position using numerical integration. Interpolation adds latency, so I prefer to extrapolate. However, extrapolation can be jittery if there is lots of non-smooth motion. I also run physics at 120Hz so the possibility of no physics update within a render frame is small.

Advertisement

Gnollrunner said:
In any case what exactly do you do if the physics isn't done before the next frame? Display the same frame twice?

Interpolate between both states? I'm only a bit confused by your question, since this is exactly what OP is doing and the sole point of error in this topic. I thought based on your previous responses that you would know that.

In case you actually don't know - what you do in this scenario is to keep the last state around until the next frame is to be calculed. On rendering, you calculate at which point in time between both frames you are (as an alpha between 0.0 and 0.99), and display the state in between based on that alpha (via lerp/interpolate). This produces a result that is visually indistinquishable from if you were doing a variable timestep, and very smooth… if it works properly, anyways.

I'm personally also very in favour of doing it that way, and I've even gone so far as to make everything that is not purely render-only part of this fixed timestep. You do get additional determinism, which is something that is solely missing from systems that don't fully commit to a fixed timestep (I'm talking about you, Unity). I'm not saying it's not possible or feasable to do otherwise, but you get rid of a lot of edge-cases and potential different behaviours based on machine, scene or what not (basically everything that affects framerate). The crouning achievement for myself that came fromt his, is the ability to easily create accurate replays based solely on user-input at a specific frame, which is used both as a way of automated testing, as well as being able to reproduce crashes and errors reported by users. While there are certainly also replay-systems under variable timestep-conditions, the additional robustness and ease of use due to a fixed-frame timing is a major factor for this, IMHO very useful system (that you simply could not do in engines like Unity).

Whether that matter to you or not is another topic, but if we talk about general engines/frameworks, I at least appreciate the option.

EDIT: Oh yeah, forgot that exptrapolition was also a thing, that probably explains my confusion because I was assuming interpolate was the only option for a fixed timestep. The obvious downside of the interpolate-based approach that I describe is that you effectively run 1 frame behind and have that additional latency. Also, you get additional complexity, at least if you apply this system to the entire gameplay, and not only physics (you have to implement it for everything that can be interpolated; and you also need to be able to distinquish for operations whether they “move” or “set” a value; otherwise you get false interpolation like when an entity is teleporting).

OK guys all that makes som sense, and I won't argue it has to be dome my way (especially since I'm in Tanzania at the moment typing on my phone, and it's hard for me to get in long discussions). I'll only say what I'm doing is working for me so while that holds, I'm not going to change it. In the case of the OP however, I'm still wondering why with a near constant frame rate does it move 0 and then move 2. That still seems suspicious to me. I would go into the debugger or logger and understand why that's happening.

Gnollrunner said:
OK guys all that makes som sense, and I won't argue it has to be dome my way (especially since I'm in Tanzania at the moment typing on my phone, and it's hard for me to get in long discussions). I'll only say what I'm doing is working for me so while that holds, I'm not going to change it. In the case of the OP however, I'm still wondering why with a near constant frame rate does it move 0 and then move 2. That still seems suspicious to me. I would go into the debugger or logger and understand why that's happening.

One thing that does seem strange indeed is the amount of times that no frame is run (*** in the OPs original log). I compared with my own loop, fixing it the same 160hz that my monitor has (with VSync on), and the amount of times over 6 seconds where no frame-update is run, is 6 (out of 1000 frames). Can't run on a lower-hz monitor right now to see if that makes a difference; and also OPs list is not very long, but seems to have a drastically higher rate of frames where not enough time passed to varrant a fixed-step update. Now, this in itself, just like the move values, would be normal. When I have my loop set to 50hz and the montiro is 160hz, of course a lot of times the loop passes, no update is necessary, and the alpha should smooth that out (which could still print odd move-deltas, depending on what alpha is at the point). Still, OP might have some inconsistency in eigther the frame-timing or general execution-delays, based on those differences.

Not sure how you could reliably debug those, though. One more thing for the OP that I noticed though: I see you use unsigned long long to count the timings. I'm personally using floats, aquired from the following function:

	double Timer::Duration(void) const noexcept
	{
		const auto end = getNow();
		const std::chrono::duration<double> duration = end - m_start;

		return duration.count();
	}

Also shouldn't make much of a difference, but since I cannot personally run your code… If that doesn't change things, maybe one last thing to do is try to actually log the calculated rendered rectangle position in relation to the state of the high_resolution system clock. Too sleepy right now to come up with a full formulate, but what I'm thinking is, you should get some factor to confirm (or deny) that the final position that is being rendered is actually constant with the progress of time - that would at least point out if there is some error in the calculation, or timing. Other than that, I'm out of ideas.

Crazy thought, printf is actually a pretty heavy operation, but it's there no matter what so I guess couldn't be the problem.

None

This topic is closed to new replies.

Advertisement