这里回顾GAMES101 HW1,这次的作业主题是旋转与投影 。

课程主页:

课程作业:

课程视频:

这次作业主要是实现get_model_matrix和get_projection_matrix函数。

get_model_matrix

这里需要实现的是一种特殊情况,绕着$z$轴旋转,其一般情形为课程中介绍的罗德里格斯公式(公式的具体推导见后续的课程笔记):

其中$n$为轴的平行单位向量,$\alpha$为旋转角度。

利用上述公式,实现起来是很简洁的:

Eigen::Matrix4f get_rotation(Vector3f axis, float angle) {
    Eigen::Matrix4f model = Eigen::Matrix4f::Identity();
    Eigen::Matrix3f rotate = Eigen::Matrix3f::Zero();
    Eigen::Matrix3f tmp;
    tmp << 0, -axis.z(), axis.y(), 
           axis.z(), 0, -axis.x(), 
           -axis.y(), axis.x(), 0;
    float alpha = angle / 180 * MY_PI;
    rotate += std::cos(alpha) * Eigen::Matrix3f::Identity() + 
              (1 - std::sin(alpha)) * axis * axis.transpose() + \
              std::sin(alpha) * tmp;
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3;j ++) {
            model(i, j) = rotate(i, j);
        }
    }
    
    return model;
}

Eigen::Matrix4f get_model_matrix(float rotation_angle)
{
    // Eigen::Matrix4f model = Eigen::Matrix4f::Identity();

    // TODO: Implement this function
    // Create the model matrix for rotating the triangle around the Z axis.
    // Then return it.
    Eigen::Vector3f z(0, 0, 1);
    Eigen::Matrix4f model = get_rotation(z, rotation_angle);

    return model;
}

get_projection_matrix

投影变换的目标是将立方体[l, r] x [b, t] x [f, n]映射到$[-1, 1]^3$,分为两步:

  1. Perspective Projection
  2. Orthographic Projection

Orthographic Projection比较简单,公式为:

Perspective Projection比较复杂,其计算公式为:

最后的结果为:

函数传入的参数为:

  • eye_fov
  • aspect_ratio
  • zNear (n)
  • zFar (f)

要和[l, r] x [b, t] x [f, n]对应上,需要使用下图:

因此(注意作业中假设$r+l =0, t+b=0$):

  • $t= |n|\tan \frac{fovY}{2}$
  • $b =-t$
  • $r= t\times aspect$
  • $l=-r$

注意,由于可视化的原因,实际中$t$的计算方式为:

整体代码如下:

Eigen::Matrix4f get_projection_matrix(float eye_fov, float aspect_ratio, float zNear, float zFar)
{
    // TODO: Copy-paste your implementation from the previous assignment.
    Eigen::Matrix4f projection = Eigen::Matrix4f::Identity();

    // TODO: Implement this function
    // Create the projection matrix for the given parameters.
    // Then return it.
    // persp
    Eigen::Matrix4f persp2ortho = Eigen::Matrix4f::Zero();
    // 保证为负数
    float n = zNear;
    float f = zFar;
    float A = n + f;
    float B = - n * f;
    persp2ortho << n, 0, 0, 0,
                   0, n, 0, 0,
                   0, 0, A, B,
                   0, 0, 1, 0;

    // orth
    Eigen::Matrix4f scale = Eigen::Matrix4f::Zero();
    Eigen::Matrix4f tran = Eigen::Matrix4f::Identity();
    // 不加-图形为反向
    float t = -std::tan(eye_fov / 180 * MY_PI / 2) * std::abs(n);
    float r = aspect_ratio * t;
    float l = -r;
    float b = -t;
    scale << 2 / (r - l), 0, 0, 0,
             0, 2 / (t - b), 0, 0,
             0, 0, 2 / (n - f), 0,
             0, 0, 0, 1;
    tran << 1, 0, 0, -(r + l) / 2,
            0, 1, 0, -(t + b) / 2,
            0, 0, 1, -(n + f) / 2,
            0, 0, 0, 1;
            
    // final result
    projection = scale * tran * persp2ortho;

    return projection;
}

编译并运行:

make -j4
 ./Rasterizer -r 20 image.png
 ./Rasterizer -r 0 origin.png 

可视化结果:

origin.png:

image.png: