C++ OpenGL 窗口只跟踪背景
Posted
技术标签:
【中文标题】C++ OpenGL 窗口只跟踪背景【英文标题】:C++ OpenGL window only tracks background 【发布时间】:2013-08-28 01:09:26 【问题描述】:有人知道为什么在 OpenGL 中尝试生成简单正方形时会发生这种情况吗?
我正在使用Computer Graphics Through OpenGL一书中的以下源代码:从理论到实验。
////////////////////////////////////////////////////
// square.cpp
//
// Stripped down OpenGL program that draws a square.
//
// Sumanta Guha.
////////////////////////////////////////////////////
#include <iostream>
#ifdef __APPLE__
# include <GLUT/glut.h>
#else
# include <GL/glut.h>
#endif
using namespace std;
// Drawing (display) routine.
void drawScene(void)
// Clear screen to background color.
glClear(GL_COLOR_BUFFER_BIT);
// Set foreground (or drawing) color.
glColor3f(0.0, 0.0, 0.0);
// Draw a polygon with specified vertices.
glBegin(GL_POLYGON);
glVertex3f(20.0, 20.0, 0.0);
glVertex3f(80.0, 20.0, 0.0);
glVertex3f(80.0, 80.0, 0.0);
glVertex3f(20.0, 80.0, 0.0);
glEnd();
// Flush created objects to the screen, i.e., force rendering.
glFlush();
// Initialization routine.
void setup(void)
// Set background (or clearing) color.
glClearColor(1.0, 1.0, 1.0, 0.0);
// OpenGL window reshape routine.
void resize(int w, int h)
// Set viewport size to be entire OpenGL window.
glViewport(0, 0, (GLsizei)w, (GLsizei)h);
// Set matrix mode to projection.
glMatrixMode(GL_PROJECTION);
// Clear current projection matrix to identity.
glLoadIdentity();
// Specify the orthographic (or perpendicular) projection,
// i.e., define the viewing box.
glOrtho(0.0, 100.0, 0.0, 100.0, -1.0, 1.0);
// Set matrix mode to modelview.
glMatrixMode(GL_MODELVIEW);
// Clear current modelview matrix to identity.
glLoadIdentity();
// Keyboard input processing routine.
void keyInput(unsigned char key, int x, int y)
switch(key)
// Press escape to exit.
case 27:
exit(0);
break;
default:
break;
// Main routine: defines window properties, creates window,
// registers callback routines and begins processing.
int main(int argc, char **argv)
// Initialize GLUT.
glutInit(&argc, argv);
// Set display mode as single-buffered and RGB color.
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
// Set OpenGL window size.
glutInitWindowSize(500, 500);
// Set position of OpenGL window upper-left corner.
glutInitWindowPosition(100, 100);
// Create OpenGL window with title.
glutCreateWindow("square.cpp");
// Initialize.
setup();
// Register display routine.
glutDisplayFunc(drawScene);
// Register reshape routine.
glutReshapeFunc(resize);
// Register keyboard routine.
glutKeyboardFunc(keyInput);
// Begin processing.
glutMainLoop();
return 0;
我已经尝试了最长时间......
在此处了解更多详情:
屏幕打开时只显示背景,如果你拖动它,它将继续跟踪背景,这是将窗口移动到底部然后再次将其移动到原始位置的结果。我已经在 linux 机器上测试了相同的源代码,它工作正常...... :(
编辑:我尝试过使用 glutSwapBuffers() ,但这似乎也不起作用。
【问题讨论】:
您是否在 Windows Vista 或更高版本上运行?这可能是与渲染到前端缓冲区相关的 DWM 合成器问题。 是的,我正在运行 W7... 这到底是什么意思?这是否意味着无法解决这个问题? 好的,这将很难解释 :) 基本上,在 Windows Vista 和更高版本中,窗口被绘制到屏幕外表面,并且操作系统在“绘制”窗口时使用后台缓冲区的副本.通过拥有可用的后缓冲区副本,它可以进行花哨的实时窗口预览和其他在 Windows XP 之前不存在的效果。要纠正这个问题,您要么需要绘制到后台缓冲区,要么使用双缓冲和交换缓冲区。 【参考方案1】:在 Windows Vista 和更新的 Windows 操作系统上,有一个称为 Desktop Window Manager
(DWM) 的组件,它具有一种称为“桌面合成”的特殊模式,可将窗口绘制到屏幕外缓冲区然后合成它们。它这样做是为了提供新的视觉效果,例如 Alt+Tab 屏幕中的实时窗口预览。
这种新架构的一个结果是,您无法像在 Windows XP 中(或在禁用桌面合成的 Windows Vista+ 中)那样绘制单个缓冲应用程序(无论如何都在窗口模式下)。简而言之,DWM 使用渲染上下文的后台缓冲区的副本进行合成。您应该切换到双缓冲绘图。
要在 GLUT 中使用双缓冲绘图,您可以在调用 glutInitDisplayMode (...)
时使用 GLUT_DOUBLE
而不是 GLUT_SINGLE
。此外,您需要将对glFlush (...)
的调用替换为glutSwapBuffers (...)
。
【讨论】:
我厌倦了使用 gluSwapBuffers() 而不是 glFlush() 并且这似乎也不起作用:(最终解决方案真的是切换操作系统吗? @Stupid.Fat.Cat:您还需要将GLUT_DOUBLE
传递给glutInitDisplayMode (...)
以建立双缓冲渲染上下文。不,绝对不需要切换操作系统。单缓冲渲染是你不应该首先使用的东西,这只会把问题强加给你:P
天哪!有效!我不知道发生了什么,但它奏效了!添加 GLUT_DOUBLE。嗯..所以我有点想了解这里发生了什么,GLUT_DOUBLE 到底做了什么?我非常感谢这一点。五个小时!谢谢!
@Stupid.Fat.Cat: GLUT_DOUBLE
这样做是为了让您的 GPU 在绘制时使用两个缓冲区。有一个front buffer
,它将您的所有命令呈现到(此缓冲区随着绘制单个多边形而不断更新)和一个back buffer
,其中包含您最后一帧的完成副本。当您完成当前帧的绘制命令时,您通过执行称为“交换缓冲区”的操作让驱动程序知道,并且在完成时它将复制/交换前缓冲区的内容与后缓冲区。 DWM 总是想要一个完全渲染的图像,所以它使用后台缓冲区。
我想我现在对这一点有了更好的理解。谢谢@Andon M. Coleman,非常感谢您花时间回答我的问题。【参考方案2】:
尝试在drawScene
的末尾添加对glutSwapBuffers();
的调用,并从glutInitDisplayMode
中删除GLUT_SINGLE
。单缓冲模式存在各种兼容性问题。在 Windows 上,它使用软件光栅化器,速度非常慢,而且问题更多。
如果这不起作用,请尝试通过将glClear
更改为glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
并将glClearcolor
更改为glClearColor(1.0, 1.0, 1.0, 1.0);
来清除深度缓冲区。
此外,此示例使用旧版 OpenGL,它比现代 OpenGL 慢得多,并且存在许多其他问题。除非您使用的 GPU 已有十多年的历史,否则您使用它的理由为零。从技术上讲,甚至不需要现代 GPU 来支持它。如果你需要一个好的现代 OpenGL 教程,http://open.gl 是一个很好的教程。只需寻找 OpenGL 2.1(或更高版本)教程。
【讨论】:
感谢您的建议@ECrownofFire,但这也不起作用:(。我关注这个的唯一原因是因为我的班级使用这本教科书,我正在以身作则。跨度> @Stupid.Fat.Cat 啊,那很不幸。旧版 OpenGL 不能很好地继承。 @Stupid.Fat.Cat:这本书实际上是一本相当不错的书,尽管早期的示例使用的是旧版 OpenGL。我对这本书很熟悉,它是一本很棒的教科书,它着重于理论而不是 API。你很幸运有一个使用这么好的书的课程,只是要注意一些简单的示例在现代计算机上无法正常运行——几乎所有的 OpenGLtextbooks
都是如此。以上是关于C++ OpenGL 窗口只跟踪背景的主要内容,如果未能解决你的问题,请参考以下文章