iT邦幫忙

2021 iThome 鐵人賽

DAY 11
0
自我挑戰組

翻車機率極高的2D平台遊戲(2D Platformer)製作系列 第 11

[Day11] 2D的數學世界 (三) - 位移、旋轉、縮放

今日目標

  • 位移、旋轉、縮放

以下位移、旋轉、縮放僅是補充,又或著是說個人筆記(?),閱讀這篇單純的看算式結果就可以知道,為什麼他的矩陣是長這樣了。

位移、縮放

把這兩個放在一起講是因為真的沒有甚麼要多補充的,只是單純少了一軸-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);

就這樣,我們的矩形跟貼圖就會跟著視窗大小變化了。

參考

然後這是今日的成果,明天(應該)會開始處理時間相關的功能...


上一篇
[Day10] 2D的數學世界(二) - 座標系轉換
下一篇
[Day12] 關於時間粗略紀錄一下
系列文
翻車機率極高的2D平台遊戲(2D Platformer)製作33

尚未有邦友留言

立即登入留言