1
\$\begingroup\$

I've searched around the Internet, and eventually read a suggested article, "Fix your Timestep!". In accordance with the article, I came up with an update method, but I still have problems. Whenever I instantiate more objects, in my scene, I get much slower physical interaction. I've fixed other sub-systems, that they were wasting cycles during the update process, and I've tracked my physics performance drop to this point. I think the way I'm updating my physics is somehow wrong, because I'm using a fixed timing of 1.0 / 60.0 for my Box2D engine.

What are the mistakes I'm making in my update process? What is the correct way to update a physics frame rate? Here is my code:

void Core::Update()
{
    // Input
    this->cInput->Update();

    // Physics
    this->cPhysics->Update();

    // Keep frame rate
    static const double desiredTime = 1.0 / 60.0;
    static double currentTime = (double)(GetTickCount());
    static double accumulator = 0.0;

    double newTime = (double)(GetTickCount());
    double frameTime = newTime - currentTime;

    if(frameTime > 0.25){ frameTime = 0.25; }
    currentTime = newTime;

    accumulator += frameTime;

    while(accumulator >= desiredTime)
    {
        // Input
        this->cInput->Update();

        // Physics
        this->cPhysics->Update(desiredTime);

        // Scripts
        this->cScripts->Update();

        accumulator -= desiredTime;
    }

I've read that you shouldn't tie your physics frame rate to the render frame rate, so I use this->cPhysics->Update();. I've used my previous approach, but with a slight change; I'm not sure if what I'm doing is right, but it solved my performance issue. First, I changed currentTime to get time in milliseconds, instead of seconds. At the end, I've moved all of my update code to a time step loop, except for the renderers update. I still do not know if this is the correct way to go.

\$\endgroup\$
  • 1
    \$\begingroup\$ See: gafferongames.com/game-physics/fix-your-timestep \$\endgroup\$ – Vaughan Hilts Aug 3 '13 at 18:01
  • \$\begingroup\$ @VaughanHilts that's the article that I've already checked. \$\endgroup\$ – MahanGM Aug 3 '13 at 18:04
  • \$\begingroup\$ This psuedo code makes no sense, and I feel you don't understand the purpose of the Fix Your Timestep article. The whole point of the Fix Your Timestep article is to allow a physics library to step at a frequency differently from which you render. This is a nice thing to have, but not required. Here's another resource for timestepping + interpolation: gamedev.tutsplus.com/tutorials/implementation/… Of course you'll have a bottleneck here, you're doing your entire engine loop here. For optimization you'll need more specific info. \$\endgroup\$ – RandyGaul Aug 3 '13 at 19:40
  • \$\begingroup\$ @RandyGaul I'm impressed with your article. This is part of an actual code that I'm using and Core::Update is called by a higher level loop which is the game loop, anyway, I can't understand why you're saying you're doing your entire engine loop here because I have no idea how else I can do this! And I've profiled most of other parts and I know my physics update rate is the problem. I'll check your article. \$\endgroup\$ – MahanGM Aug 3 '13 at 23:45
  • \$\begingroup\$ @MahanGM Well I mean, the bottleneck must be here because you're doing so much in this loop. So if you wanted to analyze performance (assuming your timestepping code was corrected), you would need to know more about the specifics of the code called within the timestepping loop. If you need more help you can always just respond here and I'll take a look. \$\endgroup\$ – RandyGaul Aug 4 '13 at 0:28
1
\$\begingroup\$

The problem lies here

    static double currentTime = (double)time(NULL);
    static double accumulator = 0.0;

    double newTime = (double)time(NULL);

your currentTime and newTime are roughtly the same that way, this can't work.

you need to measure the time you needed for one frame (the last frame) and sleep the remaining time till you hit your 1.0s/60s mark. Don't forget that the sleeping doesn't sleep exactly the amount of time you passed in so you need to compesate for that.

An optional way to get the used time for the frames is to use a sliding window approach for all frame times and sum the times and divide by the count.

Another important oint is to limit your delta-time you actually measured (say to 0.2 seconds) for avoiding instabilities.

Edit 1 Example code to illustrate it

private double Time = 0.0;

private double deltaTArray[10];
private unsigned int deltaTArrayI;

// NOTE< this->currentTime must be set once before this is called >


void Core::Update()
{
    // Input
    this->cInput->Update();

    double newTime = (double)time(NULL);

    double deltaT = newTime - this->currentTime;

    this->currentTime = newTime;

    deltaT = min(deltaT, 0.25); // because of stability

    this->deltaTArray[this->deltaTArrayI] = deltaT;

    (this->deltaTArrayI)++;
    this->deltaTArrayI = this->deltaTArrayI % 10;

    // calculate delta T as average of the sliding window
    double deltaTAverage = 0.0;

    for( unsigned int i = 0; i < 10; ++i )
    {
        deltaTAverage += this->deltaTArray[i];
    }

    deltaTAverage = deltaTAverage / (double)10;

    // Physics
    this->cPhysics->Update(deltaTAverage);

    // Keep frame rate
    sleep(max((1.0/60.0)-deltaTAverage, 0));

    // Render
    this->cRender->Update();
}
\$\endgroup\$
  • \$\begingroup\$ Can you give me a coding example? \$\endgroup\$ – MahanGM Aug 3 '13 at 18:06
  • \$\begingroup\$ According to this article altdevblogaday.com/2012/06/05/in-praise-of-idleness, do I really have to use Sleep()? \$\endgroup\$ – MahanGM Aug 3 '13 at 18:30
  • \$\begingroup\$ @MahanGM the article has nothing to do with it because it is about syncronisation/waiting of multiple threads, i don't do such a thing, it is perfectly fine. Sleep doesn't do busy waiting. \$\endgroup\$ – Quonux Aug 3 '13 at 18:36
  • \$\begingroup\$ Thank you for your time. I tested your code and it seems I still got my problem. Actually my problem is with the physics frame rate. If I set it to 1.0 / 30.0 it'll run two times faster and the amount of objects that I should create to test my performance would become two times larger. This means the timing of my physics engine has a direct relation on my issue. \$\endgroup\$ – MahanGM Aug 3 '13 at 18:42
  • \$\begingroup\$ do you want to use a fixed timestep or a dynamic for your physics engine, i updated my code for the dynamic timestep \$\endgroup\$ – Quonux Aug 3 '13 at 19:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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