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

uyhoqukh  于 2023-04-11  发布在  其他
关注(0)|答案(7)|浏览(311)

我试图找到一个可靠的方法来设置我希望我的OpenGL应用程序在屏幕上渲染多少FPS。我可以在一定程度上通过睡眠1000/fps毫秒来实现,但这并没有考虑渲染所需的时间。哪种方法可以将fps限制到所需的数量?

luaexgnf

luaexgnf1#

你可以在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");
}
kxkpmulp

kxkpmulp2#

由于OpenGL只是一个低级的图形API,你不会发现任何类似的东西直接内置在OpenGL中。
但是,我认为你的逻辑有点缺陷。而不是以下内容:
1.并条机
1.等待1000/fps毫秒
1.重复
你应该这样做:
1.启动计时器
1.并条机
1.停止计时器
1.等待(1000/fps -(停止-开始))毫秒
1.重复
这样,如果你只是等待你应该的量,你应该结束非常接近60(或任何你的目标)帧每秒。

1wnzp6jl

1wnzp6jl3#

不要使用sleeps。如果使用了,那么应用程序的其余部分必须等待它们完成。
相反,跟踪已经过去了多少时间,并仅在达到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;
}
0tdrvxhp

0tdrvxhp4#

OpenGL本身没有任何允许限制帧率的功能。
然而,在现代GPU上有很多功能,包括帧率,帧预测等。有约翰卡马克的问题,他推动使一些功能可用。还有英伟达的自适应同步。
这一切对你意味着什么?让GPU来决定吧。假设绘图是完全不可预测的(当你只使用OpenGL时,你应该这样做),自己计时事件,并将逻辑更新(如物理)与绘图分开。这样用户就可以从所有这些先进技术中受益,你就不必再担心了。

oyxsuwqo

oyxsuwqo5#

一个简单的方法是使用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);
}
erhoui1w

erhoui1w6#

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

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

如果你想要60 fps,minFrameTime = 1.0/60.0(假设时间以秒为单位)。
这不会给予你vsync,但将意味着你的应用程序不会失控,这可能会影响物理计算(如果他们不是固定的步骤),动画等。只要记住处理输入 * 后 * 睡眠!我已经尝试尝试平均帧时间,但这是最好的工作到目前为止。
对于getElapsedTimeOfChoice(),我使用前面提到的here,即

cvxl0en2

cvxl0en27#

另一个想法是使用WaitableTimers(如果可能的话,例如在Windows上)
基本理念:

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

更多信息:How to limit fps information

相关问题