在OpenGL中撕裂?
Posted
技术标签:
【中文标题】在OpenGL中撕裂?【英文标题】:Tearing in OpenGL? 【发布时间】:2010-04-16 22:59:26 【问题描述】:我正在使用 win32 和 opengl,并且我设置了一个窗口,其投影位于窗口坐标的 glOrtho。我启用了双缓冲,也使用 glGet 对其进行了测试。如果我的程序不断被翻译,我的程序似乎总是会撕裂我试图利用它的任何原语。
这是我的 OpenGL 初始化函数:
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glViewport(0, 0, 640, 480);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 640, 0, 480, 0, 100);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glDrawBuffer(GL_BACK);
glLoadIdentity();
这是我的渲染函数,gMouseX 和 gMouseY 是鼠标的坐标:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glTranslatef(gMouseX, gMouseY, 0.0f);
glColor3f(0.5f, 0.5f, 0.5f);
glBegin(GL_TRIANGLES);
glVertex2f(0.0f, 128.0f);
glVertex2f(128.0f, 0.0f);
glVertex2f(0.0f, 0.0f);
glEnd();
SwapBuffers(hDC);
无论渲染函数的运行频率如何,都会出现同样的撕裂问题。我在这里做错了什么或遗漏了什么?
【问题讨论】:
【参考方案1】:如果您只渲染一两个三角形,您的帧率将会非常高(可能达到数千 FPS),这意味着它就像地狱一样的 SwapBuffering,这意味着您可能总是在屏幕刷新(即使打开双缓冲)。一旦您的场景开始包含更多内容并且帧速率下降到更真实的值,它应该停止撕裂。或者,考虑启用 V-Sync,例如在 Windows 上使用 wglSwapIntervalEXT
。
【讨论】:
我忘了说帧率的上限大约是 60 FPS(使用 WM_TIMER 每 16 毫秒),无论我将定时器设置为多少,它仍然会流泪。 如@AshleysBrain 所说启用垂直同步。使用计时器手动限制帧速率不会与屏幕刷新同步。 调用 glGetString(GL_EXTENSIONS) 后,我发现我的系统上没有启用 VSync,因为字符串“WGL_EXT_swap_control”没有返回。是否真的没有其他方法可以减少撕裂,因为我可以下载的几乎所有其他游戏都没有这个问题。 @kaykun:wgl_ext_swap_control 不是 GL 扩展。这是一个 wgl 扩展。有关如何处理 wgl 扩展的一般信息,请参阅 opengl.org/registry/specs/EXT/wgl_extensions_string.txt。 Windows 上的所有现代 GL 实现都支持它,afaik。【参考方案2】:正如互联网上的所有人都试图建议的那样,这个问题不一定与垂直同步有关。在我的情况下,问题是由窗口初始化的方式引起的。我注意到,摆脱 dwStyle=WS_POPUP 解决了这个问题,但只是部分因为那时窗口没有处于全屏模式。最后对我有用的是在创建窗口后使用 SetWindowLong(hwnd, GWL_STYLE, 0); 。它基本上清除了窗口样式。所以我初始化窗口的代码是这样的:
dwStyle=WS_POPUP; //Windows Style
ShowCursor(FALSE); //Hide Mouse Pointer
//Create the Window
hwnd= CreateWindowEx(NULL,
"GLClass",
appName,
dwStyle,
0, 0,
(long)windowWidth,
(long)windowHeight,
NULL,
NULL,
hInstance,
NULL);
SetWindowLong(hwnd, GWL_STYLE, 0);
修改后,我所有的撕裂和无法打印屏幕的问题都得到了解决。我不需要在任何地方触摸 VSync。
【讨论】:
【参考方案3】:在定义您的 win32 应用程序窗口样式时,不要包含 WS_POPUP 在调试了一个全屏会导致屏幕撕裂的问题后,我发现了全屏的样式,在删除 WS_POPUP 之后,它似乎已经停止了单手撕裂,而不必强制渲染循环到刷新率。 WS_POPUP 以存在问题而闻名,我猜。它还会阻止任何全屏屏幕截图以完成白色。
【讨论】:
这个问题是由垂直同步引起的。您有任何证据表明 WS_POPUP 可能相关吗? 在调试了一个全屏会导致屏幕撕裂的问题后,我发现了全屏的样式,在删除 WS_POPUP 后,它似乎已经停止了单手撕裂,而无需强制渲染循环刷新速度。 WS_POPUP 以存在问题而闻名,我猜。它还会阻止任何全屏屏幕截图以完成白色。 您应该将该解释添加到您的答案中)【参考方案4】:撕裂是由于未将更新与显示器的垂直消隐间隔同步造成的。它在 OpenGL 中有点依赖硬件(我认为,不是专家),从寻找 glXWaitVideoSyncSGI 开始。谷歌搜索“opengl sync to vblank”也有回报。
【讨论】:
glX 是 Unix,OP 说他在 win32 上。【参考方案5】:尝试对帧速率设置上限/限制或降低帧速率(如果您没有垂直同步):
这是伪代码:
let tick equals new_tick
if tick is less than last_tick do
yield
done
calculate last_tick
尝试睡眠功能并将其设置为 1,以便让步:
Sleep(1);
还请记住,限制或限制帧速率并不可取,因为某些功能实际上是为了减少帧计算。
【讨论】:
以上是关于在OpenGL中撕裂?的主要内容,如果未能解决你的问题,请参考以下文章