Возможна ли запись событий с учетом времени? - PullRequest
0 голосов
/ 06 июня 2011

Основной вопрос

Есть ли способ записи событий при воспроизведении в чувствительной ко времени (независимой от частоты кадров) системе?

Любая помощь, включая простое «Нет, извините, что это невозможно», будет принята с благодарностью. За последние несколько выходных я потратил на это почти 20 часов, и я схожу с ума.

Полная информация

В настоящее время это нацелено на игру, но библиотеки, которые я пишу, разработаны более общими, и эта концепция применима не только к моему кодированию на C ++.

У меня есть некоторый код, который выглядит функционально похожим на это ... (он написан на C ++ 0x, но я использую некоторые возможности, чтобы сделать его более компактным)

void InputThread()
{
    InputAxisReturn AxisState[IA_SIZE];
    while (Continue)
    {
        Threading()->EventWait(InputEvent);
        Threading()->EventReset(InputEvent);

        pInput->GetChangedAxis(AxisState);

        //REF ALPHA

        if (AxisState[IA_GAMEPAD_0_X].Changed)
        {
             X_Axis = AxisState[IA_GAMEPAD_0_X].Value;
        }
    }
}

И у меня есть отдельная тема, которая выглядит следующим образом ...

//REF BETA
while (Continue) 
{
    //Is there a message to process? 
    StandardWindowsPeekMessageProcessing();

    //GetElapsedTime() returns a float of time in seconds since its last call
    UpdateAll(LoopTimer.GetElapsedTime());
}

Теперь я хотел бы записать входные события для воспроизведения для тестирования и некоторые ограниченные функции воспроизведения.

Я могу легко записать события с точной синхронизацией, просто вставив следующий код, где я пометил // REF ALPHA

//REF ALPHA
EventRecordings.pushback(EventRecording(TimeSinceRecordingBegan, AxisState));

Реальная проблема заключается в их воспроизведении. Мой LoopTimer обладает чрезвычайно высокой точностью благодаря высокопроизводительному счетчику (QueryPreformanceCounter). Это означает, что почти невозможно достичь той же разницы во времени, используя код, как показано ниже, вместо // REF BETA

// REF BETA
NextEvent = EventRecordings.pop_back()
Time TimeSincePlaybackBegan;
while (Continue) 
{
    //Is there a message to process? 
    StandardWindowsPeekMessageProcessing();

    //Did we reach the next event?
    if (TimeSincePlaybackBegan >= NextEvent.TimeSinceRecordingBegan)
    {
        if (NextEvent.AxisState[IA_GAMEPAD_0_X].Changed)
        {
             X_Axis = NextEvent.AxisState[IA_GAMEPAD_0_X].Value;
        }

        NextEvent = EventRecordings.pop_back();
    }

    //GetElapsedTime() returns a float of time in seconds since its last call
    Time elapsed = LoopTimer.GetElapsedTime()
    UpdateAll(elapsed);
    TimeSincePlabackBegan += elapsed;
}

Проблема с этим подходом заключается в том, что вы почти никогда не попадете точно в одно и то же время, поэтому у вас будет несколько микросекунд, при которых воспроизведение не соответствует записи.

Я также попробовал привязку событий. Вроде сбивающего с толку термина, но в основном, если TimeSincePlaybackBegan> NextEvent.TimeSinceRecordingBegan, тогда TimeSincePlaybackBegan = NextEvent.TimeSinceRecordingBegan и ElapsedTime были изменены для соответствия.

У него были некоторые интересные побочные эффекты, которые можно было бы ожидать (например, некоторое замедление), но, к сожалению, это все равно приводило к десинхронизации воспроизведения.

Для получения дополнительной информации - и, возможно, причина, по которой мой подход к привязке времени не сработал - я использую BulletPhysics где-то в этом вызове UpdateAll. Вроде как это ...

void Update(float diff)
{
    static const float m_FixedTimeStep = 0.005f;
    static const uint32 MaxSteps = 200;

    //Updates the fps
    cWorldInternal::Update(diff);

    if (diff > MaxSteps * m_FixedTimeStep)
    {
        Warning("cBulletWorld::Update() diff > MaxTimestep. Determinism will be lost");
    }

    pBulletWorld->stepSimulation(diff, MaxSteps, m_FixedTimeStep);
}

Но я также пытался с pBulletWorkd-> stepSimulation (diff, 0, 0), который в соответствии с http://www.bulletphysics.org/mediawiki-1.5.8/index.php/Stepping_the_World должен был сделать свое дело, но все равно безрезультатно.

1 Ответ

0 голосов
/ 26 июня 2011

Отвечая на мой вопрос для всех, кто сталкивается с этим.

В основном, если вы хотите детерминированную запись и воспроизведение, вам нужно заблокировать частоту кадров.Если система не может обработать частоту кадров, вы должны ввести замедление или асинхронизацию риска.

После двух недель дополнительных исследований я решил, что это просто невозможно из-за неадекватности с плавающей запятой и того факта, что числа с плавающей запятойне обязательно являются ассоциативными.

Единственное решение, имеющее детерминированный механизм, который опирается на числа с плавающей запятой, - это иметь стабильную и фиксированную частоту кадров.Любое изменение частоты кадров в течение длительного времени приведет к десинхронизации воспроизведения.

...