Time Step in PhysX

1.2k views Asked by At

I'm trying to define a time step for the physics simulation in a PhysX application, such that the physics will run at the same speed on all machines. I wish for the physics to update at 60FPS, so each update should have a delta time of 1/60th of a second.

My application must use GLUT. Currently, my loop is set up as follows.

Idle Function:

void GLUTGame::Idle()
{
    newElapsedTime = glutGet(GLUT_ELAPSED_TIME);
    deltaTime = newElapsedTime - lastElapsedTime;
    lastElapsedTime = newElapsedTime;

    glutPostRedisplay();
}

The frame rate does not really matter in this case - it's only the speed at which my physics update that actually matters.

My render function contains the following:

void GLUTGame::Render()
{
    // Rendering Code

    simTimer += deltaTime;

    if (simTimer > m_fps)
    {
        m_scene->UpdatePhys(m_fps);
        simTimer = 0;
    }
}

Where:

Fl32 m_fps = 1.f/60.f

However, this results in some very slow updates, due to the fact that deltaTime appears to equal 0 on most loops (which shouldn't actually be possible...) I've tried moving my deltaTime calculations to the bottom of my rendering function, as I thought that maybe the idle callback was called too often, but this did not solve the issue. Any ideas what I'm doing wrong here?

3

There are 3 answers

1
rwols On BEST ANSWER

From the OpenGL website, we find that glutGet(GLUT_ELAPSED_TIME) returns the number of passed milliseconds as an int. So, if you call your void GLUTGame::Idle() method about 2000 times per second, then the time passed after one such call is about 1000 * 1/2000 = 0.5 ms. Thus more than 2000 calls per second to void GLUTGame::Idle() results in glutGet(GLUT_ELAPSED_TIME) returning 0 due to integer rounding.

1
Sorin On

Likely you're adding very small numbers to larger ones and you get rounding errors. Try this:

void GLUTGame::Idle()
{
  newElapsedTime = glutGet(GLUT_ELAPSED_TIME);
  timeDelta = newElapsedTime - lastElapsedTime;
  if (timeDelta <  m_fps) return;
  lastElapsedTime = newElapsedTime;

  glutPostRedisplay();
}

You can do something similar in the other method if you want to.

0
Proxy On

I don't now anything about GLUT or PhysX, but here's how to have something execute at the same rate (using integers) no matter how fast the game runs:

if (currentTime - lastUpdateTime > msPerUpdate)
{
    DWORD msPassed = currentTime - lastUpdateTime;
    int updatesPassed = msPassed / msPerUpdate;
    for (int i=0; i<updatesPassed; i++)
        UpdatePhysX(); //or whatever function you use
    lastUpdateTime = currentTime - msPassed + (updatesPassed * msPerUpdate);
}

Where currentTime is updated to timeGetTime every run through the game loop, lastUpdateTime is the last time PhysX updated, and msPerUpdate is the amount of milliseconds you assign to each update - 16 or 17 ms for 60fps

If you want to support floating-point update factors (which is recommended for a physics application), then define float timeMultiplier and update it every frame like so: timeMultiplier = (float)frameRate / desiredFrameRate; - where frameRate is self-explanatory and desiredFramerate is 60.0f if you want the physics updating at 60 fps. To do this, you have to update UpdatePhysX as taking a float parameter that it multiplies all update factors by.