OpenGL之坐標轉(zhuǎn)換_第1頁
OpenGL之坐標轉(zhuǎn)換_第2頁
OpenGL之坐標轉(zhuǎn)換_第3頁
OpenGL之坐標轉(zhuǎn)換_第4頁
OpenGL之坐標轉(zhuǎn)換_第5頁
已閱讀5頁,還剩9頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

1、OpenGL之坐標轉(zhuǎn)換下面這篇文章詳細講述了OpenGL里的坐標轉(zhuǎn)換,清晰,明了。但是其所謂的渲染管線只包括modelview 轉(zhuǎn)換 和 投影變換,我覺得不是這樣的。這只是從坐標角度吧。比如什么頂點著色、光柵化、送至幀緩存都沒有涉及到。原文地址:1. OpenGL 渲染管線OpenGL渲染管線分為兩大部分,模型觀測變換(ModelView Transformation)和投影變換(Projection Transformation)。做個比喻,計算機圖形開發(fā)就像我們照相一樣,目的就是把真實的場景在一張照相紙上表現(xiàn)出來。那么觀測變換的過程就像是我們擺設相機的位置,選擇好要照的

2、物體,擺好物體的造型。而投影變換就像相機把真實的三維場景顯示在相紙上一樣。下面就分別詳細的講一下這兩個過程。1.1模型觀測變換讓我們先來弄清楚OpenGL中的渲染管線。管線是一個抽象的概念,之所以稱之為管線是因為顯卡在處理數(shù)據(jù)的時候是按照一個固定的順序來的,而且嚴格按照這個順序。就像水從一根管子的一端流到另一端,這個順序是不能打破的。先來看看下面的圖1:                     圖

3、1 OPENGL渲染管線                                 圖中顯示了OpenGL圖形管線的主要部分,也是我們在進行圖形編程的時候常常要用到的部分。一個頂點數(shù)據(jù)從圖的左上角(MC)進入管線,最后從圖的右下角(DC)輸出。MC是Model C

4、oordinate的簡寫,表示模型坐標。DC是Device Coordinate的簡寫,表示設備坐標。當然DC有很多了,什么顯示器,打印機等等。這里DC我們就理解成常說的屏幕坐標好了。MC當然就是3D坐標了(注意:我說的3D坐標,而不是世界坐標),這個3D坐標就是模型坐標,也說成本地坐標(相對于世界坐標)。MC要經(jīng)過模型變換(Modeling Transformation)才變換到世界坐標,圖2:圖2 世界坐標系和模型坐標系變換到世界坐標WC(World Coordinate)說簡單點就是如何用世界坐標系來表示本地坐標系中的坐標。為了講得更清楚一些,這里舉個2D的例子。如圖3:圖3 世界坐標系

5、和模型坐標系的計算圖中紅色坐標系是世界坐標系WC,綠色的是模型坐標系MC?,F(xiàn)在有一個頂點,在模型坐標系中的坐標為(1,1),現(xiàn)在要把這個模型坐標轉(zhuǎn)換到世界坐標中來表示。從圖中可以看出,點(1,1)在世界坐標系中的坐標為(3,4),現(xiàn)在我們來通過計算得到我們希望的結果。首先我們要把模型坐標系MC在世界坐標系中表示出來,使用齊次坐標(Homogeneous Coordinate )可以表示為矩陣(注意,本教程中使用的矩陣都是以列向量組成):其中,矩陣的第一列為MC中x軸在WC中的向量表示,第二列為MC中y軸WC中的向量表示,第三列為MC中的原點在WC中的坐標。對齊次坐標系不了解的同學,請先學習游戲

6、數(shù)學方面的知識。有了這個模型變換矩陣后,用這個矩陣乘以在MC中表示的坐標就可以得到該坐標在世界坐標系中的坐標。所以該矩陣和MC中的坐標(1,1)相乘有:這也正是我們需要的結果?,F(xiàn)在讓我們把相機坐標也加進去,相機坐標也稱為觀測坐標(View Coordinate),如圖4和圖5。圖4 ModelView變換的三個坐標系圖5 ModelView變換計算來看看MC坐標中的點(1,1)如何在相機坐標中表示。從圖5中可以直接看出MC中的點(1,1)在相機坐標系VC中為(-2,-2)。和上面同樣的道理,我們可以寫出相機坐標系VC在世界標系WC中可以表示為:那么世界坐標系中的點轉(zhuǎn)換為相機坐標系中的點我們就需

7、求VC的逆矩陣:那么世界坐標系WC中的點(3,4)在相機坐標系VC中坐標為:上面的變換過程,就是可以把模型坐標變換為相機坐標。在OpenGL中,當我們申明頂點的時候,有時候說的是世界坐標,這是因為初始化的時候世界坐標系、模型坐標系和相機坐標系是一樣的,重合在一起的。所以OpenGL中提供了模型觀測變換,它是把模型坐標系直接轉(zhuǎn)換為相機坐標系,如圖4?,F(xiàn)在我們已經(jīng)計算得到了VC-1和MC,如果把VC-1和MC相乘,就可以得到模型坐標在相機坐標中的表示。為了得到模型坐標系中的坐標在相機坐標系中的表示,這就是OpenGL中的ModelView變換矩陣。這也是ModelView變換的名字的由來,它是通過

8、了上面兩個步驟得到的。那么這里,ModelView變換矩陣M為:現(xiàn)在只要用上面的模型觀測矩陣M乘以模型坐標系MC中的坐標就可以得到相機坐標系中的坐標了。模型觀測變換的關鍵就是要得到相機坐標系中的坐標,因為光照等計算都是在這個這個坐標系中完成的。下面我們實際OpenGL程序中檢查一下。在程序中,為了計算方便,我們使用圖6中的模型。圖6 ModelView變換計算模型根據(jù)圖中的數(shù)據(jù),我們分別可以寫出對應MC和VC-1,從而求得觀測變換矩陣M?,F(xiàn)在程序中用glGetFloatv()這個函數(shù)來獲得當前矩陣數(shù)據(jù)來檢查一下。cpp view plaincopy1. float m16 

9、= 0; /用來保存當前矩陣數(shù)據(jù)  2. glMatrixMode(GL_MODELVIEW);  3. glLoadIdentity();  4. glGetFloatv(GL_MODELVIEW_MATRIX, m);   5. /相機設置,View 變換  6. gluLookAt(0.0, 0.0, 5.0,  7. 0.0, 0.0, 0.0,  8. 0.

10、0, 1.0, 0.0);  9. glGetFloatv(GL_MODELVIEW_MATRIX, m);   10. /投影設置  11. glMatrixMode(GL_PROJECTION);  12. glLoadIdentity();  13. glOrtho(-10,10,-10,10,-10,10);  14. glMatrixMode(GL_MODELVIEW);   15. /Model

11、ing變換  16. glTranslatef(0, 0, -3);  17. glGetFloatv(GL_MODELVIEW_MATRIX, m);  18. glBegin(GL_POINTS);  19. glVertex3f(1,1,0);  20. glEnd();   如果在上面程序段中最后一個glGetFloatv(GL_MODELVIEW_MATRIX, m)處設定斷點的話,就可以看到圖7所顯示的數(shù)據(jù)。圖7 ModelView變

12、換矩陣數(shù)據(jù)到這里,整個ModelView變換就完成了。通過ModelView變換后得到是相機坐標系內(nèi)的坐標。在這個坐標系內(nèi)典型的計算就是法線了?,F(xiàn)在再來看看后面一個階段。 /我的理解:ModelView 變換矩陣,就是完成從模型坐標到View坐標的轉(zhuǎn)換,是坐標系之間的大變換。注意,modelview 既有model,也有view。不只是一個model的矩陣。只是對model的進行平移或旋轉(zhuǎn)的函數(shù)為  glTranslatef等函數(shù),稱作模型變換!它的坐標是基于模型本身的,即位于模型坐標系類,比如glTranslatef(0, 0, -3);的3個坐標值。

13、只是針對view進行設置的函數(shù)為  gluLookAt,它的坐標系是view坐標系,比如 1. gluLookAt(0.0, 0.0, 5.0,  2. 0.0, 0.0, 0.0,  3. 0.0, 1.0, 0.0);它里面的坐標的原點位于相機坐標系的原點。參看下面的投影變換。/1.2投影變換先還是復習一下OpenGL的渲染管線。圖1中可以看到,在投影變換(Projection Transformation)中也分為兩個部分,第一個部分是將上個階段得到的坐標轉(zhuǎn)換為平面坐標,第二個部

14、分是將轉(zhuǎn)換后的平面坐標在進行歸一化并進行剪裁。一般地,將三維坐標轉(zhuǎn)換為平面坐標有兩種投影方式:正交投影(Orthogonal Projection)和透視投影(Perspective Projection)。1.2.1 正交投影正交投影很簡單,如圖8,對于三維空間中的坐標點和一個二維平面,要在對應的平面上投影,只需將非該平面上的點的坐標分量改為該平面上的坐標值,其余坐標不變。圖8 正交投影比如將點(1,1,5)正交投影到z=0的平面上,那么投影后的坐標為(1,1,0)。在openGL中,設置正交投影可以使用函數(shù):cpp view plaincopy1. glOrtho (G

15、Ldouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar)   該函數(shù)可以設置正交投影的投影空間,在該空間以外的坐標點就不會被投影到投影平面上。函數(shù)中的六個參數(shù)分是投影空間六個平面,如圖9:圖9 OpenGL正交投影空間和投影變換在圖9中,大的投影空間是根據(jù)這六個參數(shù)設置的投影空間,OpenGL會自動將該空間歸一化,也就是將該空間或立方體轉(zhuǎn)化為

16、變長為1的正六面體投影空間,并且該證六面體的中心在相機坐標系的原點。一旦設置使用glortho函數(shù)設置投影空間,OpenGL會生成投影矩陣。這個矩陣的作用就是將坐標進行正交投影并且將投影后的坐標正規(guī)化(轉(zhuǎn)換到-1到1之間)。要注意的是,生成該矩陣的時候,OpenGL會把右手坐標系轉(zhuǎn)換為左手坐標系。原因很簡單,右手坐標系的Z軸向平面外的,這樣不符合我們的習慣。該矩陣的矩陣推導這里就不詳細說明了,不了解的同學可以參考游戲數(shù)學方面資料,這里只給出正交投影矩陣。這個矩陣看來很復雜,其實計算很簡單。舉個例子,現(xiàn)在設置了這樣的正交投影空間glOrtho(-10,10,-10,10,-10,10),這是個正

17、六面體空間,變長為10。把這些參數(shù)帶入上面的矩陣可以得到現(xiàn)在還是在OpenGL程序中來檢查一下。在OpenGL程序中添加下面代碼段:cpp view plaincopy1. /投影設置  2. glMatrixMode(GL_PROJECTION);  3. glLoadIdentity();  4. glOrtho(-10,10,-10,10,-10,10);  5. glMatrixMode(GL_MODELVIEW);  6. glGetFloatv(GL_PROJECTION_MATRI

18、X,m)   在glGetFloatv(GL_PROJECTION_MATRIX,m)處設定斷點就可以看到圖10中所顯示的信息。圖10 正交變換矩陣數(shù)據(jù) 1.2.2透視投影透視投影和正交投影最大的區(qū)別就是透視投影具有遠近感。圖11 透視投影透視投影采用了圖11中的模型,這樣的模型就是保證遠的物體看起來小,近的物體看起來大。 在OpenGL中設置透視投影可以使用函數(shù):cpp view plaincopy1. void APIENTRY gluPerspective (GLdouble fovy, GLdouble&#

19、160;aspect, GLdouble zNear, GLdouble zFar);   該函數(shù)也會根據(jù)給定的參數(shù)生成一個投影空間。如圖11中,該投影空間是一個截頭體。同樣地,OpenGL會自動生成透視投影矩陣,該矩陣也會讓3D坐標投影在投影平面上,并且將投影后的坐標也進行正規(guī)化。下面也直接給出OpenGL中使用的透視投影矩陣。下面在OpenGL中添加下面代碼段:cpp view plaincopy1. /投影設置  2. glMatrixMode(GL_PROJECTION);  3. gl

20、LoadIdentity();  4. gluPerspective(45, 1.0, 1.0, 100);  5. glMatrixMode(GL_MODELVIEW);  6. glGetFloatv(GL_PROJECTION_MATRIX,m)   設置斷點后,我們可以看到圖12中顯示的數(shù)據(jù)。圖12 透視變換矩陣數(shù)據(jù)到此為止,整個投影變換就完成了。透過投影變換后得到的是正規(guī)化的投影平面坐標。這為下一個階段的視口變換(View port Transformation)做好了準備。

21、1.3視口變換現(xiàn)在到了最后一個階段了。這個階段叫做視口變換,它把上個階段得到的正規(guī)化的投影坐標轉(zhuǎn)化為windows 窗口坐標。視口變換會將投影平面上的畫面映射到窗口上。在OpenGL中可以使用函數(shù)cpp view plaincopy1. GLAPI void GLAPIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height);   來進行對窗口的映射,如圖13。圖13 視口變換glViewp

22、ort(width/2, 0, width/2, height/2)舉個例子說明,比如上個階段中得到了一個頂點的坐標為(0,0,0.5,1),根據(jù)這個坐標,該頂點位于投影平面的正中間。如果將該點映射到大小為50*50的窗口上時,那么它應該位于屏幕的中間,坐標為(25,25, 0.5,1)。當然這里深度值0.5是不會改變的。有的同學肯定有疑問了,既然投影到了窗口上,那么還要深度值0.5干什么?這里要注意的是,雖然在窗口上顯示時只需要x,y坐標就夠了,但是要在2D窗口上顯示3D圖形時深度值是不可少的。這里的深度值不是用于顯示,而是用于在光柵化的時候進行深度測試。OpenGL也會根據(jù)glViewpo

23、rt函數(shù)提供的參數(shù)值生成一個視口變換矩陣該矩陣把上個階段得到的正規(guī)化坐標映射到窗口上,并且將正規(guī)化坐標中的深度值在轉(zhuǎn)換到0到1之間。所以在深度緩沖中最大值為1,最小值為0。視口變換結束后,OpenGL中主要的圖形管線階段就算完成了,后面就是光柵化等等操作。再來回顧一下圖1,現(xiàn)在相信大家對這個渲染管線有了一定的認識了,也明白了每一個階段對應的變換矩陣以及如何進行坐標之間的轉(zhuǎn)換的。2. 屏幕坐標轉(zhuǎn)換為世界坐標通過前面的教程,以及現(xiàn)在大家對OpenGL整個渲染管線理解后,現(xiàn)在要將屏幕上一點坐標轉(zhuǎn)換為世界坐標就比較容易了。從圖形管線的開始到結束,一個模型坐標系中的坐標被轉(zhuǎn)化為了屏幕坐標,那么

24、現(xiàn)在把整個過程倒過來的話,屏幕上一點坐標也可以轉(zhuǎn)為為世界坐標。只要在對應的階段求得對應變換矩陣的逆矩陣,就可以得到前一個階段的坐標。這整個過程可以用圖14表示。圖14屏幕坐標轉(zhuǎn)換為世界坐標圖中顯示的過程完全就是OpenGL渲染管線的逆過程,通過這個過程,屏幕上的點就可以轉(zhuǎn)化為世界坐標系中的點了??赡苡钟械耐瑢W要問,當鼠標點擊屏幕上一點的時候并沒有深度信息,轉(zhuǎn)換的時候要怎么辦呢?這個時候可以使用OpenGL函數(shù)cpp view plaincopy1. void glReadPixels (GLint x, GLint y, GLsize

25、i width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels);   該函數(shù)能夠獲得屏幕上一點對應像素的深度信息。有了這個深度信息,就可以利用上面過程把屏幕上一點轉(zhuǎn)換為世界坐標了。在OpenGL中,上面的過程其實已經(jīng)有現(xiàn)成的函數(shù)可以使用,那就是cpp view plaincopy1. int APIENTRY gluUnProject (  2.  &#

26、160;  GLdouble  winx, GLdouble  winy,  3.     GLdouble  winz,  4.     const GLdouble modelMatrix16,  5.     const GLdouble projMatrix16, 

27、60;6.     const GLint    viewport4,  7.     GLdouble  *objx,  GLdouble  *objy,  8.     GLdouble       *objz);   該函數(shù)直接將屏幕

28、上一點轉(zhuǎn)換對應的世界坐標,該函數(shù)的內(nèi)部實現(xiàn)其實還是上面的那么逆過程。下面給出利用該函數(shù)獲取世界坐標的代碼段。cpp view plaincopy1. GVector screen2world(int x, int y)  2.   3.        GLint viewport4;  4.        GLdouble modelvi

29、ew16;  5.        GLdouble projection16;  6.        GLfloat winX, winY, winZ;  7.        GLdouble posX, posY, posZ;  8.        glGetDoublev(GL_MODELVIEW_MATRIX, modelview);  9.     

溫馨提示

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

評論

0/150

提交評論