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。你很幸运有一个使用这么好的书的课程,只是要注意一些简单的示例在现代计算机上无法正常运行——几乎所有的 OpenGL textbooks 都是如此。

以上是关于C++ OpenGL 窗口只跟踪背景的主要内容,如果未能解决你的问题,请参考以下文章

如何跟踪 C++ 库的加载过程?

C++ OpenCV:跟踪街上移动的人

OpenGL - 如何跟踪移动的物体? [关闭]

openGL error 跟踪

调试时如何在 Visual C++ 2010 中跟踪/输出时间戳

使用openGL应用转换后有没有办法跟踪点