基于MFC的OpenGL編程_第1頁
基于MFC的OpenGL編程_第2頁
基于MFC的OpenGL編程_第3頁
基于MFC的OpenGL編程_第4頁
基于MFC的OpenGL編程_第5頁
已閱讀5頁,還剩5頁未讀 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

1、一、簡介 GDI是通過設(shè)備句柄(Device Context以下簡稱DC)來繪圖,而OpenGL則需要繪制環(huán)境(Rendering Context,以下簡稱RC)。每一個GDI命令需要傳給它一個DC,但與GDI不同,OpenGL使用當前繪制環(huán)境(RC)。一旦在一個線程中指定 了一個當前RC,在此線程中其后所有的OpenGL命令都使用相同的當前RC。雖然在單一窗口中可以使用多個RC,但在單一線程中只有一個當前RC。下面我將首先產(chǎn)生一個OpenGL RC并使之成為當前RC,這將分為三個步驟:設(shè)置窗口像素格式;產(chǎn)生RC;設(shè)置為當前RC。二、MFC中的OpenGL基本框架1、首先創(chuàng)建工程 用AppWi

2、zard產(chǎn)生一個MFC EXE項目,其他默認即可。2、將此工程所需的OpenGL文件和庫加入到工程中 在工程菜單中,選擇Build下的Settings項。單擊Link標簽,選擇General目錄,在Object/Library Modules的編輯框中輸入opengl32.lib glu32.lib glut.lib glaux.lib(注意,輸入雙引號中的內(nèi)容,各個庫用空格分開;否則會出現(xiàn)鏈接錯誤),選擇OK結(jié)束。然后打開文件stdafx.h,加入下列頭文件:#include #include 3、改寫OnPreCreate函數(shù)并給視圖類添加成員函數(shù)和成員變量 OpenGL需要窗口加上WS_

3、CLIPCHILDREN(創(chuàng)建父窗口使用的Windows風格,用于重繪時裁剪子窗口所覆蓋的區(qū)域)和WS_CLIPSIBLINGS(創(chuàng)建子窗口使用的Windows風格,用于重繪時剪裁其他子窗口所覆蓋的區(qū)域)風格。把OnPreCreate改寫成如 下所示:BOOL COpenGLDemoView:PreCreateWindow(CREATESTRUCT& cs) / TODO: Modify the Window class or styles here by modifying / the CREATESTRUCT cs cs.style |= (WS_CLIPCHILDREN | WS_CLI

4、PSIBLINGS); return CView:PreCreateWindow(cs); 產(chǎn)生一個RC的第一步是定義窗口的像素格式。像素格式?jīng)Q定窗口著所顯示的圖形在內(nèi)存中是如何表示的。由像素格式控制的參數(shù)包括:顏色深度、緩沖模式和所支持的繪畫接口。在下面將有對這些參數(shù)的設(shè)置。我們先在COpenGLDemoView的類中添加一個保護型的成員函數(shù)BOOL SetWindowPixelFormat(HDC hDC)(用鼠標右鍵添加)和保護型的成員變量:int m_GLPixelIndex;并編輯其中的代碼如下:BOOL COpenGLDemoView:SetWindowPixelFormat(HD

5、C hDC)/定義窗口的像素格式 PIXELFORMATDESCRIPTOR pixelDesc= sizeof(PIXELFORMATDESCRIPTOR), 1, PFD_DRAW_TO_WINDOW|PFD_SUPPORT_OPENGL| PFD_DOUBLEBUFFER|PFD_SUPPORT_GDI, PFD_TYPE_RGBA, 24, 0,0,0,0,0,0, 0, 0, 0, 0,0,0,0, 32, 0, 0, PFD_MAIN_PLANE, 0, 0,0,0 ; this-m_GLPixelIndex = ChoosePixelFormat(hDC,&pixelDesc);

6、 if(this-m_GLPixelIndex=0) this-m_GLPixelIndex = 1; if(DescribePixelFormat(hDC,this-m_GLPixelIndex,sizeof(PIXELFORMATDESCRIPTOR),&pixelDesc)=0) return FALSE; if(SetPixelFormat(hDC,this-m_GLPixelIndex,&pixelDesc)=FALSE) return FALSE; return TRUE;4、用ClassWizard添加WM_CREATE的消息處理函數(shù)OnCreate至此,OpenGL工程的基本框

7、架就建好了。但如果你現(xiàn)在運行此工程,則它與一般的MFC程序看起來沒有什么兩樣。5、代碼解釋現(xiàn)在我們可以看一看Describe-PixelFormat提供有哪幾種像素格式,并對代碼進行一些解釋:PIXELFORMATDESCRIPTOR包括了定義像素格式的全部信息。 DWFlags定義了與像素格式兼容的設(shè)備和接口。通常的OpenGL發(fā)行版本并不包括所有的標志(flag)。wFlags能接收以下標志:PFD_DRAW_TO_WINDOW 使之能在窗口或者其他設(shè)備窗口畫圖;PFD_DRAW_TO_BITMAP 使之能在內(nèi)存中的位圖畫圖;PFD_SUPPORT_GDI 使之能調(diào)用GDI函數(shù)(注:如果指

8、定了PFD_DOUBLEBUFFER,這個選項將無效);PFD_SUPPORT_OpenGL 使之能調(diào)用OpenGL函數(shù);PFD_GENERIC_FORMAT 假如這種象素格式由Windows GDI函數(shù)庫或由第三方硬件設(shè)備驅(qū)動程序支持,則需指定這一項;PFD_NEED_PALETTE 告訴緩沖區(qū)是否需要調(diào)色板,本程序假設(shè)顏色是使用24或 32位色,并且不會覆蓋調(diào)色板;PFD_NEED_SYSTEM_PALETTE 這個標志指明緩沖區(qū)是否把系統(tǒng)調(diào)色板當作它自身調(diào)色板的一部分;PFD_DOUBLEBUFFER 指明使用了雙緩沖區(qū)(注:GDI不能在使用了雙緩沖區(qū)的窗口中畫圖);PFD_STEREO

9、 指明左、右緩沖區(qū)是否按立體圖像來組織。PixelType定義顯示顏色的方法。PFD_TYPE_RGBA意味著每一位(bit)組代表著紅、綠、藍各分量的值。PFD_TYPE_COLORINDEX 意味著每一位組代表著在彩色查找表中的索引值。本例都是采用了PFD_TYPE_RGBA方式。 cColorBits定義了指定一個顏色的位數(shù)。對RGBA來說,位數(shù)是在顏色中紅、綠、藍各分量所占的位數(shù)。對顏色的索引值來說,指的是表中的顏色數(shù)。 cRedBits、cGreenBits、cBlue-Bits、cAlphaBits用來表明各相應(yīng)分量所使用的位數(shù)。 cRedShift、cGreenShift、cBl

10、ue-Shift、cAlphaShift用來表明各分量從顏色開始的偏移量所占的位數(shù)。一旦初始化完我們的結(jié)構(gòu),我們就想知道與要求最相近的系統(tǒng)象素格式。我們可以這樣做:m_hGLPixelIndex = ChoosePixelFormat(hDC, &pixelDesc); ChoosePixelFormat接受兩個參數(shù):一個是hDc,另一個是一個指向PIXELFORMATDESCRIPTOR結(jié)構(gòu)的指針& pixelDesc;該函數(shù)返回此像素格式的索引值。如果返回0則表示失敗。假如函數(shù)失敗,我們只是把索引值設(shè)為1并用 DescribePixelFormat得到像素格式描述。假如你申請一個沒得到支持

11、的像素格式,則Choose-PixelFormat將會返回與你要 求的像素格式最接近的一個值。一旦我們得到一個像素格式的索引值和相應(yīng)的描述,我們就可以調(diào)用SetPixelFormat設(shè)置像素格式,并且只需設(shè)置一 次?,F(xiàn)在像素格式已經(jīng)設(shè)定,我們下一步工作是產(chǎn)生繪制環(huán)境(RC)并使之成為當前繪制環(huán)境。在COpenGLDemoView中加入一個保護型的成員函數(shù)BOOL CreateViewGLContext(HDC hDC),并加入一個保護型的成員變量HGLRC m_hGLContext;HGLRC是一個指向rendering context的句柄。BOOL COpenGLDemoView:Crea

12、teViewGLContext(HDC hDC) this-m_hGLContext = wglCreateContext(hDC); if(this-m_hGLContext=NULL) /創(chuàng)建失敗 return FALSE; if(wglMakeCurrent(hDC,this-m_hGLContext)=FALSE) /選為當前RC失敗 return FALSE; return TRUE; 在OnCreate函數(shù)中調(diào)用此函數(shù): int COpenGLDemoView:OnCreate(LPCREATESTRUCT lpCreateStruct) if (CView:OnCreate(lp

13、CreateStruct) = -1) return -1; / TODO: Add your specialized creation code here HWND hWnd = this-GetSafeHwnd(); HDC hDC = :GetDC(hWnd); if(this-SetWindowPixelFormat(hDC)=FALSE) return 0; if(this-CreateViewGLContext(hDC)=FALSE) return 0; return 0; 添加WM_DESTROY的消息處理函數(shù)Ondestroy( ),使之如下所示:void COpenGLDem

14、oView:OnDestroy() CView:OnDestroy(); / TODO: Add your message handler code here if(wglGetCurrentContext()!=NULL) wglMakeCurrent(NULL,NULL); if(this-m_hGLContext!=NULL) wglDeleteContext(this-m_hGLContext); this-m_hGLContext = NULL; 最后,編輯COpenGLDemoView的構(gòu)造函數(shù),使之如下所示:COpenGLDemoView:COpenGLDemoView() /

15、TODO: add construction code here this-m_GLPixelIndex = 0; this-m_hGLContext = NULL;至此,我們已經(jīng)構(gòu)造好了框架,使程序可以利用OpenGL進行畫圖了。你可能已經(jīng)注意到了,我們在程序開頭產(chǎn)生了一個RC,自始自終都使用它。這與大多數(shù)GDI程序不同。在GDI程序中,DC在需要時才產(chǎn)生,并且是畫完立刻釋放掉。實際上,RC也可以這樣做;但要記住,產(chǎn)生一個RC需要很多處理器時 間。因此,要想獲得高性能流暢的圖像和圖形,最好只產(chǎn)生RC一次,并始終用它,直到程序結(jié)束。 CreateViewGLContex產(chǎn)生RC并使之成為當前R

16、C。WglCreateContext返回一個RC的句柄。在你調(diào)用 CreateViewGLContex之前,你必須用SetWindowPixelFormat(hDC)將與設(shè)備相關(guān)的像素格式設(shè)置好。 wglMakeCurrent將RC設(shè)置成當前RC。傳入此函數(shù)的DC不一定就是你產(chǎn)生RC的那個DC,但二者的設(shè)備句柄(Device Context)和像素格式必須一致。假如你在調(diào)用wglMakeforCurrent之前已經(jīng)有另外一個RC存在,wglMakeforCurrent 就會把舊的RC沖掉,并將新RC設(shè)置為當前RC。另外你可以用wglMakeCurrent(NULL, NULL)來消除當前RC。

17、 我們要在OnDestroy中把繪制環(huán)境刪除掉。但在刪除RC之前,必須確定它不是當前句柄。我們是通過wglGetCurrentContext來了 解是否存在一個當前繪制環(huán)境的。假如存在,那么用wglMakeCurrent(NULL, NULL)來把它去掉。然后就可以通過wglDelete-Context來刪除RC了。這時允許視類刪除DC才是安全的。注:一般來說,使用的都是單線 程的程序,產(chǎn)生的RC就是線程當前的RC,不需要關(guān)注上述這一點。但如果使用的是多線程的程序,那我們就特別需要注意這一點了,否則會出現(xiàn)意想不到的后 果。三、畫圖實例下面給出一個簡單的二維圖形的例子(這個例子都是以上述框架為基

18、礎(chǔ)的)。用Classwizard為COpenGLDemoView添加WMSIZE的消息處理函數(shù)OnSize,代碼如下:void COpenGLDemoView:OnSize(UINT nType, int cx, int cy) CView:OnSize(nType, cx, cy); / TODO: Add your message handler code here GLsizei width,height; GLdouble aspect; width = cx; height = cy; if(cy=0) aspect = (GLdouble)width; else aspect =

19、(GLdouble)width/(GLdouble)height; glViewport(0,0,width,height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0.0,500.0*aspect,0.0,500.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity();用Classwizard為COpenGLDemoView添加WM_PAINT的消息處理函數(shù)OnPaint,代碼如下:void COpenGLDemoView:OnPaint() CPaintDC dc(thi

20、s); / device context for painting / TODO: Add your message handler code here / Do not call CView:OnPaint() for painting messages glLoadIdentity(); glClear(GL_COLOR_BUFFER_BIT); glBegin(GL_POLYGON); glColor4f(1.0f,0.0f,0.0f,1.0f); glVertex2f(100.0f,50.0f); glColor4f(0.0f,1.0f,0.0f,1.0f); glVertex2f(4

21、50.0f,400.0f); glColor4f(0.0f,0.0f,1.0f,1.0f); glVertex2f(450.0f,50.0f); glEnd(); glFlush();這個程序的運行結(jié)果是黑色背景下的一個絢麗多彩的三角形。這里你可以看到用OpenGL繪制圖形非常容易,只需要幾條簡單的語句就能實現(xiàn) 強大的功能。如果你縮放窗口,三角形也會跟著縮放。這是因為OnSize通過glViewport(0, 0, width, height)定義了視口和視口坐標。glViewport的第一、二個參數(shù)是視口左下角的像素坐標,第三、四個參數(shù)是視口的寬度和高度。 OnSize中的glMatrixM

22、ode是用來設(shè)置矩陣模式的,它有三個選項:GL_MODELVIEW、GL_PROJECTION、GL_TEXTURE。GL_MODELVIEW表示從實體坐標系轉(zhuǎn)到人眼坐標系。GL_PROJECTION表示從人眼坐標系轉(zhuǎn)到剪裁坐標系。GL_TEXTURE表示從定義紋理的坐標系到粘貼紋理的坐標系的變換。glLoadIdentity初始化工程矩陣(project matrix);gluOrtho2D把工程矩陣設(shè)置成顯示一個二維直角顯示區(qū)域。 這里我們有必要說一下OpenGL命令的命名原則。大多數(shù)OpenGL命令都是以gl開頭的。也有一些是以glu開頭的,它們來自O(shè)penGL Utility。大多數(shù)g

23、l命令在名字中定義了變量的類型并執(zhí)行相應(yīng)的操作。例如:glVertex2f就是定義了一個頂點,參數(shù)變量為兩個浮點數(shù), 分別代表這個頂點的x、y坐標。類似的還有g(shù)lVertex2d、glVertex2f、glVertex3I、glVertex3s、 glVertex2sv、glVertex3dv等函數(shù)。那么,怎樣畫三角形 呢?我們首先調(diào)用glColor4f(1.0f, 0.0f, 0.0f, 1.0f),把紅、綠、藍分量分別指定為1、0、0。然后我們用glVertex2f(100.0f, 50.0f)在(100,50)處定義一個點。依次,我們在(450,400)處定義綠點,在(450,50)處定

24、義藍點。然后我們用glEnd結(jié)束畫三 角形。但此時三角形還沒畫出來,這些命令還只是在緩沖區(qū)里,直到你調(diào)用glFlush函數(shù),由glFlush觸發(fā)這些命令的執(zhí)行。OpenGL自動改變?nèi)?角形頂點間的顏色值,使之絢麗多彩。還可通過glBegin再產(chǎn)生新的圖形。glBegin(GLenum mode)參數(shù)有:GL_POINTS,GL_LINES,GL_LINE_STRIP,GL_LINE_LOOP, GL_TRIANGLES,GL_TRIANGLE_STRIP,GL_TRIANGLE_FAN,GL_QUADS, GL_QUAD_STRIP, GL_POLYGON在glBegin和glEnd之間的有效

25、函數(shù)有: glVertex,glColor,glIndex, glNormal,glTexCoord, glEvalCoord,glEvalPoint, glMaterial, glEdgeFlag四小結(jié)1、如果要響應(yīng)WM_SIZE消息,則一定要設(shè)置視口和矩陣模式。2、盡量把你全部的畫圖工作在響應(yīng)WM_PAINT消息時完成。3、產(chǎn)生一個繪制環(huán)境要耗費大量的CPU時間,所以最好在程序中只產(chǎn)生一次,直到程序結(jié)束。4、盡量把你的畫圖命令封裝在文檔類中,這樣你就可以在不同的視類中使用相同的文檔,節(jié)省你編程的工作量。5、glBegin和glEnd一定要成對出現(xiàn),這之間是對圖元的繪制語句。 glPushM

26、atrix()和glPopMatrix()也一定要成對出現(xiàn)。glPushMatrix()把當前的矩陣拷貝到棧中。當我們調(diào)用 glPopMatrix時,最后壓入棧的矩陣恢復(fù)為當前矩陣。使用glPushMatrix()可以精確地把當前矩陣保存下來,并用 glPopMatrix把它恢復(fù)出來。這樣我們就可以使用這個技術(shù)相對某個物體放置其他物體。例如下列語句只使用一個矩陣,就能產(chǎn)生兩個矩形,并將它們成一定角度擺放。glPushMatrix(); glTranslated( m_transX, m_transY, 0); glRotated( m_angle1, 0, 0, 1); glPushMatri

27、x(); glTranslated( 90, 0, 0); glRotated( m_angle2, 0, 0, 1); glColor4f(0.0f, 1.0f, 0.0f, 1.0f); glCallList(ArmPart);/ArmPart 且桓鼉卣竺 glPopMatrix(); glColor4f(1.0f, 0.0f, 0.0f, 1.0f); glCallList(ArmPart); glPopMatrix(); 6、 解決屏幕的閃爍問題。我們知道,在窗口中拖動一個圖形的時候,由于邊畫邊顯示,會出現(xiàn)閃爍的現(xiàn)象。在GDI中解決這個問題較為復(fù)雜,通過在內(nèi)存中生成一個 內(nèi)存DC,繪畫

28、時讓畫筆在內(nèi)存DC中畫,畫完后一次用Bitblt將內(nèi)存DC“貼”到顯示器上,就可解決閃爍的問題。在OpenGL中,我們是通過雙緩存 來解決這個問題的。一般來說,雙緩存在圖形工作軟件中是很普遍的。雙緩存是兩個緩存,一個前臺緩存、一個后臺緩存。繪圖先在后臺緩存中畫,畫完后,交換到 前臺緩存,這樣就不會有閃爍現(xiàn)象了。通過以下步驟可以很容易地解決這個問題:1) 要注意,GDI命令是沒有設(shè)計雙緩存的。我們首先把使用InvalidateRect(null)的地方改成InvalidateRect(NULL,FALSE)。這樣做是使GDI的重畫命令失效,由OpenGL的命令進行重畫;2) 將像素格式定義成支持

29、雙緩存的(注:PFD_DOUBLEBUFFER和PFD_SUPPORT_GDI只能取一個,兩者相互沖突)。 pixelDesc.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_STEREO_DONTCARE; 3) 我們得告訴OpenGL在后臺緩存中畫圖,在視類的OnSize()的最后一行加入:glDrawBuffer (GL_BACK);4) 最后我們得把后臺緩存的內(nèi)容換到前臺緩存中,在視類的OnPaint()的最后一行加入:SwapBuffers(dc.m_ ps.hdc)。 7、生成簡單

30、的三維圖形。我們知道,三維和二維的坐標系統(tǒng)不同,三維的圖形比二維的圖形多一個z坐標。我們在生成簡單的二維圖形時,用的是 gluOrtho2D;我們在生成三維圖形時,需要兩個遠近裁剪平面,以生成透視效果。實際上,二維圖形只是視線的近裁剪平面z= -1,遠裁剪平面z=1;這樣z坐標始終當作0,兩者沒有本質(zhì)的差別。在上述基礎(chǔ)之上,我們只做簡單的變化,就可以生成三維物體。 1) 首先,在OnSize()中,把gluOrtho2D(0.0, 500.0*aspect,0.0, 500.0)換成gluPerspective(60, aspect, 1, 10.0);這樣就實現(xiàn)了三維透視坐標系的設(shè)置。該語句說明了視點在原點,透視角是60度,近裁剪面在z=1處,遠裁剪面在z=10.0處。2) 在RenderScene()中生成三維圖形;實際上,它是由多邊形組成的。下面就是一個三維多邊形的例子:glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, RedSurface) glBegin(GL_POLYGON); glNormal3d( 1.0, 0.0,

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論