目录

GAMES101 作业1答案

开始坚持学习GAMES101了,本来去年暑假都已经打算开始,却还是拖到了现在。上学期在学校已经上过了图形学的课,但感觉啥也没学,现在在这里我要坚持把这个课学完。

模型变换

三维中绕z轴旋转

课件中给出了三维绕z轴的旋转矩阵的公式:

在函数中直接写入该公式即可,注意参数rotation_angle使用角度表示,而cmath中的三角函数使用弧度制,因此要进行转换。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
Eigen::Matrix4f get_model_matrix(float rotation_angle)
{
    Eigen::Matrix4f model = Eigen::Matrix4f::Identity();

    // Implement this function [Implemented]
    // Create the model matrix for rotating the triangle around the Z axis.
    // Then return it.
    auto rr = static_cast<float>(rotation_angle * MY_PI / 180.);  // rotation radian
    Eigen::Matrix4f rotate;
    rotate << cos(rr), -sin(rr), 0, 0,
            sin(rr), cos(rr), 0, 0,
            0, 0, 1, 0,
            0, 0, 0, 1;

    model = rotate * model;

    return model;
}

绕任意过原点的轴旋转

绕任意过原点的轴可以转化为绕x、y和z三轴综合旋转而成: 根据课中学到的Rodrigues公式有:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// 绕任意过原点的轴旋转的变换矩阵
Eigen::Matrix4f get_rotation(Vector3f axis, float angle) {
    Eigen::Matrix4f rotation = Eigen::Matrix4f::Identity();

    auto a = static_cast<float>(angle * MY_PI / 180.);
    Eigen::Vector3f n = axis.normalized();  // 进行归一化
    float nx = n(0), ny = n(1), nz = n(2);
    // 根据Rodrigues旋转公式
    rotation.block<3, 3>(0, 0) =
            cos(a) * Eigen::Matrix3f::Identity() +
            (1 - cos(a)) * n * n.transpose() +
            sin(a) * Eigen::Matrix3f{{0,   -nz, ny},
                                     {nz,  0,   -nx},
                                     {-ny, nx,  0}};

    return rotation;
}

投影变换

透视投影可以先通过矩阵转换为一个长方体,接着就可以使用平行投影的方法对它进行变换。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Eigen::Matrix4f get_projection_matrix(float eye_fov, float aspect_ratio,
                                      float zNear, float zFar)
{
    // Students will implement this function

    Eigen::Matrix4f projection = Eigen::Matrix4f::Identity();

    // Implement this function [Implemented]
    // Create the projection matrix for the given parameters.
    // Then return it.
    float n = zNear, f = zFar;
    Eigen::Matrix4f M_persp2ortho{{n, 0, 0,     0},
                                  {0, n, 0,     0},
                                  {0, 0, n + f, -n * f},
                                  {0, 0, 1,     0}};
    auto a = static_cast<float>(eye_fov * MY_PI / 180. / 2.);
    float t = abs(n) * tan(a), b = -t, l = b / aspect_ratio, r = -l;
    auto M_ortho = Eigen::Matrix4f{{2 / (r - l), 0,           0,           0},
                                   {0,           2 / (t - b), 0,           0},
                                   {0,           0,           2 / (n - f), 0},
                                   {0,           0,           0,           1}} *
                   Eigen::Matrix4f{{1, 0, 0, -(r + l) / 2},
                                   {0, 1, 0, -(t + b) / 2},
                                   {0, 0, 1, -(n + f) / 2},
                                   {0, 0, 0, 1}};
    projection = M_ortho * M_persp2ortho * projection;

    return projection;
}

渲染结果

1
./Rasterizer.exe -r 30 output.png

/games101-1/output.png