C++ glClear()不服从剪刀区域

C++ glClear()不服从剪刀区域,c++,windows,opengl,C++,Windows,Opengl,我在一个已经打开的任意Windows 7窗口(例如Windows记事本窗口)中使用双缓冲绘制OpenGL内容(direct Win32-不使用GLUT、FreeGLUT、GLFW等)。我有窗口句柄,可以按预期绘制所需的内容,但我看到glClear()函数有奇怪的行为 我的理解是,glClear()函数应该只影响屏幕上位于glScissor()函数定义的区域内的像素。我使用glScissor()定义了剪刀区域,然后使用glEnable(GL\u剪刀测试)启用剪刀功能glClearColor设置为白

我在一个已经打开的任意Windows 7窗口(例如Windows记事本窗口)中使用双缓冲绘制OpenGL内容(direct Win32-不使用GLUT、FreeGLUT、GLFW等)。我有窗口句柄,可以按预期绘制所需的内容,但我看到
glClear()
函数有奇怪的行为

我的理解是,
glClear()
函数应该只影响屏幕上位于
glScissor()
函数定义的区域内的像素。我使用
glScissor()
定义了剪刀区域,然后使用
glEnable(GL\u剪刀测试)
启用剪刀功能<代码>glClearColor设置为白色
(0,0,0,1)
。我正在使用
glClear()
命令清除颜色和深度缓冲区

当执行
SwapBuffers()
命令以便在屏幕上进行渲染时,我选择的白色清晰颜色将按照我的要求绘制在剪刀区域内,但剪刀区域外的窗口其余部分将绘制为黑色,而不是像我预期的那样保持这些像素不变

如图所示,剪刀区域(白色)和对象(3D立方体)绘制正确,但记事本窗口的其余像素设置为黑色,并且之前在该记事本窗口中绘制的任何内容都被覆盖

glClearColor(1.0f, 1.0f, 1.0f, 1.0f);               // white background
glViewport(0, 0, 300, 300);
glScissor(0, 0, 250, 400);
glEnable(GL_SCISSOR_TEST);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//... draw cube inside glBegin()/glEnd()...
SwapBuffers(hDC);

如果我没有弄错您的描述,
glClear
可以正常工作

你不能仅仅因为你在屏幕上看到了一些东西,就认为它也存在于后台缓冲区中。您看到的记事本窗口的内容要么是前缓冲区,要么是前缓冲区的副本,该前缓冲区被闪电式地放入DWM自己的秘密渲染缓冲区(取决于您是否进行了合成)。或者,其他一些东西,一个被Blit到DWM的缓冲区的GDI缓冲区,或者诸如此类的东西。很可能是后者,因为它使用GDI进行渲染

当您翻转缓冲区时,后台缓冲区显示在该区域屏幕上的任何内容上,您得到的是一个全黑缓冲区(实际上未初始化,但可能是驱动程序将内存归零),但您清除为白色的区域除外。
这正是您应该期望的——您的
glClear
只影响一个子区域,其余的子区域未定义,它恰好为零(黑色)

顺便说一句,如果没有启用合成功能,您在屏幕上看到的内容可以从大多数图形卡的前缓冲区复制到后缓冲区,因此,如果您希望这样做,您仍然可以看到记事本窗口的原始内容。但是,您的后台缓冲区中永远不会神奇地包含GDI窗口的内容(DWM也不能这样做,也不能保证它可以工作,它只在大多数情况下偶尔工作)


如果您想要窗口的原始内容,干净的解决方案是从DC到内存
BitBlt
,创建一个纹理,并将其绘制(或blit)到后缓冲区。

您是否清除过整个视口?缓冲区交换可能会使屏幕上您永远无法清除的部分未定义。好的,谢谢Damon的回复。很高兴知道这是预期的行为,而不是我代码中的一些奇怪问题。您提出的解决方案看起来像是一种迂回的方法,使OpenGL能够在刷新期间只更新给定窗口中的一部分像素,但我可以试一试。我假设,由于我的剪切区域之外的像素可能会根据其他不相关的过程发生变化,因此每次更新OpenGL内容时,我都必须重新对窗口进行BitBlt操作——这听起来计算成本很高,因为BitBlt使用的是CPU而不是GPU,对吧?@user3666612:这是一个往返过程,但没有一个干净的方法可以做任何不同的事情。您绘制到的“曲面”(后缓冲区)包含“未初始化”或您绘制到其中的内容,其中包括清除。这与屏幕上的表面不同(想想剪裁或重叠窗口,显然不是这样)。因此,如果您希望原始窗口的内容(即GDI图形)显示在OpenGL曲面上,则必须在其中绘制/blit/复制该像素数据。