I've tested it with an object rotating where there was no input dependency) but still the same stuttering appears.
Does your frame interpolation do a slerp on object orientation?
I've tested it with an object rotating where there was no input dependency) but still the same stuttering appears.
@DaveSF yea I'm using a slerp for the orientation in the interpolation step
@Buckeye That's what I'm still trying to figure out, if this is conditional or not. As far as I can tell its not but I haven't had much time to test these last few days...Basically I tried 3 test cases with 2 of them displaying the rendered velocity on screen:
1. Move the camera left and right (no rotation) while having a plane in front of you. My velocity that is calculated is constant (I double checked it). So the result should be a constant color during the movement, but it is not. You can see it flickering from time to time. (And no it's not an issue of the rendered velocity calculation because the stuttering can be observed regularly, too)
2. An object that I'm rotating around the Y axis using only "elapsedTime" which is accumulated inside the update loop using my deltaTime.
The output here should also be constant but it is not. Again the flickering can be observed
3. Standing in front of a plane that has a UV animation, where a symbol is "scrolling down". This time of course there's no velocity to be calculated but I believe the stutter can be observed here too...
What I believe right now is that the stuttering originates from the inner update while loop because the more intense the work inside becomes the bigger the stuttering/flickering becomes. E.g. I output the acc variable each update step to my GUI (which creates lag) and the flickering becomes very prominent...
UPDATE: I just tried removing the inner while entirely just to see how it behaved. If I don't limit my physics the motion is perfectly smooth. At least as long as the framerate is around the same as the update frequency.
As soon as I introduce a time difference variable (currTime - prevTime) as deltaTime, the stuttering reappears.
Don't think there's anything wrong with my method of getting the current time stamp but anyway here's the code:
const double GameTime::GetTime()
{
if (start == 0)
{
QueryPerformanceCounter((LARGE_INTEGER*)&start);
QueryPerformanceFrequency((LARGE_INTEGER*)&frequency);
return 0.0;
}
__int64 counter = 0;
QueryPerformanceCounter((LARGE_INTEGER*)&counter);
return (double)((counter - start) / double(frequency));
}
Don't think there's anything wrong with my method of getting the current time stamp but anyway here's the code:
There is. It will drift as a result of your cast to double, meaning you shouldn’t plan on making any networked games with this code.
But that is not your current problem.
I just tried removing the inner while entirely just to see how it behaved. If I don't limit my physics the motion is perfectly smooth. At least as long as the framerate is around the same as the update frequency.
All hints that your interpolation code is incorrect. Either because it is being fed wrong numbers (the low values from accumulator before) or because the math is wrong.
One of the main differences between the typical fix-your-time-step Gaffer on Games article and mine is how the interpolation is calculated. He tries to predict into the future, whereas mine is simpler and interpolates between the last 2 sets of graphics data (so no data about the current velocity etc. is needed).
L. Spiro
To echo what L. Spiro said, you probably want to interpolate between the current and previous frame, as opposed to extrapolating based on current velocity. This sort of introduces a tiny bit of conceptual "frame lag", but it isn't noticeable.
This sort of introduces a tiny bit of conceptual "frame lag"
Actually, L. Spiro's method results, in fact, in rendering the "action" intentionally and exactly 1 fixed time-step previous to the most current clock time queried.
if (frameTime > 0.25) frameTime = 0.25;
This is part of a problem.
Whenever this limit is reached you will always get a stutter because the logic loop won’t wind down accumulator to the same result as it should.
When you implement a cap, it must always be done as the number of logical cycles you are willing to do, otherwise you have to manually take care to adjust the accumulator time so that ::frac( accumulator, gameTime->TimeStep ) yields the same result as without the cap.
Currently accumulator will always end up at 0.0 (+ some drift) at the end of the logical loop if that limit is ever reached.
L. Spiro
So basically you're interpolating between current and render state and not create a render state using prev and current ?
So basically you're interpolating between current and render state and not create a render state using prev and current ?
No. The state used for rendering is an interpolation of the last 2 states calculated using an Update function.
I'm still working on my first pot of coffee, so read the following carefully. Hopefully I'm thinking straight, but no guarantee.
I just noticed that you're processing mouse and keyboard input within the update loop. I suggest that you move the input processing outside that loop. That may be part of the problem. It appears you're updating object states with input data that may have occurred after the update time. It would be better to synchronize updating objects with input that occurred during the time frame for that update. Remember, what you render is what the object's state was 1 fixed time-step before the current gametime.
Consider the following situation (see the link to L. Spiro's implementation), assuming some numbers for illustration purposes.
[ to avoid confusion with regard to the term "current," I use terms prevUpdate, lastUpdate, and currentRenderState. ]
The fixed time-step is 33 microseconds. Updating and rendering takes ~20 microseconds. The object's state was calculated at time 0. The next time through the loop, gametime is 20, so no updating takes place. The currentRenderState is calculated with alpha = 20/33, but both prevUpdate and lastUpdate are from time 0, so nothing changes. The next time through the loop, gametime is 40, so the object is updated for time = 33 using mouse and keyboard input just obtained. If that input occurred after time = 33, then the object updating at time = 33 will be wrong as it's based on user input that hasn't occurred yet (as far as the object is concerned).
At that point, the currentRenderState is calculated with alpha = 7/33 (between states 0 and 33). But ... it's based on input data that may have occurred after time = 33.
Remember, the idea of using the update loop is let the object catch up to some multiple of the fixed time-step - not the current game time. Updates are always in the past relative to the game time.
A solution may be to time-stamp the input data, and use it for updating only if the time-stamp is in the interval [ prevUpdateTime, lastUpdateTime ).