1

私はperlでオブジェクト指向OpenGLフレームワークを書いていますが、各フレーム間のDeltaTimeを測定すると、奇妙な問題が発生します。デルタ時間は時々(〜.5秒ごとに)負になるようです。これがgettimeofdayの問題なのか、GLUTがコールバックを呼び出す方法の問題なのかはわかりませんが、スプライトの動きが0.5秒ごとにわずかにジャンプするため、かなり面倒です。

これが私の過剰なメインループ関数です:

# This is called everytime in the main glut loop
sub Tick
{
    my $this = shift;
    my ($now, $dt);

    $now = gettimeofday;
    $dt = $now - $this->{_oldTime};

    if ($dt < 0)
    {
        my $dterr;

        $dterr = $now - $this->{_oldErrorTime};

        print "WTF! We just encountered a time paradox! " . 
            "This function was last called $dt seconds ago...\n" .
            "Current time: $now, Last call: $this->{_oldTime}\n" .
            "We already encountered this error $dterr seconds ago.\n\n";

        $this->{_oldErrorTime} = $now;
    }

    $this->{_oldTime} = $now;
    $this->{FPS} = 1.0 / $dt;

    $this->Update($dt);
    $this->DrawFrame($dt);
}

そして、これが出力です:

WTF!時間のパラドックスに遭遇しました!この関数の最後の呼び出しは-0.0171449184417725秒前です...現在の時刻:1340196716.27624、最後の呼び出し:1340196716.29339このエラーは0.482785940170288秒前に発生しました。

WTF!時間のパラドックスに遭遇しました!この関数の最後の呼び出しは-0.0132658481579秒前です...現在の時刻:1340196716.74632、最後の呼び出し:1340196716.75959すでに0.470081090927124秒前にこのエラーが発生しました。

WTF!時間のパラドックスに遭遇しました!この関数は、最後に-0.011317 9683685303秒前に呼び出されました...現在の時刻:1340196717.21836、最後の呼び出し:1340196717.22968このエラーは0.472035884857178秒前に発生しました。

WTF!時間のパラドックスに遭遇しました!この関数の最後の呼び出しは-0.0152010917663574秒前です...現在の時刻:1340196717.68649、最後の呼び出し:1340196717.70169このエラーは0.468127012252808秒前に発生しました。

4

2 に答える 2

4

CLOCK_MONOTONICが必要です。Time ::HiResを参照してください。

于 2012-06-20T13:27:56.677 に答える
1

皆さんの回答のおかげで、私はこのクロスプラットフォームの単調ストップウォッチ機能を思いつきました。

use constant WIN32 =>   $^O eq "MSWin32";

our $QueryPerformanceCounter = undef;
our $QueryPerformanceFrequency = undef;
our $qpf = undef;

sub GetTime
{
    # Windows
    if (WIN32)
    {
        my ($count, @unpacked_count);

        require Win32::API;
        Win32::API->import();

        if (!$QueryPerformanceCounter || !$QueryPerformanceFrequency || !$qpf)
        {
            my ($freq, @unpacked_freq);

            $QueryPerformanceCounter = new Win32::API(
                "Kernel32", "QueryPerformanceCounter", [qw(P)], 'I')
            or Carp::croak("GLPerl::Utils::GetTime(): Failed to get QueryPerformanceCounter: " .
                Win32::FormatMessage(Win32::GetLastError()));

            $QueryPerformanceFrequency = new Win32::API(
                "Kernel32", "QueryPerformanceFrequency", [qw(P)], 'I')
            or Carp::croak("GLPerl::Utils::GetTime(): Failed to get QueryPerformanceFrequency: " .
                Win32::FormatMessage(Win32::GetLastError()));

            $freq = pack 'I2', 0;

            Carp::croak("GLPerl::Utils::GetTime(): QueryPerformanceFrequency call failed: " .
                Win32::FormatMessage(Win32::GetLastError()))
                unless ($QueryPerformanceFrequency->Call($freq));

            @unpacked_freq = reverse unpack 'I2', $freq;
            $qpf = $unpacked_freq[0] * 2**32 + $unpacked_freq[1];
        }

        $count = pack 'I2', 0;

        Carp::croak("GLPerl::Utils::GetTime(): QueryPerformanceCounter call failed: " .
            Win32::FormatMessage(Win32::GetLastError()))
            unless ($QueryPerformanceCounter->Call($count));

        @unpacked_count = reverse unpack 'I2', $count;
        return ($unpacked_count[0] * 2**32 + $unpacked_count[1]) / $qpf;
    }

    # Linux
    require Time::HiRes;
    Time::HiRes->import(qw(clock_gettime));
    eval "return clock_gettime(CLOCK_MONOTONIC);";
}
于 2012-06-20T14:39:12.150 に答える