对于OpenGL的学习很多都是基于控制台或者win32,然后MFC类库对于我们各种消息响应是非常优秀的,因为在MFC下面进行OpenGL绘图是非常有必要的。OpenGL绘图的跟一般的绘图都是一样,需要设定一个绘图环境,设置环境的过程:1,定义一个窗口像素格式,2,创建一个一个渲染设备描述表,3,当前绘图设备关联渲染设备描述表,在COpenGL.h中定义一个OpenGL类,这个OpenGL类结构如下:

1 class COpenGL 2 { 3 public: 4 COpenGL(void); 5 ~COpenGL(void); 6 BOOL InitializeOpenGL(CWnd*); //初始化 OpenGL 7 BOOL SetupPixelFormat(); //设置 Pixel Format 8 void RenderScene(HDC); //绘图 Render Scene 9 void ReShape(GLint,GLint); //重置视口 10 void DestoryGL(); //销毁绘图设备 11 12 13 HGLRC m_hRC; //Rendering Context着色描述表 14 CDC* m_pDC; //Device Context设备描述表 15 };
在COpenGL.cpp实现

1 #include "OpenGL.h" 2 3 4 COpenGL::COpenGL(void) 5 { 6 } 7 8 9 COpenGL::~COpenGL(void) 10 { 11 } 12 13 //初始化绘图设备 14 BOOL COpenGL::InitializeOpenGL(CWnd* pWnd) 15 { 16 //获取绘图客户区绘图设备上下文DC 17 m_pDC = new CClientDC(pWnd); 18 19 if(!m_pDC) 20 { 21 MessageBoxA(NULL,"获取绘图设备DC失败","警告",MB_OK|MB_ICONWARNING); 22 return FALSE; 23 } 24 25 if(!SetupPixelFormat()) //配置像素格式 26 { 27 MessageBoxA(NULL,"像素格式配置失败","警告",MB_OK|MB_ICONWARNING); 28 return FALSE; 29 } 30 31 m_hRC = wglCreateContext (m_pDC->GetSafeHdc ());//创建一个渲染设备描述表RC 32 33 if(!m_hRC) 34 { 35 MessageBoxA(NULL,"创建渲染设备描述表失败","警告",MB_OK|MB_ICONWARNING); 36 return FALSE; 37 } 38 39 if(!wglMakeCurrent (m_pDC->GetSafeHdc (), m_hRC))//关联设备描述表RC和当前绘图设备上下文DC 40 { 41 MessageBoxA(NULL,"渲染设备描述表关联失败","警告",MB_OK|MB_ICONWARNING); 42 return FALSE; 43 } 44 glClearColor(0.0f,0.0f,0.0f,0.0f); //初始化设备背景颜色为黑色 45 glClearDepth(1.0f); //设置设备绘图深度为1.0 46 47 glEnable(GL_DEPTH_TEST); //启用深度测试 48 return TRUE; //绘图设备初始化成功 49 } 50 51 //设置像素格式 52 BOOL COpenGL::SetupPixelFormat() 53 { 54 static PIXELFORMATDESCRIPTOR pfd = 55 { 56 sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd 57 1, // version number 58 PFD_DRAW_TO_WINDOW | // support window 59 PFD_SUPPORT_OPENGL | // support OpenGL 60 PFD_DOUBLEBUFFER, // double buffered 61 PFD_TYPE_RGBA, // RGBA type 62 24, // 24-bit color depth 63 0, 0, 0, 0, 0, 0, // color bits ignored 64 0, // no alpha buffer 65 0, // shift bit ignored 66 0, // no accumulation buffer 67 0, 0, 0, 0, // accum bits ignored 68 16, // 16-bit z-buffer 69 0, // no stencil buffer 70 0, // no auxiliary buffer 71 72 PFD_MAIN_PLANE, // main layer 73 0, // reserved 74 0, 0, 0 // layer masks ignored 75 }; 76 //选择像素格式 77 int m_nPixelFormat = ChoosePixelFormat(m_pDC->GetSafeHdc(), &pfd); 78 79 if ( !m_nPixelFormat ) 80 return FALSE; 81 82 //设置像素格式 83 if ( !SetPixelFormat(m_pDC->GetSafeHdc(), m_nPixelFormat, &pfd)) 84 return FALSE; 85 86 return TRUE; 87 } 88 89 void COpenGL::ReShape(GLint witdh,GLint height ) 90 { 91 GLdouble aspect_ratio; // width/height ratio 92 aspect_ratio = (GLdouble)witdh/(GLdouble)height; //计算宽高比 93 94 if ( 0 >= witdh || 0 >= height ) 95 { 96 return; 97 } 98 99 glViewport(0, 0, witdh, height); //设置视口 100 101 glMatrixMode(GL_PROJECTION); //选取投影模型矩阵 102 glLoadIdentity(); //重置投影模型矩阵 103 104 gluPerspective(45.0f, aspect_ratio, 0.1f, 200.0f);//三维视口模型 105 //::gluOrtho2D(-10.0f, 10.0f, -10.0f, 10.0f); //二维视口模型 106 107 glMatrixMode(GL_MODELVIEW); //选取模型视图矩阵 108 glLoadIdentity(); //重置模型视图矩阵 109 } 110 111 void COpenGL::DestoryGL() 112 { 113 if(!wglMakeCurrent (0,0)) //解除设备描述表关联 114 MessageBoxA(NULL,"设备描述表RC解除关联失败","警告",MB_OK|MB_ICONWARNING); 115 if(!wglDeleteContext (m_hRC)) //删除设备描述表 116 MessageBoxA(NULL,"删除设备描述表RC失败","警告",MB_OK|MB_ICONWARNING); 117 118 if(m_pDC) //删除绘图设备上下文DC 119 delete m_pDC; 120 m_pDC = NULL; 121 } 122 123 void COpenGL::RenderScene(HDC hDC) 124 { 125 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer 126 glLoadIdentity(); // Reset The Current Modelview Matrix 127 128 glTranslatef(0.0f,0.0f,-6.0f); // Move Left 1.5 Units And Into The Screen 6.0 129 glRotatef(30,0.0f,1.0f,0.0f); // Rotate The Triangle On The Y axis ( NEW ) 130 131 glBegin(GL_TRIANGLES); // Start Drawing A Triangle 132 glColor3f(1.0f,0.0f,0.0f); // Red 133 glVertex3f( 0.0f, 1.0f, 0.0f); // Top Of Triangle (Front) 134 135 glColor3f(0.0f,1.0f,0.0f); // Green 136 glVertex3f(-1.0f,-1.0f, 1.0f); // Left Of Triangle (Front) 137 138 glColor3f(0.0f,0.0f,1.0f); // Blue 139 glVertex3f( 1.0f,-1.0f, 1.0f); // Right Of Triangle (Front) 140 141 glColor3f(1.0f,0.0f,0.0f); // Red 142 glVertex3f( 0.0f, 1.0f, 0.0f); // Top Of Triangle (Right) 143 144 glColor3f(0.0f,0.0f,1.0f); // Blue 145 glVertex3f( 1.0f,-1.0f, 1.0f); // Left Of Triangle (Right) 146 147 glColor3f(0.0f,1.0f,0.0f); // Green 148 glVertex3f( 1.0f,-1.0f, -1.0f); // Right Of Triangle (Right) 149 150 glColor3f(1.0f,0.0f,0.0f); // Red 151 glVertex3f( 0.0f, 1.0f, 0.0f); // Top Of Triangle (Back) 152 153 glColor3f(0.0f,1.0f,0.0f); // Green 154 glVertex3f( 1.0f,-1.0f, -1.0f); // Left Of Triangle (Back) 155 156 glColor3f(0.0f,0.0f,1.0f); // Blue 157 glVertex3f(-1.0f,-1.0f, -1.0f); // Right Of Triangle (Back) 158 159 glColor3f(1.0f,0.0f,0.0f); // Red 160 glVertex3f( 0.0f, 1.0f, 0.0f); // Top Of Triangle (Left) 161 162 glColor3f(0.0f,0.0f,1.0f); // Blue 163 glVertex3f(-1.0f,-1.0f,-1.0f); // Left Of Triangle (Left) 164 165 glColor3f(0.0f,1.0f,0.0f); // Green 166 glVertex3f(-1.0f,-1.0f, 1.0f); // Right Of Triangle (Left) 167 glEnd(); // Done Drawing The Pyramid 168 169 glFlush(); 170 SwapBuffers(hDC); 171 }
然后为了在整个MFC程序中可以调用这个类,我们需要在CxxxApp这个类中实例化一个COpenGL类,也有另外一个办法,可以将COpenGL类的成员全部定义为静态方法和静态属性,我这里用了第一种方法。
然后在CXXXview.cpp中进行各种消息的响应,这里主要是这几个消息:WM_CREATE (for OnCreate), WM_DESTROY (for OnDestroy), WM_SIZE (for OnSize), WM_ERASEBACKGROUND (for OnEraseBkground).具体响应的代码如下:

1 int CDrawOpenGLView::OnCreate(LPCREATESTRUCT lpCreateStruct) 2 3 { 4 5 if (CView::OnCreate(lpCreateStruct) == -1) 6 7 return -1; 8 9 10 11 // TODO: 在此添加您专用的创建代码 12 13 //初始化openGL绘图 14 ((CDrawOpenGLApp*)AfxGetApp())->m_OpenGL.InitializeOpenGL(this); 15 16 17 return 0; 18 19 } 20 void CDrawOpenGLView::OnDraw(CDC* /*pDC*/) 21 { 22 CDrawOpenGLDoc* pDoc = GetDocument(); 23 ASSERT_VALID(pDoc); 24 if (!pDoc) 25 return; 26 27 // TODO: 在此处为本机数据添加绘制代码 28 29 ((CDrawOpenGLApp*)AfxGetApp())->m_OpenGL.RenderScene(::GetDC(this->m_hWnd));//绘图都放在这 30 } 31 void CDrawOpenGLView::OnSize(UINT nType, int cx, int cy) 32 { 33 CView::OnSize(nType, cx, cy); 34 35 // TODO: 在此处添加消息处理程序代码 36 ((CDrawOpenGLApp*)AfxGetApp())->m_OpenGL.ReShape(cx,cy); 37 } 38 void CDrawOpenGLView::OnDestroy() 39 { 40 CView::OnDestroy(); 41 42 // TODO: 在此处添加消息处理程序代码 43 44 ((CDrawOpenGLApp*)AfxGetApp())->m_OpenGL.DestoryGL(); 45 }
做完这些,还有一个为了使改变窗口大小时严重的闪烁,在OnEraseBkgnd里做一些操作,避免windows自己的窗口刷新闪烁。
BOOL CDrawOpenGLView::OnEraseBkgnd(CDC* pDC) { // TODO: 在此添加消息处理程序代码和/或调用默认值 //return CView::OnEraseBkgnd(pDC); return TRUE; }
补:1.为了在MFC里面顺利使用OpenGL的各种库函数,你需要在stdafx里面添加opengl的头文件和链接库(我喜欢用#pragam comment()的方式)。代码如下:
#include <gl/GL.h> #include <gl/GLU.h> #pragma comment(lib,"opengl32.lib") #pragma comment(lib,"glu32.lib") #pragma comment(lib,"glut.lib") #pragma comment(lib,"glaux.lib")
温馨提示:1.为了不必要的报错,请在stdafx的最后面加入这些头文件和库文件
2.设置窗口显示风格。窗口创建之前我们必须设置窗口风格包含WS_CLIPCHILDREN和 WS_CLIPSIBLINGS,从而避免OpenGL绘制到其他窗口中去。这些应该放在PreCreateWindow()中。代码如下:
BOOL CDrawOpenGLView::PreCreateWindow(CREATESTRUCT& cs) { // TODO: 在此处通过修改 // CREATESTRUCT cs 来修改窗口类或样式 cs.style |=WS_CLIPCHILDREN|WS_CLIPSIBLINGS; return CView::PreCreateWindow(cs); }