-1

请告诉我这个问题是否流行,我需要尽快答复

有关该问题的更多信息,您可以参考this。我只是不明白如何正确管理缓冲区。

在 2D 纹理上绘制的红色矩形在绘制后立即消失

在自定义COpenGLControl类的最后阶段:
我在 MFC 对话框中创建了该类的两个实例:
在此处输入图像描述
每当在较大窗口中更改缩放范围时,它都会在较小窗口上绘制为红色矩形。始终处于全范围模式。为了在两个实例之间建立这种关系,我使用了用户定义消息的概念并将消息发送给类的父类。


基于以上信息 的主要问题:

1-当我在较大的窗口中平移时(意味着我导致用户定义的消息被快速发送并被快速m_oglWindow2.DrawRectangleOnTopOfTexture()调用我看到一个红色矩形的轨迹显示但立即在较小的窗口中消失了

2- 当从 3% 平移到 25% 时,CPU 使用率立即变高

3-在其他导航任务Fixed zoom in中,例如Fixed zoom outPan等,红色矩形闪烁然后立即消失,我的意思是当控件在函数中时红色矩形似乎在那里,m_oglWindow2.DrawRectangleOnTopOfTexture()但我希望矩形在那里直到下一次取消m_oglWindow2.DrawRectangleOnTopOfTexture()

4-调用glDrawBuffer(GL_FRONT_AND_BACK)glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)导致较小窗口中的纹理关闭和打开,即使鼠标处于空闲状态

我知道问题主要在于以下代码中的行glClear, 。但我不知道具体如何解决 glDrawBufferSwapBuffers

void COpenGLControl::OnTimer(UINT nIDEvent)
{
wglMakeCurrent(hdc,hrc);
switch (nIDEvent)
{
    case 1:
    {
        // Clear color and depth buffer bits
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        // Draw OpenGL scene
        oglDrawScene();

        // Swap buffers
        SwapBuffers(hdc);

        break;
    }

    default:
        break;
}

CWnd::OnTimer(nIDEvent);
wglMakeCurrent(NULL, NULL);
}  

void COpenGLControl::DrawRectangleOnTopOfTexture()
{
wglMakeCurrent(hdc, hrc);
//glDrawBuffer(GL_FRONT_AND_BACK);
//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushAttrib(GL_ENABLE_BIT|GL_CURRENT_BIT);
glDisable(target);
glColor3f(1.0f,0.0f,0.0f);
glBegin(GL_LINE_LOOP);
   glVertex2f(RectangleToDraw.at(0),RectangleToDraw.at(1));
   glVertex2f(RectangleToDraw.at(0),RectangleToDraw.at(3));
   glVertex2f(RectangleToDraw.at(2),RectangleToDraw.at(3));
   glVertex2f(RectangleToDraw.at(2),RectangleToDraw.at(1));
glEnd();
glPopAttrib();
SwapBuffers(hdc);
wglMakeCurrent(NULL, NULL);
}  

void COpenGLControl::OnDraw(CDC *pDC)
{
// TODO: Camera controls
wglMakeCurrent(hdc,hrc);
glLoadIdentity();
gluLookAt(0,0,1,0,0,0,0,1,0);
glTranslatef(m_fPosX, m_fPosY, 0.0f);
glScalef(m_fZoom,m_fZoom,1.0);
wglMakeCurrent(NULL, NULL);
}  

记住:

OnDraw函数只是在较小的窗口中调用两次,第一次是在初始化窗口时,第二次是在调用时m_oglWindow2.ZoomToFullExtent(),然后对于OnDraw在较大的窗口中的每次调用,都会在较小的窗口中调用,但在较大的窗口中永远不会调用 DrawRectangleOnTopOfTexture()此函数DrawRectangleOnTopOfTexture()

如果:

  • 你更正了我的代码

  • 向我介绍一个关于如何在多个绘图中使用无法在单个函数或单个线程中完成的缓冲区的优秀教程(关于缓冲区的优秀教程,例如 opengl 中的颜色缓冲区等

-------------------------------------------------- ---------------------------------------- ---------- -------------------------------------------------- -----------------------------------------

我只是在下面添加了解释,以提供有关该类在需要时如何工作的更多信息。如果您认为它困扰观众,只需编辑它以删除您认为不需要的部分。但请帮帮我。

oglInitialize 设置场景的初始参数:

void COpenGLControl::oglInitialize(void)
{
// Initial Setup:
//
static PIXELFORMATDESCRIPTOR pfd =
{
    sizeof(PIXELFORMATDESCRIPTOR),
    1,
    PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
    PFD_TYPE_RGBA,
    32, // bit depth
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    24, // z-buffer depth
    8,0,PFD_MAIN_PLANE, 0, 0, 0, 0,
};

// Get device context only once.
hdc = GetDC()->m_hDC;
// Pixel format.
m_nPixelFormat = ChoosePixelFormat(hdc, &pfd);
SetPixelFormat(hdc, m_nPixelFormat, &pfd);
// Create the OpenGL Rendering Context.
hrc = wglCreateContext(hdc);
wglMakeCurrent(hdc, hrc);
// Basic Setup:
//
// Set color to use when clearing the background.
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClearDepth(1.0f);
// Turn on backface culling
glFrontFace(GL_CCW);
glCullFace(GL_BACK);
// Turn on depth testing
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
// Send draw request
OnDraw(NULL);
wglMakeCurrent(NULL, NULL);
}  

导航任务示例:

平底锅:

void COpenGLControl::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
if (WantToPan)
{
    if (m_fLastX < 0.0f && m_fLastY < 0.0f)
    {
        m_fLastX = (float)point.x;
        m_fLastY = (float)point.y;
    }
    int diffX = (int)(point.x - m_fLastX);
    int diffY = (int)(point.y - m_fLastY);
    m_fLastX = (float)point.x;
    m_fLastY = (float)point.y;
    if (nFlags & MK_MBUTTON)
    {
        m_fPosX += (float)0.05f*m_fZoomInverse*diffX;
        m_fPosY -= (float)0.05f*m_fZoomInverse*diffY;
    }
    if (WantToSetViewRectangle)
        setViewRectangle();
    OnDraw(NULL);
}
CWnd::OnMouseMove(nFlags, point);
}     

最重要的部分: 在调用OnDraw每个导航函数之前,如果客户端程序员已设置WantToSetViewRectangle为 true,则意味着他希望计算窗口的视图矩形并调用setViewRectangle()如下。如果有以下更新,它会向父级发送消息ViewRectangle

void COpenGLControl::setViewRectangle()
{
CWnd *pParentOfClass = CWnd::GetParent();
ViewRectangle.at(0) = -m_fPosX - oglWindowWidth*m_fZoomInverse/2;
ViewRectangle.at(1) = -m_fPosY - oglWindowHeight*m_fZoomInverse/2;
ViewRectangle.at(2) = -m_fPosX + oglWindowWidth*m_fZoomInverse/2;
ViewRectangle.at(3) = -m_fPosY + oglWindowHeight*m_fZoomInverse/2;
bool is_equal = ViewRectangle == LastViewRectangle;
if (!is_equal)
    pParentOfClass ->SendMessage(WM_RECTANGLECHANGED,0,0);
LastViewRectangle.at(0) = ViewRectangle.at(0);
LastViewRectangle.at(1) = ViewRectangle.at(1);
LastViewRectangle.at(2) = ViewRectangle.at(2);
LastViewRectangle.at(3) = ViewRectangle.at(3);
} 

这就是我们在客户端代码中使用类的方式:

MyOpenGLTestDlg.h

类的两个实例:

COpenGLControl m_oglWindow;
COpenGLControl m_oglWindow2;  

MyOpenGLTestDlg.cpp

在窗口上应用纹理并在OnInitDlg

    m_oglWindow.pImage = m_files.pRasterData;
    m_oglWindow.setImageWidthHeightType(m_files.RasterXSize,m_files.RasterYSize,m_files.eType);
    m_oglWindow.m_unpTimer = m_oglWindow.SetTimer(1, 1, 0);  

    m_oglWindow2.pImage = m_files.pRasterData;
    m_oglWindow2.setImageWidthHeightType(m_files.RasterXSize,m_files.RasterYSize,m_files.eType);
    m_oglWindow2.m_unpTimer = m_oglWindow2.SetTimer(1, 20, 0);  
    m_oglWindow2.ZoomToFullExtent();
    m_oglWindow.ZoomToFullExtent();  

希望 pan、zoomtool 和 setViewRectangle 对较大的窗口有效,但对较小的窗口无效:

m_oglWindow.WantToPan = true;
m_oglWindow.WantToUseZoomTool = true;
m_oglWindow.WantToSetViewRectangle = true;  

处理父级中的用户定义消息。将数据交换ViewRectangle到较小的窗口并绘制红色矩形:

LRESULT CMyOpenGLTestDlg::OnRectangleChanged(WPARAM wParam,LPARAM lParam)
{
m_oglWindow2.RectangleToDraw = m_oglWindow.ViewRectangle;
m_oglWindow2.DrawRectangleOnTopOfTexture();
return 0;
}  

如果您有兴趣下载并解决我的问题,这是完整的自定义课程。

4

1 回答 1

0

问题是您正在使用计时器以及您的应用程序何时收到WM_PAINT消息。当MFCOnDraw (...)需要重新绘制窗口时,它会调用您的回调,您应该将所有绘图功能移入OnDraw (...)OnDraw (...)从您的计时器函数中调用。

void COpenGLControl::OnTimer(UINT nIDEvent)
{
  switch (nIDEvent)
  {
    case 1:
    {
      OnDraw (NULL);
      break;
    }

    default:
      break;
  }

  CWnd::OnTimer(nIDEvent);
}

void COpenGLControl::OnDraw(CDC *pDC)
{
  // TODO: Camera controls
  wglMakeCurrent(hdc,hrc);

  // Clear color and depth buffer bits
  glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  glLoadIdentity ();
  gluLookAt      (0,0,1,0,0,0,0,1,0);
  glTranslatef   (m_fPosX, m_fPosY, 0.0f);
  glScalef       (m_fZoom,m_fZoom,1.0);

  // Draw OpenGL scene
  oglDrawScene();

  // Swap buffers
  SwapBuffers(hdc);

  wglMakeCurrent(NULL, NULL);
}

void COpenGLControl::DrawRectangleOnTopOfTexture()
{
  glPushAttrib(GL_ENABLE_BIT|GL_CURRENT_BIT);
  glDisable(target);
  glColor3f(1.0f,0.0f,0.0f);
  glBegin(GL_LINE_LOOP);
    glVertex2f(RectangleToDraw.at(0),RectangleToDraw.at(1));
    glVertex2f(RectangleToDraw.at(0),RectangleToDraw.at(3));
    glVertex2f(RectangleToDraw.at(2),RectangleToDraw.at(3));
    glVertex2f(RectangleToDraw.at(2),RectangleToDraw.at(1));
  glEnd();
  glPopAttrib();
}

并且只调用wglMakeCurrent (...)inside OnDraw (...)。此函数实际上适用于您要渲染到多个渲染上下文或使用多个线程进行绘制的情况。

于 2013-08-31T02:59:10.420 回答