去除OpenGL橡皮筋文物

时间:2012-01-23 02:59:56

标签: c++ windows opengl rubber-band

我正在使用一些用于科学可视化的OpenGL代码,并且我遇到了将橡皮带用于更新硬件的问题。代码在现有场景上绘制一个“缩放窗口”,其中“缩放窗口”的一个角位于存储的左键单击位置,另一个角落在鼠标移动时。在第二个左键单击,场景放大到所选窗口。

当鼠标在场景中移动时我看到的症状是:

  1. 出现的橡皮筋文物是用于创建“缩放窗口”的线条,未通过第二个“RenderLogic”传递从缓冲区中移除(参见下面的代码)
  2. 我可以清楚地看到前一个缓冲区的内容在交换缓冲区时闪烁并消失
  3. 上述问题不会发生在低端硬件上,例如我上网本的集成显卡。另外,我记不起这个问题〜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 - 下面的图片

    Artefacts from Zoom Window

3 个答案:

答案 0 :(得分:2)

使用OpenGL,如果发生任何变化,重绘整个视口是规范的。考虑一下:现代系统绘制动画复杂的场景超过30 FPS。

但我明白,你可能想避免这种情况。所以通常的方法是在绘制第一个橡皮筋之前先在纹理中复制前缓冲。然后,对于每个橡皮带,重绘“重置”图像,方法是使用纹理填充四边形填充四边形。

答案 1 :(得分:1)

我知道我发布了一年半的问题,但万一其他人遇到这个问题。

我自己发生这种情况是因为你试图从错误的缓冲区中删除这些行。例如,您在缓冲区A上调用swapBuffer绘制矩形,然后尝试从缓冲区B中删除矩形。您要做的是跟踪2个“缩放窗口”矩形,同时为缓冲区A和一个绘制一个矩形对于缓冲区B,然后跟踪哪一个是最新的。

答案 2 :(得分:0)

如果您使用的是Vista / 7和Aero,请尝试切换到经典主题。