本篇沒有實作,僅數學理解內容
今天的內容,可能有點長,會拆成兩篇 - 2D的數學世界(三) (謎: 爽啦?!有水了一回)
DrawTexture
之前畫的兔子,不只倒著,還有中年發福的跡象,發福的原因在於,預設所使用的座標
// 每行前兩個是頂點座標的XY
static const float VERTICES[] = {
0.5f, 0.5f, 1.0f, 1.0f, // top right
0.5f, -0.5f, 1.0f, 0.0f, // bottom right
-0.5f, -0.5f, 0.0f, 0.0f, // bottom left
-0.5f, 0.5f, 0.0f, 1.0f // top left
};
換個角度觀察可以知道一件事,明明頂點的座標這麼小,解析度有800x600,可是為什麼看起來已經佔了1/4的螢幕了?其原因則在於座標系上。
笛卡爾座標,這個從國小就開始接觸的座標系,簡單的在紙上換上兩條垂直交叉的線,2D世界的雛型就出來了。除了常見的笛卡爾座標系,還有極座標系、球座標系和齊次座標系(這個後面會用到)。
接下來談談座標系轉換,我的用詞可能是錯誤的,也請糾正,這裡僅寫上我的理解還請見諒:
我們拿笛卡爾、極座標系來說明,如果用這兩個不同的座標系在2D上作圖,最終結果都只會看到一個點,或是一條線(向量)。既使最終描繪的點一樣,這兩個最大的不同是他們的基底(Basis)不一樣,也是說同一個點,不同坐標系上,描述的情況不一樣,以笛卡爾來說:
// 假如要動X軸,那"基底向量"就是
| 1 |
| 0 |
// 假如要動Y軸,那"基底向量"就是
| 0 |
| 1 |
// 把這兩個向量形成一個矩陣
| 1 0 |
| 0 1 |
最後範例裡的矩陣,就是"基底(Basis)",我們可以用這個矩陣來構築2D世界,只要這樣作
// 這裡的x, y先不視為座標上的x, y
// 而是對於"基底向量"的延伸(scalar)
// 如: x 就是對基底向量 (1, 0)的延伸,之後就變成(x, 0)
| 1 0 | | x |
| 0 1 | | y |
就可以到一個平面上的任意點,這個叫做"線性生成空間(Span)",沒錯,這樣一個空間就誕生了。
那以極座標來說,他的基底就會是
// 令角度為theta
| cos(theta) 0 |
| 0 sin(theta) |
如果要從A座標系轉換到B座標系,我們只要找到轉換矩陣就可以把A座標系的向量X轉換到座標系B。舉個例來說,這邊我用unity舉例,用過的小夥伴,應該聽過這兩個
localPositon
Position
這兩個就是描述不同座標系底下的座標位置,localPosition是物件本身,你可以看成是模型本身,以自身為原點畫出的座標;Position則是世界座標,是以世界為中心點畫出來的座標。
其實最後要說明的就是這件事,最開始畫的矩形,並不是在800x600的這個座標系(世界座標)上,而是OpenGL本身的座標系-Normalized Device Coordinate, NDC上,這個座標系三軸(x, y, z)的範圍都是[-1, 1],所以才會看到以每個象限0.5為頂點的矩形,會長在中間,並佔了整個畫面的1/4。
接下來就是要對四個頂點座標,轉換到800x600的世界裡面...
回到預設的vertex shader上,原本各為0.5的座標是上面所提到的localPosition
,我們要把他換到世界座標上,這邊會需要一個轉換的矩陣。但除了世界座標還不夠,我們要觀看這個世界還需要一個小窗口也可以說是相機,去觀看世界,這裡也會需要一個矩陣。然後我們還要決定看過去的景象是透視(往遠處延伸到一點)還是正投影(沒有透視效果),這個空間會叫作齊次座標空間,最後還要把矩形轉換到NDC上,也就是螢幕空間。
整理一下:
本地(?)座標 -> [模型矩陣] -> 世界座標 -> [視角矩陣] -> 相機空間 -> [透視矩陣] -> 齊次座標空間
那這些矩陣合而為一,就會是所謂的MVP矩陣。
最後換到齊次座標空間原因是,齊次坐標可讓包括無窮遠點的點坐標以有限坐標表示(from wiki),轉到世界空間時就是了,XY兩軸並終點是無窮大,但我們需要把我們的矩形放到NDC裡面,這就需要換到齊次空間了。
這裡是先跳過相機視角,因為這還要處理相機的移動,之後會再相機篇的時候加進去,所以會先跳過視角矩陣的部分;透視(Perspective)還是正投影(Orthographic),因為只是在2D內所以透視矩陣會是正投影的方式。
所以目前MVP的矩陣,只會是MP的部分。
再來其實就是矩陣的運算了,請注意,通常我們看數學算式都是從左到右,但矩陣的計算會是從右到左
首先是模型(Model)矩陣,測試用的,直接產在原點上,主要要處理的就是實作,正投影的功能。
如何實作我是參考這篇的OpenGL Projection Matrix