MFC+OpenGL基礎繪制<轉>


轉載地址: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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM