How to achieve smooth animation - DT prediction

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
User avatar
Przemator
Party member
Posts: 107
Joined: Fri Sep 28, 2012 6:59 pm

How to achieve smooth animation - DT prediction

Post by Przemator »

Hi all

I want to ask you about a very basic thing, yet I think many people do not realize it. I am talking about creating a smooth animation, an optimal main loop. I decided to look into this matter after reading this article: http://frankforce.com/?p=2636

OK, so how do we get smooth animation? Just turn on Vsync and use the DT, then you have smooth animation, you may say. But recently I discovered that this whole approach only appears to work fine, but it's logic is false. The thing is, the DT that is passed to the update loop represents the time difference between the last screen flip and the second to last. So it is the DT that has been, not the DT that will be. OK, you may say, but the vsync fixes the DT, so it's always the same. Well, that's not true. Vsync does not assure perfectly even DT's.

So, we're not looking for the DT that has been, we're predicting the time of the next screen flip in order to draw an accurate frame. Honestly, I did not understand all of the stuff in the linked article, that's why I would like to hear your opinion.

I also attached an example with comparison where I use the Actual DT versus the Average DT. When you look at the moving blocks, you can see (at least on my screen) that the red block is "shaking" from time to time, and the green one is more stable.
Attachments
dt_test.love
DT Test
(776 Bytes) Downloaded 147 times
User avatar
bartbes
Sex machine
Posts: 4946
Joined: Fri Aug 29, 2008 10:35 am
Location: The Netherlands
Contact:

Re: How to achieve smooth animation - DT prediction

Post by bartbes »

I don't agree with your logic of "we're predicting the next frame". No, we're taking the state at the last frame, then applying our transformation for time passed since then to present the current frame. Yes, dt is the time to the last frame, but that is also the time you've yet to simulate.

EDIT: Also keep in mind your average is also measured over the past, this hides sudden movement (hence the smoothness), but I could easily induce larger dt values and it would show that the average dt method rubber bands back into a consistent state. This is arguably a nicer effect, but it also means your simulation is inconsistent for your averaging period after a sudden discontinuity. (Note that I assume the dt method is always consistent, which it isn't, but it's a fair baseline for this.)
User avatar
Przemator
Party member
Posts: 107
Joined: Fri Sep 28, 2012 6:59 pm

Re: How to achieve smooth animation - DT prediction

Post by Przemator »

bartbes wrote:I don't agree with your logic of "we're predicting the next frame". No, we're taking the state at the last frame, then applying our transformation for time passed since then to present the current frame. Yes, dt is the time to the last frame, but that is also the time you've yet to simulate.
I disagree, too :awesome: . If you use the actual dt, you're always one step behind, you're delivering frames which are accurate for the previous screen flip, not the one that you are about to render. In your code you're assuming this: OK, so if last flip interval was 0.03 seconds, then the next flip will take place in 0.03 seconds. And then comes the flip at 0.01 seconds, sooner than what you have drawn, and the user has a bad visual experience.

In my opinion a better approach is this: I want to predict when the next frame is displayed to the user and keep my simulation up to date with that. Using average DT is just one way of predicting, in the linked article the guy is using some more sophisticated way.
User avatar
bartbes
Sex machine
Posts: 4946
Joined: Fri Aug 29, 2008 10:35 am
Location: The Netherlands
Contact:

Re: How to achieve smooth animation - DT prediction

Post by bartbes »

No, the next draw happens directly after you are done, conceptually at least. Dt also includes time spent waiting, for whatever reason. I really do believe that you are always talking about now, and then drawing that. And not thinking about whenever this timestep ends (which is always after the draw occurs, by the way), and drawing that. Your claim that I assume anything about the next draw is plain wrong, I make no assumptions whatsoever on the future.

Regardless, like I mentioned, while your average dt method is smoother (which may very well be your goal) it is by definition lagging because you're basing your predictions not only on the last frame, but on the last second or so, which means you just smear a lagspike out instead of dealing with it.
User avatar
MGinshe
Prole
Posts: 31
Joined: Sun Apr 17, 2011 3:50 am
Location: New Zealand

Re: How to achieve smooth animation - DT prediction

Post by MGinshe »

i think you might have the logic behind dt a little bit wrong. dt is a means of accurately changing a variable, each update, based on time. if we want our object to move exactly 10 units per second, dt works perfectly. if our frame takes 0.5 of a second, our object will move 5 units. if our frame takes 1 second, our object will move 10 units. it doesn't matter than dt is based on the last frame, because 10 units will always take 1 second to travel.

by averaging the dt, our object is no longer guaranteed to have moved 10 units after 1 second. this is because a frame taking 1 second will not move the object 10 units, only a fraction more than our non-laggy frame.

your example is a cool concept with its own uses, but i think it would be a little too unreliable for any kind of accurate calculations
User avatar
Przemator
Party member
Posts: 107
Joined: Fri Sep 28, 2012 6:59 pm

Re: How to achieve smooth animation - DT prediction

Post by Przemator »

OK I implemented the logic described in the article, the loop looks like this:

Code: Select all

function love.update(dt)
    local old_delta = dt + delta_buffer
    local frames = math.floor(old_delta * 60)
    if frames < 1 then frames = 1 end
    local new_delta = frames / 60
    delta_buffer = old_delta - new_delta
end
1. We assume Vsync is on, with interval of 60 Hz.
2. We calculate how many full frames we should simulate.
3. We ensure that the simulation progresses by at least 1 frame.
4. We calculate the difference between the simulated time and actual time and store it in the delta buffer.

Now, please test the attached LOVE file and see how the red block shakes left and right once every couple of seconds. Then, grab the window to generate a lag spike and see how both blocks stay in the same relative position.
Attachments
dt_test2.love
DT Test 2
(703 Bytes) Downloaded 130 times
User avatar
micha
Inner party member
Posts: 1083
Joined: Wed Sep 26, 2012 5:13 pm

Re: How to achieve smooth animation - DT prediction

Post by micha »

It works for me. On my monitor it looks as if the blue box is moving steadily while the red one moves in jumps from time to time.

I was skeptical at first, but now that I see the method in action, I think it is a clever method, as long as vsync is switched on.
It took me a while to understand what the method does, so here is a summary:

In the update, we obtain a dt, which is the time passed, since the update was called last. But what we are really interested in, is the time between two drawing calls. dt is a good approximation to this, but additionally we know that the time between two drawing calls must be a multiple of the vsync-frequency. Thus, the method you show, rounds dt downward to the next multiple of the vsync-frequency. The part that was cut of is added on top of the next dt, so that no time gets lost.

The method can still not predict, the accurate time, the current update takes. So if for some reason the update takes more time, then still the frame drawn afterwards is "at the wrong time". And I think there is no way around this. This is a chicken-egg-situation. We need dt to make an update, but the time the update takes is not know beforehand.
User avatar
Przemator
Party member
Posts: 107
Joined: Fri Sep 28, 2012 6:59 pm

Re: How to achieve smooth animation - DT prediction

Post by Przemator »

micha wrote:It works for me. On my monitor it looks as if the blue box is moving steadily while the red one moves in jumps from time to time.

I was skeptical at first, but now that I see the method in action, I think it is a clever method, as long as vsync is switched on.
It took me a while to understand what the method does, so here is a summary:

In the update, we obtain a dt, which is the time passed, since the update was called last. But what we are really interested in, is the time between two drawing calls. dt is a good approximation to this, but additionally we know that the time between two drawing calls must be a multiple of the vsync-frequency. Thus, the method you show, rounds dt downward to the next multiple of the vsync-frequency. The part that was cut of is added on top of the next dt, so that no time gets lost.
Cheers! That's exactly how I understood it. Rather than relying on the DT, we rely on the fact than the interval between two physical screen refreshes is constant. I'm glad that you see how the red box jumps. For me it's not comfortable to see this kind of glitch.
micha wrote:The method can still not predict, the accurate time, the current update takes. So if for some reason the update takes more time, then still the frame drawn afterwards is "at the wrong time". And I think there is no way around this. This is a chicken-egg-situation. We need dt to make an update, but the time the update takes is not know beforehand.
For me there are two issues:
1. How to make this work for any refresh rate, not just 60 Hz? (LOVE does not support getScreenRefreshRate property, right?)
2. How do I achieve "smooth" graphics with a constant timestep with vsync turned off?
Post Reply

Who is online

Users browsing this forum: No registered users and 4 guests