在MFC框架中使用OpenGL的簡單實例


引言

  我們知道,在MFC框架中,用於繪圖的接口是GDI。但GDI只能繪制簡單的2D圖形,要想制作精美的3D圖形,一個可行的辦法是使用OpenGL或者Direct3D等第三方庫。

  由於最近在給導師的一個小項目幫忙,而且要求使用OpenGL,所以我特地在網上搜索“如何在MFC框架中使用OpenGL”,看了很多博文,甚至論文(居然還有人把這個寫成論文)后,自己又到VS2012上嘗試了一番,最終摸索出了最最簡單基本的使用方法,故總結在這里。一方面開啟自己在博客園的學習和自省之路,另一方面也為需要的朋友提供點小小的幫助。相信這個實例會是最簡單最容易理解的。

摘要

  GDI繪圖使用的是HDC,而OpenGL使用的則是HGLRC。與D2D通過把RenderTarget綁定到HDC以實現和GDI的混用的方法類似,OpenGL要想與HDC混用,或者說兼容HDC吧,需要使用wglCreateContext()函數來通過HDC創建一個HGLRC並把它選為當前所使用的環境。不過在此之前,我們還需要把像素格式設置成支持OpenGL的格式。另外,窗口也必須被改為特定的樣式才能被OpenGL使用。做好了這三點,就能在MFC框架中使用OpenGL進行繪制了。

具體實現步驟

1. 封裝OpenGL類

  首先,基於OOP的思想,我們把跟OpenGL相關的數據與操作封裝起來:

#pragma once
class COpenGL
{
private:
  HDC hDC;     //GDI繪圖中使用的的設備環境句柄
  HGLRC hRC;    //OpenGL渲染時使用的渲染環境句柄

public:
  COpenGL(void);
  virtual ~COpenGL(void);
    
  bool SetupPixelFormat(HDC hdc);  //設置像素格式為適合OpenGL的格式
  void Init(void);           //初始化渲染過程中屬性的設置
  void Render(void);          //繪制代碼

  void Reshape(int width,int height);  //改變窗口大小時對視窗進行的操作
};
#include "stdafx.h"
#include "OpenGL.h"


COpenGL::COpenGL(void)
{
}


COpenGL::~COpenGL(void)
{
    wglMakeCurrent(hDC, NULL);
    wglDeleteContext(hRC);
}


void COpenGL::Init(void)
{  
    //可添加例如“開啟深度探測”等繪圖屬性設置代碼
}


bool COpenGL::SetupPixelFormat(HDC hdc)
{
    hDC=hdc;

    PIXELFORMATDESCRIPTOR pfd = 
    {
       sizeof(PIXELFORMATDESCRIPTOR),    // pfd結構的大小
       1,                                // 版本號
       PFD_DRAW_TO_WINDOW |              // 支持在窗口中繪圖
       PFD_SUPPORT_OPENGL |              // 支持OpenGL
       PFD_DOUBLEBUFFER,                 // 雙緩存模式
       PFD_TYPE_RGBA,                    // RGBA 顏色模式
       24,                               // 24 位顏色深度
       0, 0, 0, 0, 0, 0,                 // 忽略顏色位
       0,                                // 沒有非透明度緩存
       0,                                // 忽略移位位
       0,                                // 無累加緩存
       0, 0, 0, 0,                       // 忽略累加位
       32,                               // 32 位深度緩存   
       0,                                // 無模板緩存
       0,                                // 無輔助緩存
       PFD_MAIN_PLANE,                   // 主層
       0,                                // 保留
       0, 0, 0                           // 忽略層,可見性和損毀掩模
    };

    int nPixelFormat;    // 像素點格式
    if (!(nPixelFormat = ChoosePixelFormat(hDC, &pfd)))
    { 
        MessageBox(NULL,L"can not find proper mode",L"Error",MB_OK|MB_ICONEXCLAMATION);
        return FALSE;
    }

    SetPixelFormat(hDC,nPixelFormat,&pfd);
    hRC = wglCreateContext(hDC);    //利用GDI繪圖所使用的HDC創建對應的HGLRC
    wglMakeCurrent(hDC, hRC);        //使OpenGL繪圖所使用的HGLRC為當前繪圖工具

    return TRUE;
}


void COpenGL::Render()
{
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);        
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();                        
 
    //繪制操作:
    glColor3ub(255,0,0);
    glBegin(GL_POLYGON);//填充凸多邊形
        glVertex3f(0.5f,0.5f ,0.0f);
        glVertex3f(0.5f,-0.5f, 0.0f);
        glVertex3f(-0.5f,-0.5f,0.0f);
        glVertex3f(-0.5f,0.5f,0.0f);
    glEnd();
   
    glFlush();
    SwapBuffers(hDC);
}


void COpenGL::Reshape(int width,int height)
{
    glViewport(0,0,width,height);
}

 2. 使用OpenGL類

  接下來,我們在MFC框架中的CProjNameView類中創建剛剛編寫的OpenGL類成員並進行相應的調用和操作來進行繪制:

  先在頭文件中添加成員變量:

COpenGL opengl;

  然后,改寫CProjNameView::PreCreateWindow()函數以改變窗口樣式來適應OpenGL的要求:

BOOL CProjNameView::PreCreateWindow(CREATESTRUCT& cs)
{
    // TODO: 在此處通過修改
    //  CREATESTRUCT cs 來修改窗口類或樣式
    cs.style|=WS_CLIPSIBLINGS|WS_CLIPCHILDREN;

    return CView::PreCreateWindow(cs);
}

  再在CProjNameView::OnInitialUpdate()函數中添加設置像素格式、轉換當前繪圖所使用的環境和初始化OpenGL繪制屬性的操作。(這里我們省去了初始化操作,即省去了OpenGL.cpp中的Init()函數的代碼。設置像素格式、轉換當前繪圖所使用的環境都包含在COpenGL類的成員函數SetupPixelFormat()中)

void CProjNameView::OnInitialUpdate()
{
    CView::OnInitialUpdate();

    // TODO: 寫入最終選擇模式代碼之后移除此代碼
    m_pSelection = NULL;    // 初始化所選內容
   opengl.SetupPixelFormat(::GetDC(GetSafeHwnd()));
    opengl.Init();
} 

  接下來,在CProjNameView::OnDraw()函數中添加繪制操作。

void CProjNameView::OnDraw(CDC* /*pDC*/)
{
    CFaceModelingDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    if (!pDoc)
        return;

    // TODO: 在此處為本機數據添加繪制代碼
    opengl.Render();
}

  最后,再改寫CProjNameView::OnSize()函數,就大功告成了!(當然,這個並不是本例子中必要的,沒有這項控制也能成功繪制。)

void CProjNameView::OnSize(UINT nType, int cx, int cy)
{
    if(cx==0)
    {
       cx=1;
    }
    opengl.Reshape(cx,cy);
}

  

  效果圖如下:

補充

  當然,事先需要包含gl.h和glut.h兩個頭文件,他們一般都在GL文件夾目錄下,而且gl.h是自帶的,glut.h是需要自己擴展的。另外,還需要把glut.lib添加到工程可見的范圍內。方便起見,我在這里提供一下glut的下載鏈接:glut擴展包

  另外,在MFC中使用OpenGL的繪制列表和紋理時要注意,MFC貌似不支持OpenGL的繪制列表,而且MFC似乎要求在每次繪制前都要設置一次紋理。這之中的道理只有深入了解MFC和OpenGL后才能明白了,如果有朋友知道的話,希望能在評論里給一些指導哦~!

  如果還有什么問題或是建議的話,希望大家提出來!新人第一次寫隨筆,還請多多指教~!

 


免責聲明!

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



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