OpenGL
中場景進行變換,要經(jīng)歷一些過程:視圖變換
à
模型變換
à
投影變換,然后到了窗口坐標。這幾個變換開始的時候把我搞很混,這幾天整理一下。
??????
一般書上把這幾個變換用照相機類比,其實每個變換都是產(chǎn)生著一個
4x4
矩陣,然后與當前矩陣
(Current Matrix)
相乘,得到一個坐標變換矩陣,最后把世界坐標系(歐式空間)中的物體變換到屏幕坐標系中。這里梳理一下概念:
?????? 1
、視圖變換(
VIEW Transformation
):它類似將照相機指向物體,即確定視點(觀察點)的位置和觀察方向。一般用的函數(shù)為
glu
封裝的函數(shù):
void gluLookAt(GLdouble eyex, GLdouble eyey, GLdouble eyez,? ---------
觀察點
?????? GLdouble centrex, GLdouble centrey, GLdouble centrez,? --
視線方向:從
eye
指向
centre
?????? GLdouble upx, GLdouble upy, GLdouble upz ------------
視圖體自下而上的方向
?)
??????
這個函數(shù)會產(chǎn)生一個視圖矩陣,并右乘到當前矩陣上。模型變換通常發(fā)生在模型變換之前。其實,視圖變換也是通過平移和旋轉(zhuǎn)得到的,觀察位置與物體位置之間是個相對的狀態(tài),我們也把視圖變換和模型變換統(tǒng)一成一個變換,產(chǎn)生一個矩陣:模型視圖變換矩陣。
?????? 2
、模型變換
(MODEL Transformation)
:它確定模型的位置和方向,對模型進行旋轉(zhuǎn)、平移和縮放。用到三個子函數(shù):
glTranslate*(x, y, z)
、
glRotate*(x, y, z)
、
glScale*(x, y, z)
。每個函數(shù)都會產(chǎn)生一個矩陣,并右乘當前矩陣。
?????? 3
、投影變換(
PROJECTION Transformation
):產(chǎn)生一個六面的視圖體,把視圖體以外的場景剪裁掉,把視圖體內(nèi)的物體、場景作為繪制對象,讓“照相機拍攝”。兩種投影方式,兩個投影函數(shù):
glFrustum(left, right, bottom, top, near, far)
,
glOrtho(left, right, bottom, top, near, far )
這兩個函數(shù)的參數(shù)非常對稱,都是構(gòu)筑了一個六面體,形成可視范圍。它們都產(chǎn)生一個矩陣,并左乘當前矩陣。(當然,還有
glu
的兩個函數(shù))。
??????
??????
要理解整個過程,關(guān)鍵在理解當前變換矩陣
CTM
,(簡稱為
C
)。它是一個狀態(tài)概念,應(yīng)用到
OpenGL
流水線中的每一個定點:
P = C*P’
。這條等式是對同一個點在兩個坐標系體統(tǒng)之間進行轉(zhuǎn)換,從右邊的坐標系下的坐標(
P’
)轉(zhuǎn)換到左邊的坐標系下的坐標(
P
)。而矩陣
C
是
4x4
的齊次坐標矩陣,它都蘊含著一個局部坐標系信息:以右邊坐標系為參考坐標系統(tǒng),左邊坐標系的位置和方向。
??????
用手工定義一個矩陣,如下(按
OpenGL
矩陣方式定義。與數(shù)學定義矩陣的方式轉(zhuǎn)置):
?????? CTM[16] = { a0, a1, a2, a3,???????? // x
軸的方向向量
????????????????????
?? a4, a5, a6, a7,????????? // y
軸的方向向量
????????????????????
?? a8, a9, a10, a11,????????????? // z
軸的方向向量
????????????????????
?? a12, a13, a14, a15??? //
原點的位置
??????????????????????????? }
??????
??????
再來考察當前變換矩陣
CTM
,它是在
OpenGL
流水線中一個模型視圖矩陣和一個投影矩陣的復(fù)合。
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
"
);??? // 從這里看出,是先調(diào)用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、在全局固定坐標系下,對物體進行變換。這時候,我們要以相反的順序來考慮代碼中的變換函數(shù)了,它的實際過程是這樣
P = CTM *( R*(T* p’))
。
首先、對物體進行平移,平移到坐標(
3.0, 0.0, 0.0
)?! ∪缓?,把物體相對原點繞z軸旋轉(zhuǎn)45度。
2、物體捆綁在局部坐標系下,所有的變換都是坐標系進行的。這時,我們用順序來看這個變換。
glRotatef(45.0, 0.0, 0.0, 1.0)
產(chǎn)生一個齊次矩陣
R(
這可是代表一個局部坐標系哦
) ?
,即局部坐標系
R
相對剛才開始的坐標系
I
(單位矩陣)作了旋轉(zhuǎn)變換,繞旋轉(zhuǎn)了45度。
glTranslatef(3.0, 0.0, 0.0)
產(chǎn)生一個齊次矩陣
T
(也是代表了一個局部坐標系),相對
R
坐標系沿x軸(
R
系)平移了3個單位,得到了自己的局部坐標系
T
。
最后在這個局部坐標系
T
下畫了
Cube
。
代碼中的
Tmat = R * T
,它也是從
T
坐標系變換到
R
坐標系,再變換到最后的模型視圖的世界坐標系。
?
?
后注:
??????
對坐標系的幾何變換是
“
既采用基于齊次坐標的矩陣表達形式
!
又在歐氏幾何的
Cartesian
坐標系下以對其進行說明性的定義
.
由于齊次坐標是射影幾何的語言工具
!
前者表明幾何變換的表達是基于射影幾何的后者則帶有歐氏幾何色彩
”
,所以對它的表述清晰統(tǒng)一的表述比較難。本文寫的也比較零散,有語焉不詳、理解錯誤指出,請多多指正!
?