我试图找到能够设置正是我想要多少FPS我的OpenGL应用程序呈现在屏幕上了坚实的方法。 我可以睡1000 / FPS毫秒这样做是为了在一定程度上,但是这并没有考虑到需要渲染的时间。 这是限制FPS所需量的最一致的方式?
Answer 1:
你可以在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");
}
Answer 2:
由于OpenGL是只是一个低级别的图形API,你不会找到像这样直接内置OpenGL的东西。
不过,我觉得你的逻辑是有点瑕疵。 而不是以下内容:
- 画框架
- 等待1000 / FPS毫秒
- 重复
你应该做这个:
- 启动计时器
- 画框架
- 停止计时器
- 等待(1000 / FPS - (停止 - 启动))毫秒
- 重复
这样,如果你只等着正是你要的金额,你应该结束了非常接近60(或者任何你瞄准)帧每秒。
Answer 3:
OpenGL的本身不具有允许限制帧数的任何功能。 期。
然而,在现代GPU有很多的功能覆盖帧率,帧预测,等等有约翰·卡马克的问题,他被推到做一些功能,它可用。 还有的NVidia的自适应同步。
这是什么都意味着你吗? 离开,高达GPU。 假设绘图是完全不可预测的(如你应该坚持只OpenGL的时候),时间事件自己,保持逻辑的更新(如物理)从图纸中分离出来。 用户通过这种方式就能从所有这些先进的技术中获益,你将不必担心这个问题了。
Answer 4:
不要使用休眠。 如果这样做,那么你的应用程序的其余部分必须等待他们完成。
取而代之的是,跟踪有多少时间已经过去了,在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;
}
Answer 5:
将这个图纸和呼叫交换缓冲区后:
//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()
我用什么提到这里 ,这是
- LINUX:
clock_gettime(CLOCK_MONOTONIC, &ts);
- WINDOWS:
QueryPerformanceCounter
Answer 6:
另一个想法是使用WaitableTimers(如果可能,例如在Windows上)
基本思路:
while (true)
{
SetWaitableTimer(myTimer, desired_frame_duration, ...);
PeekMsg(...)
if (quit....) break;
if (msg)
handle message;
else
{
Render();
SwapBuffers();
}
WaitForSingleObject(myTimer);
}
更多信息: 如何限制FPS信息
Answer 7:
一个简单的方法是用过剩。 该代码可以做的工作,大致。
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);
}