OpenGL模型視圖變換

實驗5 OpenGL模型視圖變換

1.實驗目的:

理解掌握OpenGL程序的模型視圖變換。

2.實驗內容:

(1)閱讀實驗原理,運行示範實驗代碼,理解掌握OpenGL程序的模型視圖變換;

(2)根據示範代碼,嘗試完成實驗作業;

3.實驗原理:

我們生活在一個三維的世界——如果要觀察一個物體,我們可以:

1、從不同的位置去觀察它(人運動,選定某個位置去看)。(視圖變換)

2、移動或者旋轉它,當然了,如果它只是計算機裏面的物體,我們還可以放大或縮小它(物體運動,讓人看它的不同部分)。(模型變換)

3、如果把物體畫下來,我們可以選擇:是否需要一種“近大遠小”的透視效果。另外,我們可能只希望看到物體的一部分,而不是全部(指定看的範圍)。(投影變換)

4、我們可能希望把整個看到的圖形畫下來,但它只佔據紙張的一部分,而不是全部(指定在顯示器窗口的那個位置顯示)。(視口變換)

這些,都可以在OpenGL中實現。

從“相對移動”的觀點來看,改變觀察點的位置與方向和改變物體本身的位置與方向具有等效性。在OpenGL中,實現這兩種功能甚至使用的是同樣的函數。

由於模型和視圖的變換都通過矩陣運算來實現,在進行變換前,應先設置當前操作的矩陣爲“模型視圖矩陣”。設置的方法是以GL_MODELVIEW爲參數調用glMatrixMode函數,像這樣:

glMatrixMode(GL_MODELVIEW);

該語句指定一個4×4的建模矩陣作爲當前矩陣。

通常,我們需要在進行變換前把當前矩陣設置爲單位矩陣。把當前矩陣設置爲單位矩陣的函數爲:

glLoadIdentity();

我們在進行矩陣操作時,有可能需要先保存某個矩陣,過一段時間再恢復它。當我們需要保存時,調用glPushMatrix()函數,它相當於把當前矩陣壓入堆棧。當需要恢復最近一次的保存時,調用glPopMatrix()函數,它相當於從堆棧棧頂彈出一個矩陣爲當前矩陣。OpenGL規定堆棧的容量至少可以容納32個矩陣,某些OpenGL實現中,堆棧的容量實際上超過了32個。因此不必過於擔心矩陣的容量問題。

通常,用這種先保存後恢復的措施,比先變換再逆變換要更方便,更快速。

注意:模型視圖矩陣和投影矩陣都有相應的堆棧。使用glMatrixMode來指定當前操作的究竟是模型視圖矩陣還是投影矩陣。

在代碼中,視圖變換必須出現在模型變換之前,但可以在繪圖之前的任何時候執行投影變換和視口變換。

1.display()程序中繪圖函數潛在的重複性強調了:在指定的視圖變換之前,應該使用glLoadIdentity()函數把當前矩陣設置爲單位矩陣。

2.在載入單位矩陣之後,使用gluLookAt()函數指定視圖變換。如果程序沒有調用gluLookAt(),那麼照相機會設定爲一個默認的位置和方向。在默認的情況下,照相機位於原點,指向Z軸負方向,朝上向量爲(0,1,0)。

3.一般而言,display()函數包括:視圖變換 + 模型變換 + 繪製圖形的函數(如glutWireCube())。display()會在窗口被移動或者原來先遮住這個窗口的東西被一開時,被重複調用,並經過適當變換,保證繪製的圖形是按照希望的方式進行繪製。

4.在調用glFrustum()設置投影變換之前,在reshape()函數中有一些準備工作:視口變換 + 投影變換 + 模型視圖變換。由於投影變換,視口變換共同決定了場景是如何映射到計算機的屏幕上的,而且它們都與屏幕的寬度,高度密切相關,因此應該放在reshape()中。reshape()會在窗口初次創建,移動或改變時被調用。

OpenGL中矩陣座標之間的關係

物理座標*模型視圖矩陣*投影矩陣*透視除法*規範化設備座標——〉窗口座標

clip_image001

(1)視圖變換函數gluLookAt(0.0,0.0,5.0,0.0,0.0,0.0,0.0,1.0,0.0,)設置照相機的位置

把照相機放在(0,0,5),鏡頭瞄準(0,0,0),朝上向量定爲(0,1,0)朝上向量爲照相機指定了一個唯一的方向。如果沒有調用gluLookAt,照相機就設定一個默認的位置和方向,在默認情況下,照相機位於原點,指向Z軸的負方向,朝上向量爲(0,1,0)

glLoadIdentity()函數把當前矩陣設置爲單位矩陣。

(2)使用模型變換的目的是設置模型的位置和方向

(3)投影變換,指定投影變換類似於爲照相機選擇鏡頭,可以認爲這種變換的目的是確定視野,並因此確定哪些物體位於視野之內以及他們能夠被看到的程度。

除了考慮視野之外,投影變換確定物體如何投影到屏幕上,OpenGL提供了兩種基本類型的投影,1、透視投影:遠大近小;2、正投影:不影響相對大小,一般用於建築和CAD應用程序中

(4)視口變換

視口變換指定一個圖象在屏幕上所佔的區域

(5)繪製場景

4.示範代碼: 太陽系

#include <GL/glut.h>





#include <stdlib.h> static int year = 0, day = 0; void init(void) { glClearColor (0.0, 0.0, 0.0, 0.0); glShadeModel (GL_FLAT); } void display(void) { glClear (GL_COLOR_BUFFER_BIT); glColor3f (1.0, 1.0, 1.0); glPushMatrix(); glutWireSphere(1.0, 20, 16); /* draw sun */ glRotatef ((GLfloat) year, 0.0, 1.0, 0.0); glTranslatef (2.0, 0.0, 0.0); glRotatef ((GLfloat) day, 0.0, 1.0, 0.0); glutWireSphere(0.2, 10, 8); /* draw smaller planet */ glPopMatrix(); glutSwapBuffers(); } void reshape (int w, int h) { glViewport (0, 0, (GLsizei) w, (GLsizei) h); glMatrixMode (GL_PROJECTION); glLoadIdentity (); gluPerspective(60.0, (GLfloat) w/(GLfloat) h, 1.0, 20.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt (0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); } void keyboard (unsigned char key, int x, int y) { switch (key) { case ‘d’: day = (day + 10) % 360; glutPostRedisplay(); break; case ‘D’: day = (day - 10) % 360; glutPostRedisplay(); break; case ‘y’: year = (year + 5) % 360; glutPostRedisplay(); break; case ‘Y’: year = (year - 5) % 360; glutPostRedisplay(); break; case 27: exit(0); break; default: break; } } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB); glutInitWindowSize (500, 500); glutInitWindowPosition (100, 100); glutCreateWindow (argv[0]); init (); glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc(keyboard); glutMainLoop(); return 0; }

  附上本實驗的VC++工程代碼(VC++2008)

 代碼說明:

上面所描述的這個程序繪製一個簡單的太陽系,其中有一顆行星和一顆太陽,它們是用同一個球體繪製函數繪製的。爲了編寫這個程序,需要使用glRtate*()函數讓這顆行星繞太陽旋轉,並且繞自身的軸旋轉。還需要使用glTranslate*()函數讓這顆行星遠離太陽系原點,移動到它自己的軌道上。記住,可以在glutWireSphere()函數中使用適當的參數,在繪製兩個球體時指定球體的大小。

 

爲了繪製這個太陽系,首先需要設置一個投影變換和一個視圖變換。在這個例子中,可以使用glutPerspective()和gluLookat().

 

繪製太陽比較簡單,因爲它應該位於全局固定座標系統的原點,也就是球體函數進行繪圖的位置。因此,繪製太陽時並不需要移動,可以使用glRotate*()函數繞一個任意的軸旋轉。繪製一顆繞太陽旋轉的行星要求進行幾次模型變換。這顆行星需要每天繞自己的軸旋轉一週,每年沿着自己的軌道繞太陽旋轉一週。

 

爲了確定模型變換的順序,可以從局部座標系統的角度考慮。首先,調用初始的glRotate*()函數對局部座標系統進行旋轉,這個局部座標系統最初與全局固定座標系統是一致的。接着,可以調用glTranslate*()把局部座標系統移動到行星軌道上的一個位置。移動的距離應該等於軌道的半徑。因此,第一個glRotate*()函數實際上確定了這顆行星從什麼地方開始繞太陽旋轉(或者說,從一年的什麼時候開始)。

 

第二次調用glRotate*()使局部座標軸進行旋轉,因此確定了這顆行星在一天中的時間。當調用了這些函數變換之後,就可以繪製這顆行星了。

5. 實驗作業:

(1)嘗試在太陽系中增加一顆衛星,一顆行星。提示:使用glPushMatrix()和glPopMatrix()在適當的時候保存和恢復座標系統的位置。如果打算繪製幾顆衛星繞同一顆行星旋轉,需要在移動每顆衛星的位置之前保存座標系統,並在繪製每顆衛星之後恢復座標系統。

(2)嘗試把行星的軸傾斜。

1
0
« 上一篇:實驗3 OpenGL幾何變換
» 下一篇:附加實驗2 OpenGL變換綜合練習

posted on 2012-11-06 22:26 慢步前行 閱讀(3937) 評論(2) 編輯 收藏

</div>
<script type="text/javascript">var allowComments=true,cb_blogId=29869,cb_entryId=2757854,cb_blogApp=currentBlogApp,cb_blogUserGuid='ba803d0b-63cf-dd11-9e4d-001cf0cd104b',cb_entryCreatedDate='2012/11/6 22:26:00';loadViewCount(cb_entryId);var cb_postType=1;</script>

</div>

轉載來源 http://www.cnblogs.com/opengl/archive/2012/11/06/2757854.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章