二、OpenGL中的幾種變換
OpenGL中的各種轉換是通過矩陣運算實現的,具體的說,就是當發出一個轉換命令時,該命令會生成一個4X4階的轉換矩陣(OpenGL中的物體坐標一律采用齊次坐標,即(x, y, z, w),故所有變換矩陣都采用4X4矩陣),當前矩陣與這個轉換矩陣相乘,從而生成新的當前矩陣。例如,對于頂點坐標v ,轉換命令通常在頂點坐標命令之前發出,若當前矩陣為C,轉換命令構成的矩陣為M,則發出轉換命令后,生成的新的當前矩陣為CM,這個矩陣再乘以頂點坐標 v,從而構成新的頂點坐標CMv。上述過程說明,程序中繪制頂點前的最后一個變換命令最先作用于頂點之上。這同時也說明,OpenGL編程中,實際的變換順序與指定的順序是相反的。
(一)視點變換
視點變換確定了場景中物體的視點位置和方向,就向上邊提到的,它象是在場景中放置了一架照相機,讓相機對準要拍攝的物體。確省時,相機(即視點)定位在坐標系的原點(相機初始方向都指向Z負軸),它同物體模型的缺省位置是一致的,顯然,如果不進行視點變換,相機和物體是重疊在一起的。
執行視點變換的命令和執行模型轉換的命令是相同的,想一想,在用相機拍攝物體時,我們可以保持物體的位置不動,而將相機移離物體,這就相當于視點變換;另外,我們也可以保持相機的固定位置,將物體移離相機,這就相當于模型轉換。這樣,在OpenGL中,以逆時針旋轉物體就相當于以順時針旋轉相機。因此,我們必須把視點轉換和模型轉換結合在一起考慮,而對這兩種轉換單獨進行考慮是毫無意義的。
除了用模型轉換命令執行視點轉換之外,OpenGL實用庫還提供了gluLookAt()函數,該函數有三個變量,分別定義了視點的位置、相機瞄準方向的參考點以及相機的向上方向。該函數的原型為:
void gluLookAt(GLdouble eyex,GLdouble eyey,GLdouble eyez,GLdouble centerx,GLdouble centery,GLdouble upx,GLdouble upy,GLdouble upz);
該函數定義了視點矩陣,并用該矩陣乘以當前矩陣。eyex,eyey,eyez定義了視點的位置;centerx、centery和centerz變量指定了參考點的位置,該點通常為相機所瞄準的場景中心軸線上的點;upx、upy、upz變量指定了向上向量的方向。
通常,視點轉換操作在模型轉換操作之前發出,以便模型轉換先對物體發生作用。場景中物體的頂點經過模型轉換之后移動到所希望的位置,然后再對場景進行視點定位等操作。模型轉換和視點轉換共同構成模型視景矩陣。
(二)模型變換
模型變換是在世界坐標系中進行的。缺省時,物體模型的中心定位在坐標系的中心處。OpenGL在這個坐標系中,有三個命令,可以模型變換。
1、模型平移
glTranslate{fd}(TYPE x,TYPE y,TYPE z);
該函數用指定的x,y,z值沿著x軸、y軸、z軸平移物體(或按照相同的量值移動局部坐標系)。
2、模型旋轉
glRotate{fd}(TYPE angle,TYPE x,TYPE,y,TYPE z);
該函數中第一個變量angle制定模型旋轉的角度,單位為度,后三個變量表示以原點(0,0,0)到點(x,y,z)的連線為軸線逆時針旋轉物體。例如,glRotatef(45.0,0.0,0.0,1.0)的結果是繞z軸旋轉45度。
3、模型縮放
glScale{fd}(TYPE x,TYPE y,TYPE z);
該函數可以對物體沿著x,y,z軸分別進行放大縮小。函數中的三個參數分別是x、y、z軸方向的比例變換因子。缺省時都為1.0,即物體沒變化。程序中物體Y軸比例為2.0,其余都為1.0,就是說將立方體變成長方體。
(三)投影變換
經過模型視景的轉換后,場景中的物體放在了所希望的位置上,但由于顯示器只能用二維圖象顯示三維物體,因此就要靠投影來降低維數(投影變換類似于選擇相機的鏡頭)。
事實上,投影變換的目的就是定義一個視景體,使得視景體外多余的部分裁剪掉,最終進入圖像的只是視景體內的有關部分。投影包括透視投影(Perspective Projection)和正視投影(Orthographic Projection)兩種。
透視投影,符合人們心理習慣,即離視點近的物體大,離視點遠的物體小,遠到極點即為消失,成為滅點。它的視景體類似于一個頂部和底部都被進行切割過的棱椎,也就是棱臺。這個投影通常用于動畫、視覺仿真以及其它許多具有真實性反映的方面。
OpenGL透視投影函數有兩個,其中函數glFrustum()的原型為:
void glFrustum(GLdouble left,GLdouble Right,GLdouble bottom,GLdouble top,GLdouble near,GLdouble far);
它創建一個透視視景體。其操作是創建一個透視投影矩陣,并且用這個矩陣乘以當前矩陣。這個函數的參數只定義近裁剪平面的左下角點和右上角點的三維空間坐標,即(left,bottom,-near)和(right,top,-near);最后一個參數far是遠裁剪平面的Z負值,其左下角點和右上角點空間坐標由函數根據透視投影原理自動生成。near和far表示離視點的遠近,它們總為正值。該函數形成的視景體如圖三所示。

基于VC++的OpenGL編程講座之坐標變換(圖三)
圖三、透視投影視景體
另一個透視函數是:
void gluPerspective(GLdouble fovy,GLdouble aspect,GLdouble zNear, GLdouble zFar);
它也創建一個對稱透視視景體,但它的參數定義于前面的不同,參數fovy定義視野在X-Z平面的角度,范圍是[0.0, 180.0];參數aspect是投影平面寬度與高度的比率;參數zNear和Far分別是遠近裁剪面沿Z負軸到視點的距離,它們總為正值。
基于VC++的OpenGL編程講座之坐標變換(圖四)
圖四、透視投影視景體
以上兩個函數缺省時,視點都在原點,視線沿Z軸指向負方向。
正射投影,又叫平行投影。這種投影的視景體是一個矩形的平行管道,也就是一個長方體,如圖五所示。正射投影的最大一個特點是無論物體距離相機多遠,投影后的物體大小尺寸不變。這種投影通常用在建筑藍圖繪制和計算機輔助設計等方面,這些行業要求投影后的物體尺寸及相互間的角度不變,以便施工或制造時物體比例大小正確。
基于VC++的OpenGL編程講座之坐標變換(圖五)

圖五、正射投影視景體
OpenGL正射投影函數也有兩個,一個函數是:
void glOrtho(GLdouble left,GLdouble right,GLdouble bottom,GLdouble top, GLdouble near,GLdouble far)
它創建一個平行視景體。實際上這個函數的操作是創建一個正射投影矩陣,并且用這個矩陣乘以當前矩陣。其中近裁剪平面是一個矩形,矩形左下角點三維空間坐標是(left,bottom,-near),右上角點是(right,top,-near);遠裁剪平面也是一個矩形,左下角點空間坐標是(left,bottom,-far),右上角點是(right,top,-far)。所有的near和far值同時為正或同時為負。如果沒有其他變換,正射投影的方向平行于Z軸,且視點朝向Z負軸。這意味著物體在視點前面時far和near都為負值,物體在視點后面時far和near都為正值。
另一個函數是:
void gluOrtho2D(GLdouble left,GLdouble right,GLdouble bottom,GLdouble top)
它是一個特殊的正射投影函數,主要用于二維圖像到二維屏幕上的投影。它的near和far缺省值分別為-1.0和1.0,所有二維物體的Z坐標都為0.0。因此它的裁剪面是一個左下角點為(left,bottom)、右上角點為(right,top)的矩形。