3
\$\begingroup\$

In my game-loop, I am using fixed time step for physics and interpolation for rendering as suggested on Gaffer on Games | Fix Your Timestep!

However, when the framerate is varying between 30-60fps during the game, the game looks jumpy. For example, balls suddenly look accelerated when the frame rate increases from 35 to 45 suddenly.

Is there a way to make the game look smooth while framerate is varying?

Here is my game loop:

protected void update(float deltaTime) {
    //do some pre stuff

    deltaTimeAccumulator +=deltaTime; //deltaTimeAccumulator is a class-member holding the accumulated frame time
    while(deltaTimeAccumulator>FIXED_TIME_STEP) {
        world.step(FIXED_TIME_STEP, 6, 2);  //perform physics simulation
        deltaTimeAccumulator-=FIXED_TIME_STEP;
    }
    // world.step(deltaTime, 6, 2);

    destroyBodiesScheduledForRemoval();
    render(deltaTimeAccumulator /FIXED_TIME_STEP); //interpolate according to the remaining time
}

Here is the part related to the interpolation (related inner works of render() method) : this.prevPosition = this.position; //get previously simulated position

    this.position = body.getPosition(); //get currently simulated position

    //interpolate
    Vector2 renderedPosition = new Vector2();
    if (prevPosition != null) {//&& !isFloatApproximatelyEquals(this.prevPosition.x, this.position.x) && !isFloatApproximatelyEquals(this.prevPosition.y, this.position.y)) {
        renderedPosition.x = this.position.x * interpolationAlpha + this.prevPosition.x * (1 - interpolationAlpha);
        renderedPosition.y = this.position.y * interpolationAlpha + this.prevPosition.y * (1 - interpolationAlpha);
    } else {
        renderedPosition = position;
    }

    //Draw the object at renderedPosition
\$\endgroup\$

closed as off-topic by Josh Aug 17 '15 at 15:19

This question appears to be off-topic. The users who voted to close gave this specific reason:

  • "Questions about debugging a problem in your project must present a concise selection of code and context so as to allow a reader to diagnose the issue without needing to read all of your code or to engage in extensive back-and-forth dialog. For more information, see this meta thread." – Josh
If this question can be reworded to fit the rules in the help center, please edit the question.

  • 1
    \$\begingroup\$ This questions has been answered across many posts on this site. Please search. \$\endgroup\$ – Evorlor Aug 15 '15 at 16:01
  • \$\begingroup\$ I did search and looked all the topics talking about how to properly make your game independent of the variable time step (or frame time) of the game loop. I implemented my game-loop according to the principle ExOfDe suggested below (similar to what Glenn Fiedler suggested), but i am still getting acceleration for large fps changes. I added my game loop code to be clear. \$\endgroup\$ – Buddy Aug 15 '15 at 16:49
  • \$\begingroup\$ Are you making sure that you are using the fixed time value everywhere and that no code is using real time? If it isn't that, the problem seems like it is probably in how you render using the remainder of the time step. Can you show us some details on how that code works internally? \$\endgroup\$ – Alan Wolfe Aug 15 '15 at 18:48
  • \$\begingroup\$ Thank you Alan, i added the inner of the render method showing how remainder of the time step is handled \$\endgroup\$ – Buddy Aug 15 '15 at 19:04
  • 1
    \$\begingroup\$ Decrease your maximum delta time (what this code refers to as FIXED_TIME_STEP); what you're describing is temporal aliasing. You need to increase sample frequency in order to minimize it. Interpolation helps with this, but it's quite ineffective in the grander scheme of things. I'm sure you've realized in rendering in general that interpolation doesn't fix a lack of precision. That only works in the movies, where you can "enhance" an image hundreds of times ;) At some point you actually need to increase the sample rate (resolution) of the actual data to get anything meaningful happening. \$\endgroup\$ – Andon M. Coleman Aug 15 '15 at 21:50
6
\$\begingroup\$

Temporal Aliasing

As Andon M. Coleman is stating out in the comments what you describe is called temporal aliasing.

Temporal aliasing is due to a too low sampling rate of the scene compared to the the transformation speed of one or more objects within the same scene. In other words if an Object of the scene is more often updated (transformation speed to high) compared to the to the number of frames per second (sampling rate to low) temporal aliasing artefacts are appearing and the Object/s seem/s to jump around.


To avoid temporal aliasing you have to increase the sampling rate aka your FPS without increasing the transformation speed( your number of update calls ).

One way of doing this, see this example here: Vittoria Romeo's Tutorials

            while(running)
            {
                auto timePoint1(chrono::high_resolution_clock::now());

                window.clear(Color::Black);

                inputPhase();
                updatePhase();
                drawPhase();        

                auto timePoint2(chrono::high_resolution_clock::now());
                auto elapsedTime(timePoint2 - timePoint1);
                FrameTime ft{chrono::duration_cast<
                    chrono::duration<float, milli>>(elapsedTime).count()};

                lastFt = ft;

                auto ftSeconds(ft / 1000.f);
                auto fps(1.f / ftSeconds);
            }   

The key is now to take a close look into the updatePhase:

void updatePhase()
        {

        // If `currentSlice` is greater or equal than `ftSlice`,
        // we update our game logic and decrease `currentSlice` by
        // `ftSlice` until `currentSlice` becomes less than `ftSlice`.
        // Basically, if `currentSlice` is three times as big as `ftSlice`,
        // we update our game logic three times.

            currentSlice += lastFt;
            for(; currentSlice >= ftSlice; currentSlice -= ftSlice)
            {   
                //logic
                someupdatefunction(FixedtimeStep)
            }
        }

What we do is to divide our time in different slices:

 |............|............|............|..........
 |            |            |            |
 \-> slice    \-> slice    \-> slice    \-> slice

And, every frame, we will call update(mFT) "n" times, where "n" is the number of slices we passed through with our last frametime. Example:

       v-----+frametime---+--v
 |............|............|............|..........
 |            |            |            |
 \-> slice    \-> slice    \-> slice    \-> slice

In the above example, in the time it took to process a single frame, we went over two different slices. We will then call update(mFT) twice in the same frame.

No matter how big or how small or last frametime was, we will always call update(mFT) in fixed intervals (our slices). If the game goes extremely fast, we will completely skip the updating phase during certain frames. If the game goes extremely slow, we will probably need to update multiple times during a single frame. This method allows fine control over our movement precision, and guarantees the same behavior with any FPS.

This explanation is from Vittorio Romeo. You will find a complete tutorial how to implement this there via source code or Video. Vittoria Romeo's Tutorial

\$\endgroup\$
  • \$\begingroup\$ I am doing exactly what you suggested, it is similar to what Glenn Fiedler suggested but i am still getting jumpy results for large fps changes. \$\endgroup\$ – Buddy Aug 15 '15 at 16:48
  • \$\begingroup\$ can you maybe show us the relevant code it could help to solve your problem \$\endgroup\$ – ExOfDe Aug 15 '15 at 16:50
  • \$\begingroup\$ I have not tested it but i assume the difference i do not see this behaviour with my loop is because i define the "slice" size for my inner logic loop and i compare my "accumulator" (currentslice) not with the fixed timestep like you did but instead with the desired slice size. This is the key. \$\endgroup\$ – ExOfDe Aug 15 '15 at 17:05
  • 1
    \$\begingroup\$ @EnesBattal: If that's necessary, then your only option is to increase the sample frequency to reduce temporal aliasing. Interpolation never fixes aliasing problems, it only hides them. To increase sample frequency, cut your FIXED_TIME_STEP value down. That's effectively what the snippet in this answer does, only it attempts to solve this problem dynamically instead of trying to pick one value that's supposed to work across all framerates. I like ExOfDe's solution, personally. Tuning FIXED_TIME_STEP using hand-picked constant values is laborious and not very flexible. \$\endgroup\$ – Andon M. Coleman Aug 16 '15 at 12:31
  • 1
    \$\begingroup\$ Nevermind. My rubber duckie found it :) \$\endgroup\$ – ChocoMan Jul 14 '16 at 7:43

Not the answer you're looking for? Browse other questions tagged or ask your own question.