控制 OpenGL 应用程序中的 FPS 限制

问题描述 投票:0回答:7

我正在尝试找到一种可靠的方法来准确设置我的 OpenGL 应用程序应渲染到屏幕上的 FPS。在某种程度上,我可以通过休眠 1000/fps 毫秒来做到这一点,但这没有考虑渲染所需的时间。 将 FPS 限制为所需量的最一致的方法是什么?

opengl 3d frame-rate
7个回答
10
投票

您可以使用 OpenGL 中的

wglSwapIntervalEXT
同步到 vblank。这不是很好的代码,但它确实有效。

http://www.gamedev.net/topic/360862-wglswapintervalext/#entry3371062

bool WGLExtensionSupported(const char *extension_name) {
    PFNWGLGETEXTENSIONSSTRINGEXTPROC _wglGetExtensionsStringEXT = NULL;

    _wglGetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC)wglGetProcAddress("wglGetExtensionsStringEXT");

    if (strstr(_wglGetExtensionsStringEXT(), extension_name) == NULL) {
        return false;
    }

    return true;
}

PFNWGLSWAPINTERVALEXTPROC       wglSwapIntervalEXT = NULL;
PFNWGLGETSWAPINTERVALEXTPROC    wglGetSwapIntervalEXT = NULL;

if (WGLExtensionSupported("WGL_EXT_swap_control"))
{
    // Extension is supported, init pointers.
    wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT");

    // this is another function from WGL_EXT_swap_control extension
    wglGetSwapIntervalEXT = (PFNWGLGETSWAPINTERVALEXTPROC)wglGetProcAddress("wglGetSwapIntervalEXT");
}

9
投票

由于 OpenGL 只是一个低级图形 API,因此您不会在 OpenGL 中直接找到类似的内置内容。

不过,我觉得你的逻辑有点问题。而不是以下内容:

  1. 画框
  2. 等待 1000/fps 毫秒
  3. 重复

你应该这样做:

  1. 启动定时器
  2. 画框
  3. 停止计时器
  4. 等待(1000/fps - (停止 - 开始))毫秒
  5. 重复

这样,如果您只等待应有的时间,那么您最终应该非常接近每秒 60 帧(或任何您想要的目标)。


5
投票

不要使用睡眠。如果您这样做,那么您的申请的其余部分必须等待他们完成。

相反,跟踪已经过去了多少时间并仅在满足 1000/fps 时进行渲染。如果没有达到计时器,请跳过它并做其他事情。

在单线程环境中,很难确保您以精确的 1000/fps 进行绘制,除非这绝对是您所做的唯一事情。一种更通用和更可靠的方法是在单独的线程中完成所有渲染,并在计时器上启动/运行该线程。这是一个更复杂的问题,但会让您最接近您的要求。

此外,跟踪发出渲染所需的时间将有助于动态调整渲染的时间。

static unsigned int render_time=0;
now = timegettime();
elapsed_time = last_render_time - now - render_time;
if ( elapsed_time > 1000/fps ){
    render(){
        start_render = timegettime();

        issue rendering commands...

        end_render = timegettime();
        render_time = end_render - start_render;
    }
    last_render_time = now;
}

3
投票

OpenGL 本身没有任何允许限制帧速率的功能。期间。

然而,在现代 GPU 上有很多功能,涵盖帧率、帧预测等。John Carmack 提出了一个问题,他推动为其提供一些功能。还有 NVidia 的自适应同步。

这一切对你来说意味着什么?将其留给 GPU 处理。假设绘图是完全不可预测的(就像您只使用 OpenGL 时应该做的那样),请自行计时事件并将逻辑更新(例如物理)与绘图分开。这样用户将能够从所有这些先进技术中受益,而您不必再担心这一点。


2
投票

一个简单的方法是使用 GLUT。这段代码可以大致完成这项工作。

static int redisplay_interval;

void timer(int) {
    glutPostRedisplay();
    glutTimerFunc(redisplay_interval, timer, 0);
}

void setFPS(int fps)
{
    redisplay_interval = 1000 / fps;
    glutTimerFunc(redisplay_interval, timer, 0);
}

1
投票

将其放在绘制和调用交换缓冲区之后:

//calculate time taken to render last frame (and assume the next will be similar)
thisTime = getElapsedTimeOfChoice(); //the higher resolution this is the better
deltaTime = thisTime - lastTime;
lastTime = thisTime;

//limit framerate by sleeping. a sleep call is never really that accurate
if (minFrameTime > 0)
{
    sleepTime += minFrameTime - deltaTime; //add difference to desired deltaTime
    sleepTime = max(sleepTime, 0); //negative sleeping won't make it go faster :(
    sleepFunctionOfChoice(sleepTime);
}

如果您想要 60fps,

minFrameTime = 1.0/60.0
(假设时间以秒为单位)。

这不会为您提供垂直同步,但意味着您的应用程序不会失控,这可能会影响物理计算(如果它们不是固定步长)、动画等。只需记住处理输入 睡眠后!我尝试过平均帧时间,但到目前为止效果最好。

对于

getElapsedTimeOfChoice()
,我使用这里提到的,即


0
投票

另一个想法是使用 WaitableTimers(如果可能,例如在 Windows 上)

基本理念:

while (true) 
{ 
    SetWaitableTimer(myTimer, desired_frame_duration, ...); 
    PeekMsg(...) 
    if (quit....) break; 
    if (msg)
        handle message; 
    else 
    { 
        Render(); 
        SwapBuffers();
    }
    WaitForSingleObject(myTimer); 
}

更多信息:如何限制 fps 信息

© www.soinside.com 2019 - 2024. All rights reserved.