Шаг по времени в PhysX

Я пытаюсь определить временной шаг для моделирования физики в приложении PhysX, чтобы физика работала с одинаковой скоростью на всех машинах. Я хочу, чтобы физика обновлялась со скоростью 60 кадров в секунду, поэтому каждое обновление должно иметь дельту времени 1/60 секунды.

Мое приложение должно использовать GLUT. В настоящее время мой цикл настроен следующим образом.

Функция ожидания:

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

    glutPostRedisplay();
}

Частота кадров в данном случае не имеет особого значения — важна только скорость, с которой обновляется моя физика.

Моя функция рендеринга содержит следующее:

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

    simTimer += deltaTime;

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

Где:

Fl32 m_fps = 1.f/60.f

Однако это приводит к некоторым очень медленным обновлениям из-за того, что deltaTime кажется равным 0 в большинстве циклов (что на самом деле не должно быть возможным...). Я попытался переместить свои вычисления deltaTime в нижнюю часть моей функции рендеринга. , так как я думал, что, возможно, простой обратный вызов вызывался слишком часто, но это не решило проблему. Любые идеи, что я делаю неправильно здесь?


person fanatic    schedule 07.01.2014    source источник


Ответы (3)


На веб-сайте OpenGL мы видим, что glutGet(GLUT_ELAPSED_TIME) возвращает число переданные миллисекунды как int. Итак, если вы вызываете свой метод void GLUTGame::Idle() примерно 2000 раз в секунду, то время, прошедшее после одного такого вызова, составляет примерно 1000 * 1/2000 = 0,5 мс. Таким образом, более 2000 вызовов в секунду для void GLUTGame::Idle() приводят к тому, что glutGet(GLUT_ELAPSED_TIME) возвращает 0 из-за целочисленного округления.

person rwols    schedule 07.01.2014
comment
Принятие этого ответа, поскольку он привел меня к решению. Из-за того, что glutGet недостаточно точен, вместо этого я использовал clock() и clock_t из time.h, что, по-видимому, решает проблему. - person fanatic; 08.01.2014

Вероятно, вы добавляете очень маленькие числа к большим и получаете ошибки округления. Попробуй это:

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

  glutPostRedisplay();
}

Вы можете сделать что-то подобное в другом методе, если хотите.

person Sorin    schedule 07.01.2014
comment
Я пробовал это, но, похоже, это не имеет никакого значения. newElapstedTime, deltaTime и lastElapsedTime все двойные. Несмотря на то, что glutGet возвращает миллисекунды как int, я не вижу причин, по которым должны быть какие-либо проблемы с точностью. - person fanatic; 07.01.2014

Я ничего не знаю о GLUT или PhysX, но вот как заставить что-то выполняться с одинаковой скоростью (используя целые числа) независимо от того, насколько быстро работает игра:

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);
}

Где currentTime обновляется до timeGetTime при каждом прохождении игрового цикла, lastUpdateTime — это последнее обновление PhysX, а msPerUpdate — количество миллисекунд, которое вы назначаете каждому обновлению — 16 или 17 мс для 60 кадров в секунду.

Если вы хотите поддерживать коэффициенты обновления с плавающей запятой (что рекомендуется для физического приложения), то определите float timeMultiplier и обновляйте его каждый кадр следующим образом: timeMultiplier = (float)frameRate / desiredFrameRate; - где frameRate не требует пояснений, а desiredFramerate равно 60.0f, если вы хотите, чтобы физика обновлялась при 60 кадров в секунду. Для этого вам нужно обновить UpdatePhysX, приняв параметр float, на который умножаются все коэффициенты обновления.

person Proxy    schedule 07.01.2014