0

基本的な質問

時間に敏感な (フレームレートに依存しない) システム内で再生をイベント記録する方法はありますか?

簡単な「申し訳ありませんが不可能です」など、どんな助けでも大歓迎です。私は過去数週末にわたってこれに取り組んでほぼ 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 が適切に変更されました。

予想されるいくつかの興味深い副作用 (速度低下など) がありましたが、残念ながら、それでも再生の非同期化が発生しました。

いくつかの背景について、そしておそらく私のタイム スナップ アプローチが機能しなかった理由として、私は UpdateAll 呼び出しのどこかで BulletPhysics を使用しています。なんかこんな...

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

しかし、 http://www.bulletphysics.org/mediawiki-1.5.8/index.php/Stepping_the_Worldによれば、 pBulletWorkd->stepSimulation(diff, 0, 0) も試してみました.

4

1 に答える 1

0

これに出くわした他の人のために、私自身の質問に答えます。

基本的に、確定的な記録と再生が必要な場合は、フレームレートをロックする必要があります。システムがフレームレートを処理できない場合は、スローダウンを導入するか、dsyncronization のリスクを冒す必要があります。

2 週間の追加調査の後、浮動小数点数が不十分であり、浮動小数点数が必ずしも連想的ではないという事実のために、それは不可能であると判断しました。

浮動小数点数に依存する決定論的エンジンを使用する唯一の解決策は、安定した固定フレームレートを使用することです。フレームレートが変化すると、長期間にわたって再生が非同期になります。

于 2011-06-26T18:33:56.723 に答える