定时流动动画(OpenGL)

时间:2012-02-10 12:12:17

标签: c opengl

我正在用opengl和C编写一个小游戏。 我遇到了一个问题: 由于剪辑...我的动画(实际上基于glutTimerFunc)没有一个恒定的fps。 变量fps不是问题,但是动画会受到影响,所以它不对应于时间,那么:fps1,pos1; FPS2,POS2; fps3,POS3 ... 但如果fps不规则,那么动画就不会。 我会实现它:fps1,pos1;(如果没有绘制fps1)fps2,pos1; (fps1绘图已结束,所以现在,因为我跳过了一个帧)fps3,pos3。

我该怎么办?我会使用clock()函数,但它始终为0

ps:如何强制在opengl中使用v-sync?

1 个答案:

答案 0 :(得分:1)

OpenGL更新是否与垂直回扫同步将以特定于平台的方式进行通信,因为它与您的平台已将OpenGL绑定到自身相关。所以它是Mac上界面设计器的勾选框,在Windows上有一个名为WGL_EXT_swap_control的WGL扩展,在X11中有一个GLX扩展。

假设您有一些方法可以安装在垂直回扫时触发的回调(例如通过Mac上的CVDisplayLink;遗憾的是我没有使用Windows / Linux等效功能),并且您希望物理以每秒恒定的步数运行,你可以写出类似的东西:

void myRetraceFunction()
{
    static unsigned int timeError = 0;
    static unsigned int timeOfLastFrame = 0;

    unsigned int timeNow = getTimeNow(); // assume this returns in ms

    // Get time since last frame.
    // Since we ignore overflow here, we don't care that the result of
    // getTimeNow presumably overflows.
    unsigned int timeSinceLastFrame = timeNow - timeOfLastFrame;

    // Store this so that we get correct results next time around.
    timeOfLastFrame = timeNow;

    // Establish the number of times to update physics per second, as the
    // name says. So supposing it has been 0.5 of a second since we last
    // drew, we'd want to perform 0.5*200 physics updates
    const unsigned int numberOfTimesToUpdatePhysicsPerSecond = 200;

    // calculate updates as (updatesPerSecond * timeSinceLastFrame / 1000),
    // because we're assuming time is in milliseconds and there are 1000
    // of them in a second. What we'll do though is preserve any amount we'd
    // lose by dividing here, so that errors balance themselves.
    //
    // We assume that timeSinceLastFrame will be small enough that we won't
    // overflow here.
    unsigned int timeSinceLastFrameNumerator =
          timeSinceLastFrame * numberOfTimesToUpdatePhysicsPerSecond
          + timeError;

    // calculate how much of the numerator we're going to lose to
    // truncation, so that we add it next frame and don't lose time
    timeError = timeSinceLastFrameNumerator % 1000;

    // calculate how many physics updates to perform
    unsigned int physicsUpdatesToPerform = timeSinceLastFrameNumerator / 1000;

    // do the physics work...
    while(physicsUpdatesToPerform--)
       updatePhysics();

    // ... and draw a frame
    drawFrame();
}

那个timeError的东西是为了规范舍入问题。例如。假设你以每秒70帧的速度运行,并希望物理更新每秒60次。如果您忽略了累积的错误,那么您实际上会在一秒钟内运行零物理更新,因为在每个时刻代码都会得出结论:自上一帧绘制以来的时间长度不足以使物理更新具有已被要求。如果你采用其他方式,你也会遇到别名问题,任何帧速率都不是物理更新速率的整数除数。

如果你没有一个明确的回扫函数,而是一个永久循环,它会推出帧但是会阻止垂直回扫,那么你就会写出同样的东西。

如果您根本无法阻止垂直回扫,则可以按目标帧速率安装计时器并假装是垂直回扫同步。你可以尽可能快地推出框架,但是你可能会对任何拥有笔记本电脑或其他机器的人抱怨,当粉丝来的时候很明显。