我正在尝试找到一种可靠的方法,以便能够准确设置我希望我的OpenGL应用程序在屏幕上呈现多少FPS。我可以通过休眠1000 / fps毫秒在某种程度上做到这一点,但这没有考虑渲染所需的时间。 将fps限制在所需数量的最一致方法是什么?
答案 0 :(得分:7)
您可以在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");
}
答案 1 :(得分:5)
由于OpenGL只是一个低级图形API,因此您不会直接在OpenGL中找到这样的内容。
但是,我认为你的逻辑有点缺陷。而不是以下:
你应该这样做:
这样一来,如果你只是等待你应该的数量,你应该每秒非常接近60(或任何你想要的)帧数。
答案 2 :(得分:5)
OpenGL本身没有任何允许限制帧率的功能。周期。
然而,在现代GPU上,有很多功能包括帧速率,帧预测等等。有一些John Carmack的问题,他推出了一些可用的功能。还有NVidia的自适应同步。
这对你意味着什么?把它留给GPU。假设绘图是完全不可预测的(就像你只坚持使用OpenGL时那样),自己定时事件并将逻辑更新(如物理)与绘图分开。这样,用户将能够从所有这些先进技术中受益,您不必再担心这一点。
答案 3 :(得分:2)
不要使用睡眠。如果这样做,那么应用程序的其余部分必须等待它们完成。
相反,请记录已经过了多少时间,并且仅在满足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;
}
答案 4 :(得分: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
(假设时间以秒为单位)。
这不会给你vsync,但意味着你的应用程序不会失控,这会影响物理计算(如果它们不是固定步骤),动画等等。只记得 睡眠后输入 !我尝试过平均帧时间,但到目前为止效果最好。
对于getElapsedTimeOfChoice()
,我使用的是here,即
clock_gettime(CLOCK_MONOTONIC, &ts);
QueryPerformanceCounter
答案 5 :(得分:0)
另一个想法是使用WaitableTimers(如果可能,例如在Windows上)
基本理念:
while (true)
{
SetWaitableTimer(myTimer, desired_frame_duration, ...);
PeekMsg(...)
if (quit....) break;
if (msg)
handle message;
else
{
Render();
SwapBuffers();
}
WaitForSingleObject(myTimer);
}
答案 6 :(得分:0)
一种简单的方法是使用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);
}