1、基於MFC的OpenGL程序


首先,使用的庫是GLUT以及GLAUX,先下載兩者,添加查找路徑以及鏈接

 
一、單文本文件  
工程openGLMFC
1、創建單文本文件
 
2、添加路徑、鏈接
方法如之前篇章所示,
鏈接庫為opengl32.lib ;glu32.lib ;glut32.lib ;glaux.lib
 
3、頭文件
在stdafx.h中加入下列語句:
//openGL 所需要的頭文件
#include <gl/gl.h>
#include <gl/glu.h>
#include <gl/glut.h>
#include <gl/glaux.h>
4、設置窗口風格
將窗口風格設為 WS_CLIPCHILDREN WS_CLIPSIBLINGS,從而避免OpenGL繪制到其他窗口中去。這些應該放在PreCreateWindow()中。
BOOL CopenGLMFCView::PreCreateWindow(CREATESTRUCT& cs)
{
    // TODO: Modify the Window class or styles here by modifying
    //  the CREATESTRUCT cs
    cs.style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
    return CView::PreCreateWindow(cs);
}

 

5、變量、函數聲明
初始化GL,考慮到使用設備上下文、繪圖上下文,
先在openGLMFCView.h中聲明需要的變量以及函數
HGLRC m_hRC;    //RC 繪圖上下文
CDC* m_pDC;        //DC 設備上下文
BOOL InitializeOpenGL();    //初始化 OpenGL
BOOL SetupPixelFormat();    //為 DC 建立像素格式
6、創建消息響應函數
初始化需要在WM_CREATE觸發
資源釋放在WM_DESTROY觸發
窗口大小變化時  WM_SIZE觸發,需要調整繪圖
由於使用opengl繪制背景,故不需要窗口自己在繪制背景了,需要改寫  WM_ERASEBACKGROUND消息觸發的事件
 
故,打開classWizard,在openGLMFCView類中添加上面四個消息響應函數

OnCreate   OnDestroy  OnSize  OnEraseBkground

 
7、初始化

將通過建立像素格式和繪制上下文來初始化OpenGL. 在InitializeOpenGL()中會創建一個設備上下文(DC),為這個DC選擇一個像素格式,創建和這個DC相關的繪制上下文(RC),然后選擇這個RC.這個函數會調用SetupPixelFormat()來建立像素格式。

int CopenGLMFCView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    if (CView::OnCreate(lpCreateStruct) == -1)
        return -1;

    // TODO:  Add your specialized creation code here
    InitializeOpenGL();
    return 0;
}

BOOL CopenGLMFCView::InitializeOpenGL()
{
    //客戶區獲得DC
    m_pDC = new CClientDC(this);
    //Failure to Get DC
    if (m_pDC == NULL)
    {
        MessageBox(L"Error Obtaining DC");
        return FALSE;
    }
    //為DC建立像素格式
    if (!SetupPixelFormat())
    {
        return FALSE;
    }
    //創建 RC
    m_hRC = ::wglCreateContext(m_pDC->GetSafeHdc());
    //Failure to Create Rendering Context
    if (m_hRC == 0)
    {
        MessageBox(L"Error Creating RC");
        return FALSE;
    }
    //設定OpenGL當前線程的渲染環境。
    //以后這個線程所有的OpenGL調用都是在這個hdc標識的設備上繪制。
    if (::wglMakeCurrent(m_pDC->GetSafeHdc(), m_hRC) == FALSE)
    {
        MessageBox(L"Error making RC Current");
        return FALSE;
    }
    //背景顏色
    ::glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    //深度緩存 1最大,讓任何都能顯示出來
    ::glClearDepth(1.0f);
    //如果通過比較后深度值發生變化了,會進行更新深度緩沖區的操作
    ::glEnable(GL_DEPTH_TEST);
    return TRUE;
}
//建立像素格式
/////////////////////////////////////////////////////////////////////////////
BOOL CopenGLMFCView::SetupPixelFormat()
{
    static PIXELFORMATDESCRIPTOR pfd =
    {
        sizeof(PIXELFORMATDESCRIPTOR),  // size of this pfd
        1,                              // version number
        PFD_DRAW_TO_WINDOW |            // support window
        PFD_SUPPORT_OPENGL |            // support OpenGL
        PFD_DOUBLEBUFFER,                // double buffered
        PFD_TYPE_RGBA,                  // RGBA type
        24,                             // 24-bit color depth
        0, 0, 0, 0, 0, 0,               // color bits ignored
        0,                              // no alpha buffer
        0,                              // shift bit ignored
        0,                              // no accumulation buffer
        0, 0, 0, 0,                     // accum bits ignored
        16,                             // 16-bit z-buffer
        0,                              // no stencil buffer
        0,                              // no auxiliary buffer
        PFD_MAIN_PLANE,                 // main layer
        0,                              // reserved
        0, 0, 0                         // layer masks ignored
    };
    int m_nPixelFormat = ::ChoosePixelFormat(m_pDC->GetSafeHdc(), &pfd);
    if (m_nPixelFormat == 0)
    {
        return FALSE;
    }
    if (::SetPixelFormat(m_pDC->GetSafeHdc(), m_nPixelFormat, &pfd) == FALSE)
    {
        return FALSE;
    }
    return TRUE;
}

 

8、繪制場景
在繪制場景時,一般包括如下步驟:1)清空緩存。2)繪制場景。3)Flush掉渲染流水線。4)若設置了雙緩沖,則交換前后台緩沖區。
void CopenGLMFCView::OnDraw(CDC* /*pDC*/)
{
    CopenGLMFCDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    if (!pDoc)
        return;

    // TODO: add draw code for native data here

    // 清除顏色、深度緩存
    ::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    //可以添加渲染函數

    // Flush掉渲染流水線
    ::glFinish();
    // 交換前后緩存區
    ::SwapBuffers(m_pDC->GetSafeHdc());

}

 9、背景繪制修改

 

試試改變窗口的大小,你會看到很嚴重的閃爍,並且關閉程序后會報告內存泄露,因此我們這就來解決這兩個問題吧。

發生閃爍的原因是Windows先繪制背景,然后再是OpenGL繪制,因為我們已經讓OpenGL負責清空背景色,因此我們不需要Windows去清空背景了

BOOL CopenGLMFCView::OnEraseBkgnd(CDC* pDC)
{
    // TODO: Add your message handler code here and/or call default

    return TRUE;//CView::OnEraseBkgnd(pDC);
}

 內存泄露的原因是我們在InitializeOpenGL()中使用了new運算符來為CClientDC對象分配內存,因此需要顯示delete掉。

void CopenGLMFCView::OnDestroy()
{
    CView::OnDestroy();
 
    // TODO: Add your message handler code here
    if (::wglMakeCurrent(0, 0) == FALSE)
    {
        MessageBox(L"Could not make RC non-current");
    }
 
    //Delete the rendering context
    if (::wglDeleteContext(m_hRC) == FALSE)
    {
        MessageBox(L"Could not delete RC");
    }
    //Delete the DC
    if (m_pDC)
    {
        delete m_pDC;
    }
    //Set it to NULL
    m_pDC = NULL;
}
10、大小調整
在OnSize()中一般用來設置視口和視錐,因為這些是和窗口大小相關的。基本操作包括設置視口,選擇投影矩陣,設置模型視圖矩陣。
void CopenGLMFCView::OnSize(UINT nType, int cx, int cy)
{
    CView::OnSize(nType, cx, cy);

    // TODO: Add your message handler code here
    GLdouble aspect_ratio; // width/height ratio

    if (0 >= cx || 0 >= cy)
    {
        return;
    }
    // select the full client area
    ::glViewport(0, 0, cx, cy);
    // compute the aspect ratio
    // this will keep all dimension scales equal
    aspect_ratio = (GLdouble)cx / (GLdouble)cy;
    // select the projection matrix and clear it
    ::glMatrixMode(GL_PROJECTION);
    ::glLoadIdentity();
    // select the viewing volume
    ::gluPerspective(45.0f, aspect_ratio, .01f, 200.0f);

    // switch back to the modelview matrix and clear it
    ::glMatrixMode(GL_MODELVIEW);
    ::glLoadIdentity();
}

通過上面得到運行結果:

二、基於對話框

 
工程:openGLMFCDialog
1-3步驟同上
4、變量函數聲明
在openGLMFCDialogDlg.h文件中,聲明如上。
其余步驟同上,不同點在於,需要將OnDraw里面的寫到
OnPaint函數里面,其中IsIconic()是判斷是否為最小化,可以放到else里面即可。
得到結果
 


免責聲明!

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



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