Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Interpolating between 2 sf::Transforms  (Read 4897 times)

0 Members and 1 Guest are viewing this topic.

foobarbaz

  • Jr. Member
  • **
  • Posts: 53
    • View Profile
Interpolating between 2 sf::Transforms
« on: February 23, 2014, 09:22:04 pm »
Hi guys,

Is it possible to interpolate between 2 sf::Transform objects? I'm trying to implement the smoothing for my locked time step http://gafferongames.com/game-physics/fix-your-timestep/. I have had the locked time step there for a while, but the visual jitter is really bothering me now :P.

This would be trivial in a system where entities cannot be parented to each other, but in my case you can parent transforms, so I have a calculated global transform for every entity, and would like to interpolate between the current global transform and the previous one.

Is it possible to interpolate between 2 sf::Transform objects? If so, any hints as to how you'd do it?
Thanks in advance

EDIT:

Woops, I meant to post this in graphics, if Laurent wants to move it :P
« Last Edit: February 23, 2014, 09:45:05 pm by tedsta »

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: Interpolating between 2 sf::Transforms
« Reply #1 on: February 23, 2014, 09:31:42 pm »
It's impossible in general, or at least it wouldn't always yield what you expect. Assume a transform mirrors an image with respect to an axis (reflection). What would half the transform be?

What you can do, is extract affine transforms like translation, rotation and scale, interpolate them, and recompose them to a new transform matrix. An alternative way is to apply the matrix power, but then you need a linear algebra library.
« Last Edit: February 23, 2014, 09:37:59 pm by Nexus »
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

foobarbaz

  • Jr. Member
  • **
  • Posts: 53
    • View Profile
Re: Interpolating between 2 sf::Transforms
« Reply #2 on: February 23, 2014, 09:53:45 pm »
What you can do, is extract affine transforms like translation, rotation and scale, interpolate them, and recompose them to a new transform matrix.

That's what I was afraid of. I'll have to recalculate the global transforms of all entities that moved and all of their children every frame. But I suppose I have to bite the bullet.

Thanks

zsbzsb

  • Hero Member
  • *****
  • Posts: 1409
  • Active Maintainer of CSFML/SFML.NET
    • View Profile
    • My little corner...
    • Email
Re: Interpolating between 2 sf::Transforms
« Reply #3 on: February 23, 2014, 09:57:51 pm »
tedsta, maybe you should show a complete example that seems to jitter. Because in my experience I have never seen any issues when omitting the interpolation part of that game loop.
Motion / MotionNET - Complete video / audio playback for SFML / SFML.NET

NetEXT - An SFML.NET Extension Library based on Thor

eigenbom

  • Full Member
  • ***
  • Posts: 228
    • View Profile
Re: Interpolating between 2 sf::Transforms
« Reply #4 on: February 23, 2014, 11:22:02 pm »
It definitely jitters if you run your physics at a lower framerate than your renderer, which is sometimes necessary. I agree with nexus and would split the important components out, like translation and rotation.

foobarbaz

  • Jr. Member
  • **
  • Posts: 53
    • View Profile
Re: Interpolating between 2 sf::Transforms
« Reply #5 on: February 23, 2014, 11:23:01 pm »
tedsta, maybe you should show a complete example that seems to jitter. Because in my experience I have never seen any issues when omitting the interpolation part of that game loop.

It's very subtle, and becomes more noticeable as the actual framerate gets lower. You can play around with the framerate cap and with and without smoothing. Maybe I've just gone crazy and my eyes deceive me, but I think the smoothing helps :P

#include <SFML/System/Vector2.hpp>
#include <SFML/Window/Keyboard.hpp>
#include <SFML/Window/Event.hpp>
#include <SFML/Graphics/RenderWindow.hpp>
#include <SFML/Graphics/RectangleShape.hpp>

const float lockStep = 1.f/60.f;

void step(sf::Vector2f& state, const float dt);

int main()
{
    // Setup the window
    sf::RenderWindow window;
    window.create(sf::VideoMode(800, 600), "SFML Lockstep Example");

    // Player states
    sf::Vector2f oldState;
    sf::Vector2f curState;

    // Player object
    sf::RectangleShape player(sf::Vector2f(32, 32));
    player.setFillColor(sf::Color::Red);

    // Delta time stuff
    sf::Clock dtClock;
    float dtAccum = 0.f;

    // Main loop
    while (window.isOpen())
    {
        // Framerate cap
        while (dtClock.getElapsedTime().asSeconds() < 1.f/50.f);

        sf::Event event;
        while (window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
                window.close();
        }

        // Calculate dt
        float dt = dtClock.restart().asSeconds();

        // Add to the dt accumulator
        dtAccum += dt;

        // While there's unsimulated time
        while (dtAccum >= lockStep)
        {
            dtAccum -= lockStep;
            oldState = curState;
            step(curState, lockStep);
        }

        float accumStepRatio = dtAccum / lockStep;

        sf::Vector2f state = curState*accumStepRatio + oldState*(1.f - accumStepRatio);

        // Smoothed state
        player.setPosition(state);

        // Non smoothed
        //player.setPosition(curState);

        window.clear(sf::Color::Black);
        window.draw(player);
        window.display();
    }

    return 0;
}

void step(sf::Vector2f& state, const float dt)
{
    if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::W))
        state.y -= 100.f*dt;
    if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::S))
        state.y += 100.f*dt;
    if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::A))
        state.x -= 100.f*dt;
    if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::D))
        state.x += 100.f*dt;
}
 

EDIT:

Also becomes more noticeable as speed increases. Try upping the speed to 200 pixels per second.
« Last Edit: February 23, 2014, 11:36:02 pm by tedsta »

zsbzsb

  • Hero Member
  • *****
  • Posts: 1409
  • Active Maintainer of CSFML/SFML.NET
    • View Profile
    • My little corner...
    • Email
Re: Interpolating between 2 sf::Transforms
« Reply #6 on: February 23, 2014, 11:32:33 pm »
It definitely jitters if you run your physics at a lower framerate than your renderer, which is sometimes necessary.

Yes if you cap it low enough, but I always cap my update/physics code at 30-45Hz and never experience stuttering.

@tedsta Your problem comes from floating point inaccuracy. Handle your time with a time object all the way around and don't cast it away to a float until necessary.
Motion / MotionNET - Complete video / audio playback for SFML / SFML.NET

NetEXT - An SFML.NET Extension Library based on Thor