OpenGL 中場景進行變換,要經歷一些過程:視圖變換 à 模型變換 à 投影變換,而後到了窗口座標。這幾個變換開始的時候把我搞很混,這幾天整理一下。函數
通常書上把這幾個變換用照相機類比,其實每一個變換都是產生着一個 4x4 矩陣,而後與當前矩陣 (Current Matrix) 相乘,獲得一個座標變換矩陣,最後把世界座標系(歐式空間)中的物體變換到屏幕座標系中。這裏梳理一下概念:工具
1 、視圖變換( VIEW Transformation ):它相似將照相機指向物體,即肯定視點(觀察點)的位置和觀察方向。通常用的函數爲 glu 封裝的函數:oop
void gluLookAt(GLdouble eyex, GLdouble eyey, GLdouble eyez, --------- 觀察點spa
GLdouble centrex, GLdouble centrey, GLdouble centrez, -- 視線方向:從 eye 指向 centre.net
GLdouble upx, GLdouble upy, GLdouble upz ------------ 視圖體自下而上的方向orm
)對象
這個函數會產生一個視圖矩陣,並右乘到當前矩陣上。模型變換一般發生在模型變換以前。其實,視圖變換也是經過平移和旋轉獲得的,觀察位置與物體位置之間是個相對的狀態,咱們也把視圖變換和模型變換統一成一個變換,產生一個矩陣:模型視圖變換矩陣。數學
2 、模型變換 (MODEL Transformation) :它肯定模型的位置和方向,對模型進行旋轉、平移和縮放。用到三個子函數:glTranslate*(x, y, z) 、 glRotate*(x, y, z) 、 glScale*(x, y, z) 。每一個函數都會產生一個矩陣,並右乘當前矩陣。it
3 、投影變換( PROJECTION Transformation ):產生一個六面的視圖體,把視圖體之外的場景剪裁掉,把視圖體內的物體、場景做爲繪製對象,讓「照相機拍攝」。兩種投影方式,兩個投影函數: glFrustum(left, right, bottom, top, near, far) ,io
glOrtho(left, right, bottom, top, near, far )
這兩個函數的參數很是對稱,都是構築了一個六面體,造成可視範圍。它們都產生一個矩陣,並左乘當前矩陣。(固然,還有 glu的兩個函數)。
要理解整個過程,關鍵在理解當前變換矩陣 CTM ,(簡稱爲 C )。它是一個狀態概念,應用到 OpenGL 流水線中的每個定點: P = C*P’ 。這條等式是對同一個點在兩個座標系體統之間進行轉換,從右邊的座標系下的座標( P’ )轉換到左邊的座標系下的座標( P )。而矩陣 C 是 4x4 的齊次座標矩陣,它都蘊含着一個局部座標系信息:以右邊座標系爲參考座標系統,左邊座標系的位置和方向。
用手工定義一個矩陣,以下(按 OpenGL 矩陣方式定義。與數學定義矩陣的方式轉置):
CTM[16] = { a0, a1, a2, a3, // x 軸的方向向量
a4, a5, a6, a7, // y 軸的方向向量
a8, a9, a10, a11, // z 軸的方向向量
a12, a13, a14, a15 // 原點的位置
}
再來考察當前變換矩陣 CTM ,它是在 OpenGL 流水線中一個模型視圖矩陣和一個投影矩陣的複合。 CTM = P*C*M 。(注意到上面提到的左乘右乘了嗎?)
咱們來分析一個簡單的例子:
1 #define NUM 0.70710678118654746
2 // 注意這個矩陣是正交的,沒有正交就用,好像有放縮做用
GLfloat Tmat1[16] = { NUM, NUM, 0.0, 0.0,
-NUM, NUM, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0};
GLfloat Tmat2[16] = { 1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
1.0, 0.0, 0.0, 1.0,
};
7 void setupRC( void )
8 {
9 glClearColor( 0.0f , 0.0f , 0.0f , 1.0f );
10 glShadeModel(GL_FLAT);
11 }
12
13 void RenderScene( void )
14 {
15 printf( " RenderScene\n " );
16 glClear(GL_COLOR_BUFFER_BIT);
17 glColor3f( 0.0f , 1.0f , 1.0f );
18 glMatrixMode(GL_MODELVIEW);
19 glLoadIdentity();
20 gluLookAt( 0.0 , 0.0 , 5.0 , // view point
21 0.0 , 0.0 , 0.0 , // focus point
22 0.0 , 1.0 , 0.0 ); // up vector
23
24 glutSolidCube( 0.5 ); // 原點的參考位置
25 glMultMatrixf(Tmatr1); // 這個矩陣的動做和下面的兩個變換是同樣的。
glMultMatrixf(Tmatr2);
26 // glRotatef(45.0, 0.0, 0.0, 1.0);
27 // glTranslatef(3.0, 0.0, 0.0);
28 glutSolidCube( 1.0 );
29
30 glutSwapBuffers();
31 }
32
33 void ChangeSize( int w, int h)
34 {
35 printf( " ChangeSize\n " ); // 從這裏看出,是先調用ChangeSize()的
36 GLfloat nRange = 10.0f ;
37
38 if (h == 0 )
39 h = 1 ;
40 GLfloat fRatio = (GLfloat)w / (GLfloat)h;
41
42 glMatrixMode(GL_PROJECTION);
43 glLoadIdentity();
44
45 if (w <= h)
46 glOrtho( - nRange, nRange, - nRange / fRatio, nRange / fRatio, 1.0 , nRange);
47 else
48 glOrtho( - nRange * fRatio, nRange * fRatio, - nRange, nRange, 1.0 , nRange);
49
50 glViewport( 0 , 0 , w ,h);
51
52 glMatrixMode(GL_MODELVIEW);
53 glLoadIdentity();
54 }
55
56 int main( int argc, char * argv[])
57 {
58 glutInit( & argc, argv);
59 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
60 glutInitWindowSize( 800 , 600 );
61 glutCreateWindow( " example " );
62
63 glutReshapeFunc(ChangeSize);
64 glutDisplayFunc(RenderScene);
65
66 setupRC();
67
68 glutMainLoop();
69
70 std::cout << " Hello world! " << std::endl;
71 return 0 ;
72 }
73
對 glRotatef(45.0, 0.0, 0.0, 1.0)
glTranslatef(3.0, 0.0, 0.0);
這兩個變換,能夠當作:
glMultMatrixf(R);
glMultMatrixf(T);
R,T 都是右乘到 CTM : CTM = CTM * R * T
對模型變換的理解有兩種:
1、在全局固定座標系下,對物體進行變換。這時候,咱們要以相反的順序來考慮代碼中的變換函數了,它的實際過程是這樣 P = CTM *( R*(T* p’)) 。
首先、對物體進行平移,平移到座標( 3.0, 0.0, 0.0 )。 而後,把物體相對原點繞z軸旋轉45度。
2、物體捆綁在局部座標系下,全部的變換都是座標系進行的。這時,咱們用順序來看這個變換。
glRotatef(45.0, 0.0, 0.0, 1.0) 產生一個齊次矩陣 R( 這但是表明一個局部座標系哦 ) ,即局部座標系 R 相對剛纔開始的座標系 I (單位矩陣)做了旋轉變換,繞旋轉了45度。
glTranslatef(3.0, 0.0, 0.0) 產生一個齊次矩陣 T (也是表明了一個局部座標系),相對 R 座標系沿x軸( R 系)平移了3個單位,獲得了本身的局部座標系 T 。
最後在這個局部座標系 T 下畫了 Cube 。
代碼中的 Tmat = R * T ,它也是從 T 座標系變換到 R 座標系,再變換到最後的模型視圖的世界座標系。
後注:
對座標系的幾何變換是 「 既採用基於齊次座標的矩陣表達形式 ! 又在歐氏幾何的 Cartesian 座標系下以對其進行說明性的定義 . 因爲齊次座標是射影幾何的語言工具 ! 前者代表幾何變換的表達是基於射影幾何的後者則帶有歐氏幾何色彩 」 ,因此對它的表述清晰統一的表述比較難。本文寫的也比較零散,有語焉不詳、理解錯誤指出,請多多指正!