前往
大廳
主題

GAMES101-現代電腦圖形學入門-作業一

楓之焰 | 2024-01-02 05:49:22 | 巴幣 0 | 人氣 90

前言

最近下定決心開始打好底子,走技美路線,於是找到了對岸很熱門的圖形學課程
去年有看幾集但不了了之,這次要努力堅持且每個作業都會寫一篇文章記錄

目標

get_model_matrix(float rotation_angle): 逐一元素地建構模型變換矩
陣並傳回該矩陣。 在此函數中,你只需要實現三維中繞 z 軸旋轉的變換矩陣,
而不用處理平移與縮放。
• get_projection_matrix(float eye_fov, float aspect_ratio, float
zNear, float zFar): 使用給定的參數逐個元素地建立透視投影矩陣並返回
該矩陣。
• 加分題: 在 main.cpp 中建構一個函數,函數的作用是得到繞任意
過原點的軸的旋轉變換矩陣。
Eigen::Matrix4f get_rotation(Vector3f axis, float angle)

實作

1.旋轉矩陣
Eigen::Matrix4f get_model_matrix(float rotation_angle)
{
    Eigen::Matrix4f model;

    // TODO: Implement this function
    // Create the model matrix for rotating the triangle around the Z axis.
    // Then return it.
    float sinValue = std::sin(rotation_angle * MY_PI / 180);
    float cosValue = std::cos(rotation_angle * MY_PI / 180);
    model << cosValue, -sinValue, 0.0, 0.0,
        sinValue, cosValue, 0.0, 0.0,
        0.0, 0.0, 1.0, 0.0,
        0.0, 0.0, 0.0, 1.0;

    return model;
}

課堂上解釋過的旋轉矩陣,作業只有旋轉Z軸,太簡單了
要注意的是角度要換算成弧度

2.透視投影矩陣

Eigen::Matrix4f get_projection_matrix(float eye_fov, float aspect_ratio,
                                      float zNear, float zFar)
{
    // Students will implement this function

    Eigen::Matrix4f projection_pers2ortho = Eigen::Matrix4f::Identity();
    // TODO: Implement this function
    // Create the projection matrix for the given parameters.
    // Then return it.

    projection_pers2ortho << zNear, 0, 0, 0,
        0, zNear, 0, 0,
        0, 0, zNear + zFar, -zNear * zFar,
        0, 0, 1, 0;

    float height = tan(eye_fov / 2 * MY_PI / 180) * -zNear * 2;
    float width = height * aspect_ratio;
    float depth = std::abs(zNear - zFar);

    Eigen::Matrix4f projection_ortho;
    projection_ortho << 2 / width, 0, 0, -width / 2,
        0, 2 / height, 0, -height / 2,
        0, 0, 2 / depth, -depth / 2,
        0, 0, 0, 1;

    return projection_ortho * projection_pers2ortho;
}

根據課程內容,透視投影矩陣是將透視投影的視錐體變換為長方體

透視投影矩陣

再對變換過的座標乘上正視投影矩陣就完成了

要注意的是上面算出的height要乘上近平面的距離(zNear)而不是遠平面的距離(zFar)。
還有zNear要是負的,因為在這邊相機是往-Z方向看,zNear和zFar都是負數,若沒有加負號則height會是負數,會造成矩陣將scale乘上負數,導致成像是上下顛倒的

最後編譯執行可以得到一個三角形,並且按A或D可以旋轉三角形

3.加分題

這題滿難的,翻了上課影片老師只有稍微帶過一個可以繞任意軸旋轉的公式 - 羅德里格旋轉公式(rodrigues rotation formula)
看了真的很懵啊...尤其我數學又不好,雖然但是,我還是耐著性子查了一下推導方法
很多推導都是30分鐘以上的長片,又更加勸退我,不然就是一堆代數的文字講解
好在有一部影片先用簡單的畫圖方式讓人理解,我才徹底明白
其實就是假設旋轉軸為Y軸,再用叉積、點積等方式取得Z軸及X軸,在Z軸及X軸上做2D旋轉,最後把這些向量加起來而已。也許哪天有空的時候做個3D視覺化推導
了解原理後,再將公式寫成程式碼,就能讓三角形繞特定軸旋轉了!

Eigen::Matrix4f get_rotation(Vector3f axis, float angle)
{
    axis = axis.normalized();
    Eigen::Matrix4f model = Eigen::Matrix4f::Identity();
    Eigen::Matrix3f temp = Eigen::Matrix3f::Identity();
    float ag = angle / 180 * MY_PI;
    Eigen::Matrix3f tr;
    Eigen::Matrix3f crossM;
    crossM << 0, -axis[2], axis[1],
        axis[2], 0, -axis[0],
        -axis[1], axis[0], 0;
    tr = cos(ag) * temp + (1 - cos(ag)) * axis * axis.transpose() + crossM * sin(ag);
    model << tr(0, 0), tr(0, 1), tr(0, 2), 0,
        tr(1, 0), tr(1, 1), tr(1, 2), 0,
        tr(2, 0), tr(2, 1), tr(2, 2), 0,
        0, 0, 0, 1;
    return model;
}

創作回應

更多創作