Director 偶而上來逛逛的過客
註冊時間: 2013-11-04 文章: 13
381.66 果凍幣
|
發表於: 2013-11-7, PM 8:41 星期四 文章主題: GLSL&GLUT 從環境設定開始的基礎教學(02) - 關於矩陣 |
|
|
這章我打算跟大家稍微說明一下關於OpenGL裡面的矩陣(Model, View, Projection matrix)。
大部分GLSL的實作都需要一點關於這三種矩陣的基本知識,相信大多數人都認得這段程式碼。
代碼: |
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective( WINDOW_VISION_ANGLE, (float)w/(float)h, WINDOW_VISION_NEAR, WINDOW_VISION_FAR );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
gluLookAt( 0, 0, 1, 0, 0, 0, 0, 1, 0 );
|
初學OpenGL的人一般只要記得在畫圖之前先放上這些就可以畫出東西來了。
但是在GLSL的某些實作應用,你會只需要用到三種矩陣裡面的其中一種。
到這邊可能有人會問,glMatrixMode不是只能夠定義兩種矩陣嗎? 要怎麼把ModelView分開成Model跟View matrix?
那麼,他們的簡介就開始了。
事實上我沒有要完全把他們的數學意義通通說明,這樣就會跟數學課一樣無聊了 。
(有興趣的可以參考這篇http://www.opengl-tutorial.org/beginners-tutorials/tutorial-3-matrices/)
我的重點在於,要如何在你的OpenGL程式內得到這三種矩陣。
有些人會選擇自己仿作一個一模一樣的class來放置矩陣資料,這樣可能比較簡單明瞭,但我在學習的時候不知道是哪裡出了岔子,只要不用gluLookAt我的camera就會出問題 。
就結果論,取得三種矩陣的方法如下,之後我們就慢慢解釋這些程式碼的意義。
代碼: |
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective( angle, win_size_w/win_size_h, vNear, vFar );
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt( 0, 0, 1, 0, 0, 0, 0, 1, 0 );
glm::mat4 ProjcetionMatrix =
glm::perspective(
angle,
win_size_w/win_size_h,
vNear,
vFar );
glm::mat4 ViewMatrix =
glm::lookAt(
glm::vec3( 0, 0, 1 ),
glm::vec3( 0, 0, 0 ),
glm::vec3( 0, 1, 0 ) );
glm::mat4 ModelMatrix = glm::mat4( 1.0 );
|
首先,你們看到的glm就是你會需要的一個函式庫叫做OpenGL Mathematics,他裡面包含了所有OpenGL中你會需要用到的資料型態(mat4就是4*4矩陣),還有矩陣運算(perspective, lookAt)。
(從這裡下載安裝http://glm.g-truc.net/0.9.4/index.html)
相信各位到這邊對照一下,應該就能很快充分理解gluPerspective還有gluLookAt做的事情了,他們就是用來設定Projecion matrix還有View matrix的函式。
建議初學OpenGL的朋友也可以順便理解一下這些是怎麼運作的。
Projection Matrix
首先在glMatrixMode(GL_PROJECTION)的時候,我們是在說我們接下來的程式碼都是要用來調整Projection matrix的。
引言回覆: |
所以假如你在這時候用了凡是,gluPerspective、glOrtho、glOrtho2D,甚至是glLookAt、glTranslatef、glScale、glRotate,你的設定都會拿來調整Projection matrix。
可能有點難懂。
我想要表達的是,在程式設計上面的意義,所有調整矩陣的函式都是拿來調整"現在設定"的那個矩陣,並不是說gluPerspective就只會作用在Projection matrix,glLookAt就只能用在modelview matrix,所以一開始設定的那些碼才會有那樣既定的順序。
簡言之,因為你設定了glMatrixMode(GL_PROJECTION)所以gluPerspective才會調整Projection matrix。
我想這樣應該夠簡單了
|
接下來我們看到的是glLoadIdentity,他的意思是會把"現在設定"的那個矩陣還原成單位矩陣,有點類似歸零的動作(但是不是真的設為0)。
※單位矩陣在線性代數裡應該都介紹過,無論什麼矩陣乘上單位矩陣,值都不會變
接下來的gluPerspective的意思,就是你把它要的參數代進去,然後他會算出一個矩陣,然後把那個矩陣乘上"現在設定"的那個矩陣。
我想到這裡已經相當明白了,三個函式就代表,選擇矩陣、把矩陣設成單位矩陣、然後乘上gluPerspective算出來的矩陣。
但是既然gluPerspective算出來的矩陣乘上單位矩陣還是原來的樣子,那我們就可以理解,gluPerspective算出來的矩陣就是投影矩陣。
所以就像下面的。
代碼: |
glm::mat4 ProjcetionMatrix =
glm::perspective(
angle,
win_size_w/win_size_h,
vNear,
vFar );
|
我想這個是比較簡單的,那麼接下來是Model跟View matrix。
Model Matrix
我覺得先介紹Model matrix會比較好。
我不知道有沒有人曾經跟我一樣 ,誤認gluLookAt會同時設定Model matrix還有View matrix,或者覺得畫圖會影響到Model matrix(他的名子看起來就讓人覺得跟物件有關係呀 )。
假如沒有的話,其實可以跳過這段,假如有類似問題的話,那我們就接下來看下去。
事實上,Model matrix的功能只有一個,把物件的參考座標轉換成世界座標。
什麼是世界座標?
一般來說,我是指一般來說,在立體空間我們會以x=0, y=0, z=0也就是(0, 0, 0)這個座標當作基準。
也就是說,當我說一個點在(4, 0, 0),我們無形中就是在表示這個點的位置是在(0, 0, 0)的 "x軸" 正向 "4單位距離" 的地方。
我想這個是高中數學,應該大家都沒問題的。
而重點就在這裡,我們在OpenGL設定的glVertex3f(4, 0, 0)不是指一個坐落於座標(4, 0, 0)的點,而是我上面說的基於基準點的 "x軸" 正向 "4單位距離" 位置
那麼,假如我把基準點改成(2, 0, 0),那glVertex3f(4, 0, 0)就會給我一個坐落於座標(6, 0, 0)的點。
於是我們就來看看基準點和Model matrix是怎樣子的關係。
引言回覆: |
這是一個glLoadIdentity之後的Model matrix。
所謂的基準點是在最下面三行的左邊三個。
在glVertex設定的數字假如乘上這個Model matrix,最後得到的座標點就會像剛剛上面說的從(4, 0, 0)變成(6, 0, 0),大家可以自己拿筆算算看這個。
|
那麼,簡單來說Model matrix就是一個把glVertex設定的值轉換成真正座標的矩陣。
題外話,我上面用的圖片其實只有說到基準點也就是位移的部分,事實上我們通常會用glTranslate(位移)、glScale(縮放)、glRotate(旋轉),這三種函數去改變Model matrix。
大多時候,我們會保持Model matrix一直是單位矩陣,因為我們想要glVertex3f(4, 0, 0),那個點就在(4, 0, 0),我們不想要去考慮基準點的問題。
引言回覆: |
Push PopMatrix原理
這也是題外話。
當我們在畫立體圖形的時候,要讓它整個位移,我們不想要一個點一個點分座標去算,我們就會用到glTranslate,可是假如直接用通常會出現整個世界都被位移了的問題。
在這邊大家都會用glPushMatrix和glPopMatrix把glTranslate和glVertex包住,像這樣。
代碼: |
glPushMatrix();
glTranslatef( 2.0, 0.0, 0.0 );
glBegin( GL_QUADS );
glVertex3f( 3, 0, 3 );
glVertex3f( 3, 0, -3 );
glVertex3f( -3, 0, -3 );
glVertex3f( -3, 0, 3 );
glEnd();
glPopMatrix();
|
你可以想像它是這麼做的。
glPushMatrix複製了一個跟現在一樣的Model matrix(單位矩陣),然後把它做glTranslate(2, 0, 0),得到一個基準點(2, 0, 0)的Model matrix,然後當glVertex送上(3, 0, 3)的時候,會被Model matrix轉換過,變成(5, 0, 3)之後再送交給OpenGL畫圖。
glPopMatrix就把你剛剛複製並且改變的那個矩陣刪除掉,然後你原來的Model matrix依舊是單位矩陣。
glScale、glRotate會包在Push跟PopMatrix也是一樣的意思。
|
最後補充一下。
T的位置,從左至右就是使用glTranslate的(x, y, z)。
S的位置,從左至右就是使用glScale的(x, y, z)。
有興趣的都可以拿筆算算看。
於是乎,講了好久,只要一直有在利用Push和PopMatrix來調整點,那這一行通常就等於我們的Model matrix 。
代碼: |
// 這樣的宣告方式就是單位矩陣的意思
glm::mat4 ModelMatrix = glm::mat4( 1.0 );
|
View Matrix
我想這應該就不用多說了,既然我們的Model matrix一直都保持單位矩陣,那自然gluLookAt設定的就只有View matrix。
所以View matrix就等同於。
代碼: |
glm::mat4 ViewMatrix =
glm::lookAt(
glm::vec3( 0, 0, 1 ),
glm::vec3( 0, 0, 0 ),
glm::vec3( 0, 1, 0 ) );
|
利用glm提供的函數,我們可以很快速的得到它。
那麼希望大家看完之後能夠對矩陣有更多的認識,這些對於我之後要寫的範例程式來說都相當重要,那麼就先這樣。
Happy coding!
Director 在 2013-11-23, PM 9:46 星期六 作了第 1 次修改 |
|