# 作业要求

完善以下函数:

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)

# 作业实现

# 旋转矩阵

绕 z 轴旋转的变换矩阵,只需写出旋转矩阵即可:

Eigen::Matrix4f get_model_matrix(float rotation_angle) {
    Eigen::Matrix4f model = Eigen::Matrix4f::Identity();
    model << cos(rotation_angle / 180 * MY_PI), -sin(rotation_angle / 180 * MY_PI), 0, 0,
        sin(rotation_angle / 180 * MY_PI), cos(rotation_angle / 180 * MY_PI), 0, 0,
        0, 0, 1, 0,
        0, 0, 0, 1;
    return model;
}

# 透视投影矩阵

  1. 先计算各个参数

    const auto t = zNear * tan(eye_fov / 2 / 180 * MY_PI);
    const auto r = t * aspect_ratio;
    const auto l = -r;
    const auto b = -t;
    const auto f = -zFar;
    const auto n = -zNear;
  2. 再构造正交投影矩阵

    ortho_trans << 1, 0, 0, -(r + l) / 2,
        0, 1, 0, -(t + b) / 2,
        0, 0, 1, -(n + f) / 2,
        0, 0, 0, 1;
    ortho_scale << 2 / (r - l), 0, 0, 0,
        0, 2 / (t - b), 0, 0,
        0, 0, 2 / (n - f), 0,
        0, 0, 0, 1;
    ortho = ortho_scale * ortho_trans;
  3. 将正交投影矩阵转换为透视投影矩阵

    persp_to_ortho << n, 0, 0, 0,
        0, n, 0, 0,
        0, 0, f + f, -n * f,
        0, 0, 1, 0;
    projection = ortho * persp_to_ortho;

# 任意轴旋转矩阵

使用 Rodrigues' rotation formula

R(n,θ)=cos(θ)I+(1cos(θ))nnT+sin(θ)[0nznynz0nxnynx0]\mathbf{R}(\mathbf{n}, \theta) = \cos(\theta)\mathbf{I} + (1 - \cos(\theta))\mathbf{n}\mathbf{n}^T + \sin(\theta)\begin{bmatrix}0 & -n_z & n_y \\ n_z & 0 & -n_x \\ -n_y & n_x & 0\end{bmatrix}

其中 n\mathbf{n} 是轴向量,θ\theta 是旋转角度,I\mathbf{I} 是单位矩阵。

Eigen::Matrix4f get_rotation(Vector3f axis, float angle) {
    Eigen::Matrix4f rotation = Eigen::Matrix4f::Identity();
    //Rodrigues’ Rotation Formula
    Eigen::Matrix3f N;
    N << 0, -axis.z(), axis.y(),
        axis.z(), 0, -axis.x(),
        -axis.y(), axis.x(), 0;
    rotation.block<3, 3>(0, 0) = Eigen::Matrix3f::Identity() * cos(angle) + (1 - cos(angle)) * axis * axis.transpose() + sin(angle) * N;
    return rotation;
}