1

我正在用 perl 编写一个面向对象的 OpenGL 框架,当我测量每帧之间的 DeltaTime 时遇到了一个奇怪的问题。增量时间似乎每隔一段时间就会变为负数(每 ~.5 秒)。我不确定这是 gettimeofday 的问题,还是 GLUT 如何调用我的回调的问题,但这很烦人,因为它使我的精灵的运动每半秒略微跳跃一次。

这是我的过剩主循环功能:

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

这是输出:

哇!我们刚刚遇到了时间悖论!此函数上次调用 -0.017144 9184417725 秒前...当前时间:1340196716.27624,上次调用:1340196716.29339 我们已经在 0.482785940170288 秒前遇到此错误。

哇!我们刚刚遇到了时间悖论!此函数上次调用 -0.013265 84815979 秒前...当前时间:1340196716.74632,上次调用:1340196716.75959 我们已经在 0.470081090927124 秒前遇到此错误。

哇!我们刚刚遇到了时间悖论!此函数上次调用 -0.011317 9683685303 秒前...当前时间:1340196717.21836,上次调用:1340196717.22968 我们已经在 0.472035884857178 秒前遇到此错误。

哇!我们刚刚遇到了时间悖论!此函数上次调用 -0.015201 0917663574 秒前...当前时间: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 回答