opengl座標與矩陣直白剖析

1、opengl的世界座標系

opengl的默認世界座標系如圖所示,(0,0,0)點位於opengl畫布窗口正中心



2、關於glTranslate*()和glRotate*()

含義理解:

glTranslate*(a,b,c)

從當前位置,沿着向量(a,b,c)平移,不是平移到這個點

glRotate*(angle,a,b,c)

沿着從(0,0,0)到(a,b,c)的這個向量,進行旋轉angle的角度


實質理解:

實質是進行了一個矩陣乘法,把當前矩陣和一個表示物體移動的矩陣相乘。

有一種很好的理解方法是想象當前畫筆所在的Opengl世界座標系的位置,在未進行任何平移或旋轉操作前,每次繪製時畫筆都是以原始的世界座標系作爲參考,所繪製的座標就是所填寫的座標。例如

glBegin(GL_LINES);

    glBegin(GL_LINES);
    glVertex3f(-5.0f,0.0f,0.0f);
    glVertex3f(5.0f,0.0f,0.0f);
    glVertex3f(0.0f,-5.0f,0.0f);
    glVertex3f(0.0f,5.0f,0.0f);
    glVertex3f(0.0f,0.0f,5.0f);
    glVertex3f(0.0f,0.0f,-5.0f);

glEnd();

這個例子就是嚴格按照上面的三維點,繪製了一個立方體,立方體中心點是世界座標系中的(0,0,0)。


如果在繪製之前用glTranslate(a,b,c),下面的繪製語句不作任何改變,有以下理解:

(1) 相當於將整個畫筆沿(a,b,c)向量平移,然後再進行繪製。

(2) 相當於先在默認世界座標系畫好,再把畫出的圖形整體向(a,b,c)平移。

(3) 相當於以世界座標系中的(a,b,c)這個點爲新的座標系的中心點,在新的座標系下執行剛纔的繪製語句。


glTranslate3f(5.0f,5.0f,5.0f);
glBegin(GL_LINES);
    glBegin(GL_LINES);
    glVertex3f(-5.0f,0.0f,0.0f);
    glVertex3f(5.0f,0.0f,0.0f);
    glVertex3f(0.0f,-5.0f,0.0f);
    glVertex3f(0.0f,5.0f,0.0f);
    glVertex3f(0.0f,0.0f,5.0f);
    glVertex3f(0.0f,0.0f,-5.0f);
glEnd();

對於glRotate操作也可以有以上三種理解方法。


3、glTranslate和glRotate 的組合使用

(1) 組合變換,如果以模型爲中心,以世界座標系爲參考,模型實際變換的順序與程序語句相反。

例如

glTranslate3f(3.0f,0.0f,3.0f);
glRotate3f(90.0f,0.0f,1.0f,0.0f);

這兩個語句的含義是,先把模型繞y軸進行90度旋轉,再沿(3.0,0.0,3.0)平移。

而不是先平移到(3,3,3),再沿y軸旋轉。

倒着看的話,所有點都是以變換前的世界座標系(我們默認變換前是世界座標系)爲參考的。


(2)組合變換,以相對座標系爲參考,變換順序與程序語句順序相同。

剛纔的例子,可以理解爲,

座標系的中心點平移到了(3,3,3),形成了新的座標系

以(3,3,3)作爲新的座標系的中心點,作一個圖形。

再把該圖形,在新的座標系下,沿新的座標軸的y軸旋轉。


對於這前兩種理解方式,第一種方式比較好理解。


(3)組合變換使物體沿着不過原點的直線旋轉

只用glRotate()時,只能沿着(0,0,0)到(a,b,c)的向量旋轉,無法沿不過原點的其他直線旋轉。

現在我們想沿着過(1,0,1)這個點,平行於y軸的直線進行旋轉90度。

組合使用時,先把y軸平移到(1,0,1),沿着y軸旋轉90度,再平移回來。

理解就是,你把旋轉軸平移到該平移的位置了,然後旋轉完了,物體旋轉軸是對了,但是物體本身也發生了不該發生的平移,所以再平移回去。

這一套變化過程是以物體的變化爲中心的,而不是座標軸。因此,程序需要倒過來,寫法如下。

glTranslate3f(-1,0,-1); // 平移回去   第三步
glRotate3f(0,1,0); //繞新的旋轉軸旋轉   第二步
glTranslate3f(1,0,1); //把旋轉軸平移到(1,0,1) 第一步
注意模型的變換順序是從下往上的,而且我們之前說過,倒着看的話所有點都是以變換前的世界座標系爲參考的。

即:第一步是按照世界座標系下,平移到了(1,0,1);第二步把物體按照世界座標系下的(0,1,0)向量去旋轉;第三步平移回去,第三步不考慮第二步旋轉對座標系的任何影響。

(4)狀態保持

使用了glTranslate和glRotate的單個或組合完成了一次模型變化後,在沒有使用glLoadIdentity()之前,之後的繪製都相當於基於之前的變換進行。


3、glLoadIdentity() glPushMatrix() glPopMatrix()

之前我們談到了glTranslate和glRotate的狀態保持。

glLoadIdentity() 用於清除之前的平移旋轉狀態,使繪圖座標系與opengl默認的世界座標系重合

glPushMatrix() 用於保存當前的平移或旋轉狀態(變換矩陣),保存到一個棧的棧頂,下次需要恢復這個狀態時,彈出

glPopMatrix()用於將棧頂保存的狀態(矩陣)彈出棧頂

例子就是畫座標軸的箭頭,先畫好三個軸,此時沒有平移旋轉,座標軸就是opengl世界座標系,我們設當前狀態爲 s1。

畫x軸箭頭時,要先保存當前狀態s1,平移到x軸相應位置畫了箭頭後,恢復之前的s1狀態,再保存s1,平移到y軸畫箭頭........


//...畫了座標軸
glPushMatrix(); //保存狀態
glTranslatef(5.0f,0.0f,0.0f);
glutSolidCone(0.2,0.4,10,10); //畫x座標軸的箭頭

glPopMatrix();//恢復剛纔的狀態
glPushMatrix();//再保存剛纔的狀態
glTranslatef(0.0f,5.0f,0.0f);
glutSolidCone(0.2,0.4,10,10); //畫y座標軸的箭頭

glPopMatrix();
glTranslatef(0.0f,0.0f,5.0f);
glutSolidCone(0.2,0.4,10,10); //畫z座標軸的箭頭



4、三維視角變換

請記住以下固定用法,在每次畫圖前在畫圖函數外或內調用。

<strong>glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(angle, width/height , near , far); 
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(eye_x, eye_y, eye_z, lookat_x, lookat_y, lookat_z, up_x, up_y, up_z); </strong>


gluLookAt(eye_x, eye_y, eye_z, lookat_x, lookat_y, lookat_z, up_x, up_y, up_z) 

都是以opengl世界座標系爲準來填寫上上述數字,填寫時注意把這個想象成你的腦袋,最後這三個不能總設爲(0,1,0),恰好在y軸俯瞰時,頭頂衝着-z方向,就要設爲(0,0,-1)

gluPerspective(angle, width/height , near , far); 

near和far的大小隻影響能不能收納進視野,不影響成像的大小。建議設置爲near=0.1,far=1000(儘可能大)

兩個語句需要按照上述模板配合使用,分別指出了眼睛位置,眼睛看向哪,和整個的視野範圍。


不調用二者設置時,畫圖往往只能在座標零點幾的範圍內變換,因爲默認視野離得太近,因此建議每次都設置一下。

設置這個實際上是進行了一個座標系轉換,將世界座標系轉成了相機座標系。因此glLookAt和繪製語句之間不要加LoadIdentity,這樣會使glLookAt作用消失

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