使用OpenGL在MFC控件中平移

时间:2014-04-16 06:55:24

标签: visual-c++ opengl mfc

我对OpenGL很新,所以这可能是一个非常愚蠢的问题。
我正在使用的是什么:Visual Studio 2010,MFC框架,Windows 7 我正在尝试做什么:基于OpenGL的MFC控件,可以通过缩放,平移和旋转显示一些文件预览。
我已经完成了什么

  1. 从CButton派生一个班级来处理所有事件并轻松访问CClientDC;
  2. 在最近的一个教程之后,我已经在一个类中封装了OpenGL设备的创建。
我不知道它是好还是我已经理解了我的内容完了,但它确实有效。
让我给你看一些代码:

int COpenGLCtrl::OnCreate( LPCREATESTRUCT lpCreateStruct )
    {
       if( CButton::OnCreate( lpCreateStruct ) == -1 )
         return -1;
       m_pDC = new CClientDC( this );
       // This is my encapsulated device.
       m_GLDevice.Create( m_pDC->m_hDC );
       InitGL();
       return 0;
    }

    void COpenGLCtrl::InitGL( void )
    {
       glShadeModel( GL_SMOOTH );
       glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
    }
    // Drawing inside button.
    void COpenGLCtrl::OnPaint( void )
    {
       m_GLDevice.MakeCurrent();
       DrawGLScene();
    }
    // This function is called before DrawGLScene the first time the control is being redrawed.
    void COpenGLCtrl::ZoomOut( int nVal )
    {
       glMatrixMode( GL_PROJECTION );  
       glLoadIdentity();
       glOrtho( 0.0f, nVal * 1.0f, 0.0f, nVal * 1.0f, nVal * 1.0f, 0.0f );
       glMatrixMode( GL_MODELVIEW );
       glLoadIdentity();
    }
    void COpenGLCtrl::DrawGLScene( void )
    {
       glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
       glLoadIdentity();
       glRotatef( m_fRotation_X, 1.0f, .0f, 0.0f );
       glRotatef( m_fRotation_Y, 0.0f, 1.0f, 0.0f );
       glTranslatef( m_fTraslation_X, m_fTraslation_Y, 0.0f );
       glScalef( 1.0f, 1.0f, 0.0f );
       glBegin( GL_TRIANGLES );
       glColor3f( 1.0f, 0.0f, 0.0f );
       glVertex3f( 0.0f, 0.0f, 0.0f );
       glColor3f( 0.0f, 1.0f, 0.0f );
       glVertex3f( 0.5f, 1.0f, 0.0f );
       glColor3f( 0.0f, 0.0f, 1.0f );
       glVertex3f( 1.0f, 0.0f, 0.0f );
       glEnd();
       SwapBuffers( m_pDC->m_hDC );
    }

所有这些代码足以在我的控件中绘制一个小三角形,其左下顶点以OpenGL轴原点为中心。好的,我告诉你所有这些东西,看看是否有某些错误。 现在我想围绕我的三角形:从我所理解的,我要修改m_fTranslation_X和m_fTranslation_Y的值。当用户按住鼠标左键并移动它时,我决定平移视图:

void COpenGLCtrl::OnMouseMove( UINT nFlags, CPoint point )
    {
       int nRes;
       CString strOut;
       GLfloat winX, winY, winZ;
       GLint viewport[4];
       GLdouble vPos[3], modelview[16], projection[16];

       // Converting CPoint MFC coordinates to OpenGL viewport coordinates.
       m_p2dPosMouse = point;
       glGetDoublev( GL_MODELVIEW_MATRIX, modelview );
       glGetDoublev( GL_PROJECTION_MATRIX, projection );
       glGetIntegerv( GL_VIEWPORT, viewport );
       winX = (GLfloat)point.x;
       winY = (GLfloat)viewport[3] - (GLfloat)point.y;
       glReadPixels( point.x, int( winY ), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ );
       nRes = gluUnProject( winX, winY, winZ, modelview, projection, viewport, &vPos[0], &vPos[1], &vPos[2] );
       m_vPosMouse[0] = (GLfloat)vPos[0];
       m_vPosMouse[1] = (GLfloat)vPos[1];
       m_vPosMouse[2] = (GLfloat)vPos[2];
       if( nFlags == MK_LBUTTON )
       {
          if( !m_bTrasla )
          {
             ATLTRACE2( _T("\nInizio traslazione\n\n") );
             memcpy( m_vPosMouse_ult, m_vPosMouse, 3 * sizeof( GLfloat ) );
             m_p2dUltPos = point;
             m_bTrasla = true;
          }
          /*OPENGL-WAY
          m_fTraslation_X += m_vPosMouse[0] - m_vPosMouse_ult[0];
          m_fTraslation_Y += m_vPosMouse[1] - m_vPosMouse_ult[1];
          */
          /*MFC-WAY*/
          m_fTraslation_X += ( point.x - m_p2dUltPos.x ) / 5000.0f;
          m_fTraslation_Y += ( m_p2dUltPos.y - point.y ) / 5000.0f;
          CString   strBuf;
          strBuf.Format( _T("%f - %f || CPoint.x: %ld CPoint.y: %ld\n"), m_fTraslation_X, m_fTraslation_Y, point.x, point.y );
          ATLTRACE2( strBuf );
          ///////////////////////
          // EDIT: Added in edit to solve MFC-WAY
          m_p2dUltPos = point;
          ///////////////////////
          memcpy( m_vPosMouse_ult, m_vPosMouse, 3 * sizeof( GLfloat ) );
      }
      if( m_CB_PosAgg.Valid() )
         m_CB_PosAgg.Execute();
      Invalidate();
    }

简而言之:我跟踪鼠标的最后位置并计算我在X和Y上的移动量。这些差异是我的翻译。
最后我的问题:

  1. 如果我使用OpenGL坐标(注释并标记为OPENGL-WAY),则平移是平滑而精确的但是摇动。这是因为即使我的CPoint坐标增加(或减少)等差异,OpenGL也不会。这是一些值:

    m_fTraslate_X  m_fTraslate_Y  CPoint.x CPoint.y
    0.000000         0.000000        274        328
    0.014377         0.141573        283        265
    0.020767         0.152809        287        260
    0.001597         0.002247        288        259
    0.007987         0.020225        292        251
    0.025559         0.164045        295        246
    0.027157         0.170786        296        243
    

    正如您所看到的,当鼠标控制位置增加(在MFC Y轴反转时),在步骤3,X轴的值突然从0.02减少到0.002然后再回到0.02!为什么这样?

  2. 编辑:在我的回答中解决了。如果我使用MFC坐标,标记为MFC-WAY,我没有震动但是有很强的惯性。有时会发生如果我开始向右移动鼠标(假设没有上下)然后将方向改回到左侧,我的视图继续向右移动。错误在哪里?
  3. 在此先感谢,希望你不要因为这篇noobish文章而禁止我。

1 个答案:

答案 0 :(得分:0)

问题1)
第一个问题是,当视图失效然后重绘时,仍然需要执行转换!解决方案:

if( nFlags == MK_RBUTTON && m_bTrasla )
{
        // Converting MFC coordinates to OpenGL System.
    ConversioneCoordinateMFC_A_OPENGL( m_vPosMouse_ult, m_p2dUltPos );
    m_fTraslation_X += m_vPosMouse[0] - m_vPosMouse_ult[0];
    m_fTraslation_Y += m_vPosMouse[1] - m_vPosMouse_ult[1];

问题2)
MFC-STYLE平移不会更新鼠标指针的最后位置。添加此行:

m_p2dUltPos = point;
解决了这个问题。