以下位移、旋轉、縮放僅是補充,又或著是說個人筆記(?),閱讀這篇單純的看算式結果就可以知道,為什麼他的矩陣是長這樣了。
把這兩個放在一起講是因為真的沒有甚麼要多補充的,只是單純少了一軸-Z而已,並且看起來更簡單了。
/*
Translate:
1 0 0 x
0 1 0 y
0 0 1 z
0 0 0 1
*/
Mat4 Mat4Translate(Mat4 origin, float x, float y) {
Mat4 translate = MAT4_IDENTITY;
translate.ary2d[3][0] = x;
translate.ary2d[3][1] = y;
return Mat4MulMat4(origin, translate);
}
/*
Scale:
x 0 0 0
0 y 0 0
0 0 z 0
0 0 0 1
*/
Mat4 Mat4Scale(Mat4 origin, float x, float y) {
Mat4 scale = MAT4_IDENTITY;
scale.ary2d[0][0] = x;
scale.ary2d[1][1] = y;
return Mat4MulMat4(origin, scale);
}
好在是2D,要旋轉的話,我們只需要Z軸
/*
Rotate:
s = sin(angle), c = cos(angle)
c -s 0 0
s c 0 0
0 0 1 0
0 0 0 1
*/
Mat4 Mat4EulerRotate(Mat4 origin, float angle) {
Mat4 rotate = MAT4_IDENTITY;
float rad = DegToRad(angle);
float s = sinf(rad), c = cosf(rad);
rotate.ary2d[0][0] = c;
rotate.ary2d[0][1] = s;
rotate.ary2d[1][0] = -s;
rotate.ary2d[1][1] = c;
return Mat4MulMat4(origin, rotate);
}
單獨拿出來講是這裡,使用的尤拉角(Eular Angle)的旋轉,每個軸的旋轉都是分開算的,如果是3D的話,每個軸都要可以轉360的話,會出現**萬向鎖(Gimbal Lock)**(這個連結會到YT)。這時就會需要另一種旋轉的表示方式,四元數了。這邊沒有要繼續講四元數,因為我不是特別理解四元數是怎麼運作的,可能會在之後再來補充 :(。
昨天提過一件事
矩陣運算是從右到左
原因是矩陣的的順序調換會影響結果。
所以模型矩陣(Model Matrix) x 透視矩陣(Projection Matrix)事實上會是
// Mat4MulMat4是我製作的矩陣相乘的function
MVP = Mat4MulMat4(Projection, Model);
那...模型矩陣,是要先位移呢?還是縮放?還是旋轉,這個蠻有趣的,我個人試過的結果會是:**位移
旋轉 > 縮放**這個順序,才會看起來比較正常。
如果自由地縮放視窗會發現,裏頭的矩形沒有隨著視窗的大小變化進行縮放,這是因為我們縮放了視窗大小,但沒有縮放OpenGL的視窗大小,需要使用法寶:
glViewport(int x, int y, int width, int height)
然後glfw
也有提供「當視窗大小有變化時」的Callback,一樣在CreateWindow
加上新的處理
// framebuffer size callback
void FramebufferSizeCallback(GLFWwindow* window, int w, int h) {
glViewport(0, 0, w, h);
}
// in `CreateWindow`
glfwSetFramebufferSizeCallback(WINDOW.wnd, FramebufferSizeCallback);
就這樣,我們的矩形跟貼圖就會跟著視窗大小變化了。