如何选择合适的缓冲区来绘制并阻止其连续交换 [英] How to choose the right buffer to draw and stop it from swapping continuously

查看:94
本文介绍了如何选择合适的缓冲区来绘制并阻止其连续交换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果问题很流行,请告诉我,我需要尽快回答

有关该问题的更多信息,可以参考此内容.我只是不明白如何正确地管理缓冲区.

for more information about the problem you can refer to this. I just didn't understand how to manage buffers properly.

在上面绘制的红色矩形二维纹理在绘制后立即消失

处于自定义类的最后阶段

Being in the last stages of customizing the class COpenGLControl:
I have created two instances of the class in my MFC Dialog:

whenever the extent of zoom is changed in the bigger window, it is drawn as a red rectangle on the smaller window. which is always in full extent mode. In order to stablish such a relation between two instances, I have used the concept of user defined messages and send the message to the parent of the class.

主要问题
根据以上信息:

The main trouble
based on the information above:

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

1- when I pan in the bigger window (mean I cause the user defined message be sent rapidly and m_oglWindow2.DrawRectangleOnTopOfTexture() be called rapidly I see a track of red rectangles shown but immediately disappeared in the smaller window

2-从3%切换到25%时,CPU使用率立即变高

2- CPU-usage immediately get's high when panning from 3% to 25%

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

3- In other navigation tasks liked Fixed zoom in,Fixed zoom out,Pan and etc a red rectangle flashes and then immediately disappears, I mean it seems that the red rectangle is there just when the control is in the function m_oglWindow2.DrawRectangleOnTopOfTexture() but I want the rectangle be there until the next call off m_oglWindow2.DrawRectangleOnTopOfTexture()

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

4- making calls to glDrawBuffer(GL_FRONT_AND_BACK) and glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) causes the texture in the smaller window to get off and on even if the mouse is idle

我知道问题最多的原因是以下代码中的行glClearglDrawBufferSwapBuffers.但是我不知道该怎么解决

I know the problem is most because of the lines glClear, glDrawBuffer, SwapBuffers in the following codes. But I don't know exactly how to solve

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()

OnDraw function is just called twice in the smaller window first when initializing the window and second when calling m_oglWindow2.ZoomToFullExtent() and then for each call of OnDraw in the bigger window, there's a call to the DrawRectangleOnTopOfTexture() in the smaller one but this function DrawRectangleOnTopOfTexture() is never called in the bigger window

如果发生以下情况,它将对您有利:

It'll be favor of you if:

  • 您纠正我的代码

  • you correct my code

为我提供了关于如何在多个缓冲区中使用缓冲区的出色教程 不能在单个函数或单个线程中完成的图形(关于缓冲区的出色教程,例如opengl中的颜色缓冲区等

introduce me an excellent tutorial on how to use buffers in multiple drawings that can not be done in a single function or a single thread (An excellent tutorial about buffers eg.color buffers and etc in opengl

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

我刚刚在下面添加了一些说明,以提供有关该类在需要时如何工作的更多信息.如果您认为这很烦人,请对其进行编辑,以删除您认为不需要的部分.但是请帮助我.

oglInitialize设置场景的初始参数:

the oglInitialize sets initial parameters for the scene:

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);
}  

导航任务示例:

PAN:

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);
}     

最重要的部分::如果客户端程序员将WantToSetViewRectangle设置为true,则在每个导航功能中调用OnDraw之前,这意味着他希望窗口的视图矩形为计算并调用setViewRectangle(),如下所示.如果更新ViewRectangle,它会向父母发送一条消息:

the most important part: before calling OnDraw in each of the navigation functions if the client-programmer has set WantToSetViewRectangle as true means that he wants the view rectangle for the window to be calculated and calls setViewRectangle() which is as follows. It sends a message to the parent in case of an update for 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);
} 

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

this is how we use the class in the client code:

MyOpenGLTestDlg.h

两个类的实例:

COpenGLControl m_oglWindow;
COpenGLControl m_oglWindow2;  

MyOpenGLTestDlg.cpp

在窗口上应用纹理,并在OnInitDlg

apply texture on the windows and set both of them to full extent in the 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();  

想要平移,zoomtool和setViewRectangle对于较大的窗口是活动的,但对于较小的窗口则不起作用:

want pan, zoomtool and setViewRectangle be active for the bigger window but not for the smaller one:

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

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

handling the user-defined message in the parent. exchange the ViewRectangle data to the smaller window and draw the red rectangle:

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

如果您有兴趣下载,请在这里完整的自定义类并解决我的问题.

Here's the full customized class if you're interested in downloading it and fix my problem.

推荐答案

问题是您正在使用计时器,并且应用程序收到WM_PAINT消息时. MFC在需要重新绘制窗口时调用OnDraw (...)回调,您应将绘图功能的 ALL 移动到OnDraw (...)中,并从计时器函数中调用OnDraw (...).

The problem is that you're drawing on a timer and when your application receives a WM_PAINT message. MFC invokes your OnDraw (...) callback when it needs to repaint the window, you should move ALL of your drawing functionality into OnDraw (...) and call OnDraw (...) from your timer function.

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();
}

并且只能在OnDraw (...)中调用wglMakeCurrent (...).此功能确实适用于要渲染到多个渲染上下文或使用多个线程进行绘制的情况.

And only ever make calls to wglMakeCurrent (...) within OnDraw (...). This function is really meant for situations where you're rendering into multiple render contexts, or drawing using multiple threads.

这篇关于如何选择合适的缓冲区来绘制并阻止其连续交换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆