轉載地址:https://blog.csdn.net/u013232740/article/details/47904115
------------------------------------------------------------------------------------------------------------
本例在Visual Studio 2013環境下使用OpenGL,提供一個基本的開發應用程序框架。
第一步:OpenGL基礎設置:
1.創建一個單文檔的MFC應用程序,命名為TestGL,然后在TestGLView.h頭文件中添加以下兩條include包含語句:
#include "gl/gl.h" #include "gl/glu.h"
2.設置程序為靜態運行方式
執行菜單命令:項目->屬性,彈出屬性對話框,選擇配置屬性->常規->MFC使用->在靜態庫中使用MFC,然后單擊確定。這樣做會使程序變得很大,但是它編譯生成的可執行程序可以在其他計算機中運行。
3.鏈接OpenGL庫文件
執行菜單命令:項目->屬性打開屬性對話框,選擇配置屬性->鏈接器->常規->附加庫路徑,輸入OpenGL的庫文件所在的路徑,單擊確定。比如我的機子如下:
再選擇配置屬性->鏈接器->輸入->附加依賴庫,在彈出的對話框中輸入OpenGL的庫文件OpenGL32.lib和glu32.lib,如下:
然后確定結束屬性配置。編譯運行,如果沒有錯誤則表明配置正確。
第二步:在Visual Studio下用OpenGL繪制三棱錐:
繪制步驟如下:
*通過PIXELFORMATDESCRIPTOR結構設置設備描述表DC的像素格式和屬性;
*創建渲染描述表RC,並和DC建立聯系;
*使用OpenGL做圖;
*釋放所占用的資源,包括解除DC和RC的聯系,刪除RC及其與之關聯的DC;
為應用程序添加變量和函數,對相關變量進行初始化,然后在函數中實現DC像素格式設置,RC的創建及其與DC 的關聯,圖形繪制以及資源釋放等功能。
1.添加成員變量和成員函數:
為CTestGLView類添加公共變量:
CClientDC* pDrawDC; // 用於指向當前DC的指針
通過向導自動添加后,會在CTestGLView類的構造函數中將其初始化為NULL:
CTestGLView::CTestGLView() : pDrawDC(NULL) { // TODO: 在此處添加構造代碼 }
然后為CTestGLView添加三個公共成員函數:
void DrawGraphics(void);// 用於后續圖形繪制 BOOL PixelformatSetting(void); // 用於設置像素格式 void GLSetting(void); // 用於創建渲染描述表
此時在TestGLView.cpp文件中可以看到添加消息的消息映射宏ON_WM_CREATE()和對應的OnCreate()函數。該消息響應在建立一個窗體前將被調用,因此可在其中做一些初始設置。
同樣的方法添加另外兩個消息響應函數:
OnDestroy():響應WM_DESTROY消息,宏為ON_WM_DESTROY(),窗口銷毀時響應此函數,因此應該在此釋放函數中所占用的資源。
OnSize():響應WM_SIZE消息,宏為ON_WM_SIZE()。改變窗口大小時響應此函數,因此可在此函數中調整視場。
3.為成員函數和消息響應函數添加代碼:
1)設置像素格式。在BOOL CTestGLView::PixelformatSetting(void)函數中添加如下代碼:
// 用於設置像素格式 BOOL CTestGLView::PixelformatSetting(void) { static PIXELFORMATDESCRIPTOR pfd={ sizeof(PIXELFORMATDESCRIPTOR), //結構體長度 1, //版本 PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, //在窗口中繪圖|支持進行OpenGL調用|雙緩存模式 PFD_TYPE_RGBA, //RGBA顏色模式 24, //使用24位顏色 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ,0, 32, //深度緩沖區大小 0, 0, PFD_MAIN_PLANE, 0, 0, 0, 0 }; //填充PIXELFORMATDESCRIPTOR像素格式 int ipixelformat; //獲取最佳匹配的像素格式索引 if((ipixelformat = ChoosePixelFormat(pDrawDC->GetSafeHdc(),&pfd)) == 0) { MessageBox(_T("Choose pixel format failed!")); return TRUE; } //把DC的像素格式設置成由索引值ipixelformat指向的像素格式 if(SetPixelFormat(pDrawDC->GetSafeHdc(),ipixelformat,&pfd) == FALSE) { MessageBox(_T("Set pixel format failed !")); return FALSE; } return TRUE; }
2).創建渲染描述表:
在函數void CTestGLView::GLSetting(void)中調用PixelformatSetting(void)設置像素格式,然后創建和DC關聯的渲染描述表,代碼如下:
// 用於創建渲染描述表 void CTestGLView::GLSetting(void) { HGLRC hRC; //渲染描述表句柄 pDrawDC = new CClientDC(this); //使pDrawDC指向當前DC ASSERT(pDrawDC !=NULL); //斷言pDrawDC不為空 if(!PixelformatSetting()) //設置像素格式 return; //創建和當前DC兼容的RC,並和當前DC關聯 hRC = wglCreateContext(pDrawDC->GetSafeHdc()); wglMakeCurrent(pDrawDC->GetSafeHdc(),hRC); }
3).在消息響應函數OnCreate()函數中調用GLSetting()函數,使上述設置生效,代碼如下:
int CTestGLView::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CView::OnCreate(lpCreateStruct) == -1) return -1; // TODO: Add your specialized creation code here GLSetting(); //該函數用來創建渲染描述表 return 0; }
4).投影變換和視口變換。
在OnSize()中添加代碼設置投影變換和視口變換,如下所示:
void CTestGLView::OnSize(UINT nType, int cx, int cy) { CView::OnSize(nType, cx, cy); // TODO: Add your message handler code here if(cy>0) { glMatrixMode(GL_PROJECTION); //啟動投影矩陣,4×4 glLoadIdentity(); //初始化為單位矩陣 gluPerspective(45.0f,cx/cy,0.0f,30.0f); //設置透視投影變換,指定視場 glViewport(0, 0, cx, cy); //設置視場,即定義顯示范圍 } RedrawWindow(); //顯示更新 }
5).繪制三棱錐:
在void CTestGLView::DrawGraphics(void)函數中,添加代碼繪制3個三角形,構成一個三棱錐,如下:
void CTestGLView::DrawGraphics(void) { glTranslatef(0.0f, 0.0f, -6.0f); //移動物體到顯示區 glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); //以邊線方式繪制三角形 //繪制3個三角形的三個頂點 glBegin(GL_TRIANGLES); glVertex3f(-0.6f, 0.0f, 0.0f); glVertex3f(0.6f, 0.0f, 0.0f); glVertex3f(0.0f, 0.15f, 0.6f); glVertex3f(-0.6f, 0.0f, 0.0f); glVertex3f(0.0f, 0.15f, 0.6f); glVertex3f(0.0f, 0.9f, 0.6f); glVertex3f(0.0f, 0.9f, 0.6f); glVertex3f(0.0f, 0.15f, 0.6f); glVertex3f(0.6f, 0.0f, 0.0f); glEnd(); }
6).在OnDraw()函數中設置背景並調用DrawGraphics()函數繪制圖形。
通常使用CView類的成員函數OnDraw()繪制用戶界面,此外還可以在該函數中添加代碼完成背景色設置,然后調用DrawGraphics()函數完成繪制。
void CTestGLView::OnDraw(CDC* /*pDC*/) { CTestGLDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) return; // TODO: 在此處為本機數據添加繪制代碼 static BOOL bBusy = FALSE; //定義開關變量 //繪制完成后才可以更新緩存 if(bBusy) return; bBusy =TRUE; glClearColor(0.0f, 0.0f, 0.5f, 0.5f); //設置背景顏色 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //清除深度緩存和顏色緩存 glMatrixMode(GL_MODELVIEW); //啟動模型矩陣 glLoadIdentity(); //初始化為單位矩陣 DrawGraphics(); //繪制圖形 SwapBuffers(wglGetCurrentDC()); //更新緩存 bBusy=FALSE; }
7).刪除渲染描述表。
在消息響應函數OnDestroy()中刪除渲染描述表及其綁定的設備描述表,代碼如下:
void CTestGLView::OnDestroy() { CView::OnDestroy(); // TODO: Add your message handler code here HGLRC hRC; hRC=::wglGetCurrentContext(); //獲取當前RC句柄 ::wglMakeCurrent(NULL,NULL); //解除當前RC和DC的關聯,並把當前RC非當前化 if(hRC) { ::wglDeleteContext(hRC); //刪除RC } if(pDrawDC) { delete pDrawDC; //刪除DC } }
編譯運行項目,如果沒有錯,可得結果如下:
4.添加旋轉功能:
實現一個交互功能,即單擊鼠標開始/停止三棱錐旋轉。
1).添加消息響應函數。
為CTestGLView類添加鼠標左鍵消息WM_LBUTTONDOWN和定時器消息WM_TIME,鼠標左鍵消息響應函數OnLButtonDown(),宏ON_WM_LBUTTONDOWN()。定時器消息響應函數為OnTimer(),宏ON_WM_TIMER().
2).為CTestGLView類添加兩個共有屬性的成員變量,
BOOL bRotate; // 控制圖形旋轉 float RotateAngle; // 旋轉角度
Visual Studio會自動在CTestGLView類的構造函數中將bRotate初始化為FALSE,將RotateAngle初始化為0.手動將bRotate的初始值改為TRUE。
3).在void CTestGLView::OnLButtonDown(UINT nFlags, CPoint point)函數中添加如下代碼,通過單擊啟動/停止定時器,
void CTestGLView::OnLButtonDown(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default if(bRotate) { SetTimer(1,100,NULL); //設置定時器1,100ms觸發一次 } else { KillTimer(1); //移除定時器1 } bRotate = !bRotate; //更新bRotate的值 CView::OnLButtonDown(nFlags, point); }
4).設置旋轉角度。在定時器消息響應函數OnTimer()中添加如下代碼,實現每次定時到達時都能將圖形旋轉10度
void CTestGLView::OnTimer(UINT_PTR nIDEvent) { // TODO: Add your message handler code here and/or call default //若定時器1到達預定時刻,則旋轉角度增加10度 if(nIDEvent == 1) { RotateAngle += 10.0f; Invalidate(FALSE); //使當前窗口失效,重新繪制 } CView::OnTimer(nIDEvent); }
在OnTimer()函數中使用的Invalidate()函數作用是將整個客戶區失效,從而被重新繪制,而最終的重繪工作由OnDraw()函數完成。此處用函數Invalidate()函數調用了OnDraw()函數來繪制旋轉后的圖形。
5).每次按照設置的角度重繪圖形。重繪窗口由OnDraw()函數完成,而OnDraw()函數調用DrawGraphics()函數繪制圖形。因此在函數DrawGraphics()函數中需添加如下代碼:
glRotated(RotateAngle,1.0, 1.0, 1.0); //按設定的角度RotateAngle旋轉圖形
將這句代碼放在glTranslatef()函數語句之后。使得每次重繪時將圖形繞着從原點指向(1.0,1.0,1.0)的射線旋轉RotateAngle的角度,而RotateAngle的值在定時器函數OnTimer()中更新。這樣就可以實現每次單擊鼠標左鍵,定時器開始計時,每個100ms后響應定時器消息的函數OnTimer()將RotateAngle的值增加10度,同時Invalidate()函數使界面失效而被重繪,重繪是將圖形選擇RotateAngle的角度,有時間間隔短,所以看上去就會產生三棱錐旋轉的效果。當鼠標在此單擊左鍵時,定時器被取消,圖形停止旋轉。
===================================================================================================================================
原貼地址:https://blog.csdn.net/u013232740/article/details/47904115