7

DirectX ベースのアプリケーションがあります。Now()そして最近、グラフィック エンジンのメイン ループ内から関数を呼び出すと、関数が間違った値を返すことがわかりました。グラフィックが開始されたときにアプリケーションで呼び出されると、エンジンが初期化される前に呼び出される値と別の値 (通常は前後に 2 ~ 3 分異なります) が返されます。

Now()function は Windows API 関数のラッパーであることがわかりましたGetLocalTime()。この関数の戻り値に何が影響するのか、誰でも指摘できますか? timeGetTime()アプリのメインループで関数を頻繁に使用していますが、それが問題の原因になる可能性はありますか? またCheckSyncronize()、メインループで関数を使用する必要があります...

何か案は?手がかりがありません... :(

メインループのコード:

    procedure Td2dCore.System_Run;
    var
        l_Msg: TMsg;
        l_Point: TPoint;
        l_Rect : TRect;
        l_Finish: Boolean;
    begin
        if f_WHandle = 0 then
        begin
            System_Log('Engine was not started!');
            Exit;
        end;

        if not Assigned(f_OnFrame) then
        begin
            System_Log('Frame function is not assigned!');
            Exit;
        end;

        // MAIN LOOP
        l_Finish := False;
        while not l_Finish do
        begin
            // dispatch messages
            if PeekMessage(l_Msg, 0, 0, 0, PM_REMOVE) then
            begin
                if l_Msg.message = WM_QUIT then
                    l_Finish := True;
                DispatchMessage(l_Msg);
                Continue;
            end;

            GetCursorPos(l_Point);
            GetClientRect(f_WHandle, l_Rect);
            MapWindowPoints(f_WHandle, 0, l_Rect, 2);
            f_MouseOver := f_MouseCaptured or (PtInRect(l_Rect, l_Point) and (WindowFromPoint(l_Point) = f_WHandle));
            if f_Active or f_DontSuspend then
            begin
                repeat
                    f_DeltaTicks := timeGetTime - f_Time0;
                    if f_DeltaTicks <= f_FixedDelta then
                        Sleep(1);
                until f_DeltaTicks > f_FixedDelta;
                //if f_DeltaTicks >= f_FixedDelta then
                begin
                    f_DeltaTime := f_DeltaTicks / 1000.0;

                    // if delay was too big, count it as if where was no delay
                    // (return from suspended state for instance)
                    if f_DeltaTime > 0.2 then
                        if f_FixedDelta > 0 then
                            f_DeltaTime := f_FixedDelta / 1000.0
                        else
                            f_DeltaTime := 0.01;

                    f_Time := f_Time + f_DeltaTime;

                    f_Time0 := timeGetTime;

                    if(f_Time0 - f_Time0FPS < 1000) then
                        Inc(f_FPSCount)
                    else
                    begin
                        f_FPS := f_FPSCount;
                        f_FPSCount := 0;
                        f_Time0FPS := f_Time0;
                    end;

                    f_OnFrame(f_DeltaTime, l_Finish);
                    if Assigned(f_OnRender) then
                        f_OnRender();
                    ClearQueue;
                    {
                    if (not f_Windowed) and (f_FixedFPS = D2D_FPS_VSYNC) then
                        Sleep(1);
                    }
                end;
                {
                else
                    if (f_FixedDelta > 0) and (f_DeltaTicks+3 < f_FixedDelta) then
                        Sleep(1);
                }
            end
            else
                Sleep(1);
            CheckSynchronize;
        end;
    end;

Now() はf_OnFrame()関数のどこかで呼び出されます。

4

4 に答える 4

12

最後に、解決策を見つけました。D3DCREATE_FPU_PRESERVEで D3D デバイスを作成するときにth フラグを指定する必要がありましたD3D.CreateDevice

それ以外の場合、そのフラグがない場合、すべての浮動小数点演算は単精度で実行されます。はTDateTime単純Doubleであり、Now()関数は日付値と時刻値の単純な加算で構成されているため、DirectX の「スマート」オーバーライドによってすべてが台無しになります。

問題が解決しました。それは確かにトリッキーなものでした。:)

于 2012-09-01T08:28:44.187 に答える
2

私は、OpenGL とシミュレーターと MapObjects でこれらの問題に遭遇することがあります。タイミングシーケンスは、機器間の違いであることがわかりました。これは、主題に光を当てる可能性のある2つのリンクです。

http://delphi.about.com/od/windowsshellapi/a/delphi-high-performance-timer-tstopwatch.htm Zarko Gajic の記事は、私がシリアル インターフェイス用に作成しなければならなかったタイマーの助けになりました。このコード例のバリエーションを使用して、タンク センサーのデータを取得しました。

http://msdn.microsoft.com/en-us/library/windows/desktop/ms644900%28v=vs.85%29.aspx これは、ソフトウェアでのハイエンド タイマーの使用に関する Microsoft の情報です。通常、タイマーはサイクル アウトし、同期されなくなります。この記事では、高解像度タイマーと待機可能タイマー オブジェクトの 2 つのタイマーについて説明します。High-Resolution は、シミュレーターに使用したタイマー バリアントです。

于 2012-08-27T20:28:05.817 に答える
1

私がコードから理解している限り、あなたは決定を下しています

              f_DeltaTicks := timeGetTime - f_Time0;

f_Time0 変数は、ループの後の段階で初期化されます。

                f_Time0 := timeGetTime;

ループへの最初の入り口で f_Time0 が必要な/必要な方法で初期化されないという単純なバグがある可能性があります。

于 2012-08-29T10:08:47.193 に答える