我正在使用一些用于科学可视化的 OpenGL 代码,但在较新的硬件上使其橡皮筋正常工作时遇到问题。该代码在现有场景上绘制一个“缩放窗口”,其中“缩放窗口”的一个角位于存储的左键单击位置,另一个角在鼠标移动时位于鼠标下方。第二次左键单击时,场景会放大到所选窗口。
当鼠标在场景中移动时我看到的症状是:
- 出现橡皮筋伪影,它们是用于创建“缩放窗口”的线条,未通过第二个“RenderLogic” channel 从缓冲区中删除(请参见下面的代码)
- 我可以清楚地看到前一个缓冲区的内容在缓冲区交换时闪烁并消失
上述问题不会发生在低端硬件上,例如我上网本上的集成显卡。另外,我不记得大约 5 年前编写此代码时遇到的问题。
以下是相关代码部分,经过精简以重点关注相关 OpenGL:
// Called by every mouse move event
// Makes use of current device context (m_hDC) and rendering context (m_hRC)
void MyViewClass::DrawLogic()
{
BOOL bSwapRv = FALSE;
// Make the rendering context current
if (!wglMakeCurrent(m_hDC, m_hRC))
// ... error handling
// Perform the logic rendering
glLogicOp(GL_XOR);
glEnable(GL_COLOR_LOGIC_OP);
// Draws the rectangle on the buffer using XOR op
RenderLogic();
bSwapRv = ::SwapBuffers(m_hDC);
// Removes the rectangle from the buffer via a second pass
RenderLogic();
glDisable(GL_COLOR_LOGIC_OP);
// Release the rendering context
if (!wglMakeCurrent(NULL, NULL))
// ... error handling
}
void MyViewClass::RenderLogic(void)
{
glLineWidth(1.0f);
glColor3f(0.6f,0.6f,0.6f);
glEnable(GL_LINE_STIPPLE);
glLineStipple(1, 0x0F0F);
glBegin(GL_LINE_LOOP);
// Uses custom "Point" class with Coords() method returning double*
// Draw rectangle with corners at clicked location and current location
glVertex2dv(m_pntClickLoc.Coords());
glVertex2d(m_pntCurrLoc.X(), m_pntClickLoc.Y());
glVertex2dv(m_pntCurrLoc.Coords());
glVertex2d(m_pntClickLoc.X(), m_pntCurrLoc.Y());
glEnd();
glDisable(GL_LINE_STIPPLE);
}
// Setup code that might be relevant to the buffer configuration
bool MyViewClass::SetupPixelFormat()
{
PIXELFORMATDESCRIPTOR pfd = {
sizeof(PIXELFORMATDESCRIPTOR),
1, // Version number (?)
PFD_DRAW_TO_WINDOW // Format must support window
| PFD_SUPPORT_OPENGL // Format must support OpenGL
| PFD_DOUBLEBUFFER, // Must support double buffering
PFD_TYPE_RGBA, // Request an RGBA format
32, // Select a 32 bit colour depth
0, 0, 0, 0, 0, 0, // Colour bits ignored (?)
8, // Alpha buffer bits
0, // Shift bit ignored (?)
0, // No accumulation buffer
0, 0, 0, 0, // Accumulation bits ignored
16, // 16 bit Z-buffer
0, // No stencil buffer
0, // No accumulation buffer (?)
PFD_MAIN_PLANE, // Main drawing layer
0, // Number of overlay and underlay planes
0, 0, 0 // Layer masks ignored (?)
};
PIXELFORMATDESCRIPTOR chosen_pfd;
memset(&chosen_pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
chosen_pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
// Find the closest match to the pixel format
m_uPixelFormat = ::ChoosePixelFormat(m_hDC, &pfd);
// Make sure a pixel format could be found
if (!m_uPixelFormat)
return false;
::DescribePixelFormat(m_hDC, m_uPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &chosen_pfd);
// Set the pixel format for the view
::SetPixelFormat(m_hDC, m_uPixelFormat, &chosen_pfd);
return true;
}
任何有关如何移除文物的指示将不胜感激。
@Krom - 下图
最佳答案
对于 OpenGL,如果有任何变化,重新绘制整个视口(viewport)是规范的。考虑一下:现代系统以超过 30 FPS 的速度绘制复杂场景的动画。
但我理解,您可能想避免这种情况。因此,通常的方法是在绘制第一个橡皮筋之前首先复制纹理中的前缓冲区。然后,对于每个橡皮筋,通过绘制带有纹理的帧缓冲区填充四边形来重新绘制“重置”图像。
关于c++ - 去除 OpenGL 橡皮筋伪影,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8966771/