上文中,,是在對話框的基礎上,利用Picture控件進行OpenGL繪制的,,那么現在是基於一個新的類進行的OpenGL繪制,也有一個Demo,,是用GDI和OpenGL分別繪制的,,聲明,,這是別人的Demo,拿來試用一下。。示例
我也是學習了這些資料之后才懂得怎么做的。。
以三維動態球體模型來講述基於MFC對話框的OpenGL編程
1.基本思想
在Windows98/NT平台下,GDI是原始窗口的圖形接口。而GDI實現這些是通過一個設備描述表DC來實現的。現在通過OpenGL繪圖需要創建繪圖描述表RC。但是RC並不能直接完成繪圖,只能與特定的DC聯系起來,從而完成具體的繪圖工作。最后要注意釋放RC和DC。
2. 編程步驟
第一步,設置開發環境
現在以Windows2000為例,首先將glu.dll,glu32.dll,glut.dll,glut32.dll,opengl32.dll文件拷貝到操作系統WINNT/System32目錄下,將gl.h,glaux.h,glu.h,glut.h拷貝到Microsoft Visual Studio/VC98/Include/GL目錄中中,將glaux.lib,glu32.lib,glut32.lib,opengl32.lib拷貝到Microsoft Visual Studio/VC98/Lib目錄中;然后在編譯程序的時候選擇Project|Setting菜單,在Link標簽中的Object/library modules編輯框中輸入“opengl32.lib, glut32.lib ,glu32.lib,glaux.lib”。到這時候環境就建立好了,可以進行下面的具體編程工作。
第二步,具體編程
本實例采用基於對話框的工程。至於用單文檔方式和多文檔方式其編程原理是一樣的,這里不再作單獨介紹。
2.1創建項目文件。選擇File|New菜單項,新建一個基於對話框的項目文件MyDlgOpenGL;
2.2 修改對話框模板。刪除對話框中的靜態文本,調整控件的位置。
2.3 創建新類,添加消息映射。選擇View|ClassWizard菜單項,打開MFC對話框,在Add Class之中選擇New,以便添加一個新類COpenGL,且該類的基類選擇generic CWnd;最后利用MFC ClassWizard為COpenGL類添加消息WM_CREATE,WM_PAINT的映射。
2.4 添加代碼。
2.4.1 定義像素格式 ,創建OpenGL顯示。
在OpenGL能夠在一個繪圖對象中繪圖之前,該繪圖對象必須初始化。為此引入像素格式的概念。像素格式能告訴OpenGL是否使用雙緩存,顏色模式,顏色位數,深度位數等等重要信息。它由一個被稱作PIXELFORMATDESCRIPTOR的所描述。於是定義在OpenGL.h中定義函數int MySetPixelFormat(HDC hdc)。然后在OpenGL.cpp文件中加入如下代碼:
int COpenGL::MySetPixelFormat(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 iPixelFormat;
// 為設備描述表得到最匹配的像素格式
if((iPixelFormat = ChoosePixelFormat(hdc, &pfd)) == 0)
{
MessageBox("ChoosePixelFormat Failed", NULL, MB_OK);
return 0;
}
// 設置最匹配的像素格式為當前的像素格式
if(SetPixelFormat(hdc, iPixelFormat, &pfd) == FALSE)
{
MessageBox("SetPixelFormat Failed", NULL, MB_OK);
return 0;
}
return 1;
}
現在就可以在OnCreate函數中創建繪圖描述表。其代碼如下:
int COpenGL::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CWnd::OnCreate(lpCreateStruct) == -1)
return -1;
MySetPixelFormat(::GetDC(m_hWnd)); // 設置當前的繪圖像素格式
hdc = ::GetDC(m_hWnd); // 獲得繪圖描述表
hglrc = wglCreateContext(hdc); // 創建繪圖描述表
wglMakeCurrent(hdc, hglrc); // 使繪圖描述表為當前調用現程的當前繪圖描述表
return 0;
}
2.4.2 進行光照處理,添加OpenGL顯示。
在OpenGL.h中定義函數LightShine函數,作為添加光源和材質屬性的函數。在該函數中將創建兩個光源,並使其位於不同位置,以產生不同的效果。定義:環境光,散射光,鏡面光和鏡面反射指數。因為沒有一種光源完全由以上三種中的一種光源組成,所以任何一種光源都是由以上三種光源的光照成分組成的,即為混合光源。其成分值由RGBA定義。用材料對光的三原色的反射率來定義材料的顏色,與光源相對應,。代碼如下:
void COpenGL::LightShine(void)
{
GLfloat mat_diffuse[4]={1,0.5,0.5,1.0};
GLfloat mat_specular[4]={1.0,1.0,1.0,1.0};
GLfloat mat_shininess[1]={100.0};
//光源 1
GLfloat light_position0[4]={0,500,500,0};
glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_diffuse);
glMaterialfv(GL_FRONT,GL_SPECULAR,mat_specular);
glMaterialfv(GL_FRONT,GL_SHININESS,mat_shininess);
glLightfv(GL_LIGHT0,GL_POSITION,light_position0);
glEnable(GL_LIGHT0);
//光源 2
GLfloat light_position1[4]={1000,-1000,1000,0};
GLfloat mat_diffuse1[4]={0.5,0.5,1.0,1.0};
glLightfv(GL_LIGHT1,GL_DIFFUSE,mat_diffuse1);
glLightfv(GL_LIGHT1,GL_SPECULAR,mat_specular);
glLightfv(GL_LIGHT1,GL_SHININESS,mat_shininess);
glLightfv(GL_LIGHT1,GL_POSITION,light_position1);
glEnable(GL_LIGHT1);
//使模型能接受光照
glEnable(GL_LIGHTING);
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE);
glDepthFunc(GL_LESS);
glEnable(GL_DEPTH_TEST);
//計算定點法線
glEnable(GL_AUTO_NORMAL);
glEnable(GL_NORMALIZE);
}
2.4.3 定義繪圖窗口
所繪球體在哪個區域內進行繪制以及這個區域的風格是怎樣的必須需要進行定義。為下一步的繪圖工作打下基礎。那么可以在MyDlgOpenGLDlg.cpp的函數OnInitDialog()中加入如下代碼:
CRect rect(7, 7, 300, 300); //定義繪圖區域的大小
m_pDisplay->Create( NULL,
NULL,
//定義窗口風格
WS_CHILD|WS_CLIPSIBLINGS|WS_CLIPCHILDREN|WS_VISIBLE,
rect,
this,
0);
2.4.4 繪制圖象
在前面的准備之后,現在可以在OnPaint函數中繪制圖象。在具體進行繪制物體時,需要注意的是:glPushMatrix()與glPopMatrix()的使用必須成對出現。此外,必須正確使用glScale() 函數和glRatate() 函數以及雙緩存技術,以實現所繪球體的在指定窗口由遠及近,由小變大的旋轉。代碼如下:
void COpenGL::OnPaint()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
space+=0.005;
if(space>1.0)
space=0.1;
step = step + 1.0;
if (step > 360.0)
step = step - 360.0;
glPushMatrix();
glScalef(space,space,space);
glRotatef(step,0.0,1.0,0.0);
glRotatef(step,0.0,0.0,1.0);
glRotatef(step,1.0,0.0,0.0);
LightShine(); //添加光照屬性
glutSolidSphere(1.0,20,16); //繪制球體
glPopMatrix();
glFlush();
SwapBuffers(hdc); //使用雙緩存技術實現交換緩沖區
}
2.4.5 結束運行
在結束運行時,我們必須將一些環境變量釋放。於是應該在添加的類COpenGL的析構函數中進行操作,以釋放DC和刪除RC。代碼如下:
COpenGL::~COpenGL()
{
wglMakeCurrent(NULL, NULL) ;
wglDeleteContext(hglrc); //刪除繪圖描述表
::ReleaseDC (m_hWnd, hdc) ; //釋放設備描述表
}
結語
利用Visual C++強大的窗口功能完成了OpenGL繪制球體的程序的編制工作,上述程序運行正常,其結果是一個動態的球體。理解了上述編程過程,就可以使我們自如地運用MFC進行其他的OpenGL編程。