作业0
最开始的作业0还是非常简单的,基本上就是帮我们熟悉一下环境的,因此作业题目也很基础。
让我们看下题目:
3.1 作业描述
给定一个点 P=(2,1), 将该点绕原点先逆时针旋转 45◦,再平移 (1,2), 计算出
变换后点的坐标(要求用齐次坐标进行计算)。
要做出来这道题只需要知道课上提到的基础知识就可以了。
const PI = 3.14159265f;
// 首先声明要进行操作的点
Eigen::Vector3f point(2.0f,1.0f,1.0f);
// 并定义要进行的两个操作
Eigen::Matrix3f t1, t2;
t1 << cos(45/180*PI), -sin(45/180*PI), 0,
sin(45/180*PI), cos(45/180*PI), 0
0, 0, 1;
t2 << 1, 0, 1,
0, 1, 2,
0, 0, 1;
std::cout << t2 * t1 * point << std::endl;
作业1
本次作业的任务是填写一个旋转矩阵和一个透视投影矩阵。给定三维下三个
点 v0(2.0, 0.0, −2.0), v1(0.0, 2.0, −2.0), v2(−2.0, 0.0, −2.0), 你需要将这三个点的坐
标变换为屏幕坐标并在屏幕上绘制出对应的线框三角形 (在代码框架中,我们已
经提供了 draw_triangle 函数,所以你只需要去构建变换矩阵即可)。
从这次的作业开始,就会有一定的难度了。不过,这次的作业虽然是让我们写一个渲染器,但整体的框架已经为我们写好了。需要我们手写的部分,只是其中的两个函数而已。更详细的说的话,按照我的理解,就是MVP模型中的“M”和“P”两个矩阵。
先看 get_model_matrix
这个函数,题目中要求可以将给定的三角形绕z轴以任意角度旋转,这个函数即是输入一个角度来获取相应的变换矩阵,之后只要用该函数返回的矩阵左乘三角形三个点的坐标向量就可以获得三角形三个顶点的新坐标的向量了。
这里直接使用绕z轴旋转的旋转矩阵即可:
$$ R_z(\alpha) = \begin{pmatrix} \cos \alpha & -\sin \alpha & 0 & 0 \\ \sin \alpha & \cos \alpha & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{pmatrix} $$
之后是代码:
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::Matrix4f rotate;
float my_angle = rotation_angle * MY_PI / 180;
rotate << cos(my_angle), -sin(my_angle), 0, 0,
sin(my_angle), cos(my_angle), 0, 1,
0, 0, 1, 0,
0, 0, 0, 1;
model = rotate * model;
return model;
}
在之后是 get_projection_matrix
这个函数了,也就是透视矩阵。透视矩阵可以看作三个矩阵的相乘的结果,借用一个参考的说法,分别就是“挤压”,“缩放”和“平移”三个矩阵。其中,因为在经过前面的视图变换之后,我们要投影的图形已经在屏幕中间了,所以不需要平移矩阵了。这里只需要定义出“挤压”和“缩放”了。“挤压”矩阵就是要进行的透视变换了。对于x和y坐标只需要分别除以zNear即可,因为进行处理的是齐次坐标,因此只需要在相应的位置乘以zNear即可。至于z轴和最下面的一行,在笔记中也有推导可以参考。至于最后的缩放就很简单了,只需要先利用给出的 eye_fov
和 aspect_ratio
求出屏幕的长和宽,在进行相除即可。
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();
// TODO: Implement this function
// Create the projection matrix for the given parameters.
// Then return it.
Eigen::Matrix4f m1;
m1 << zNear, 0, 0, 0,
0, zNear, 0, 0,
0, 0, zNear+zFar, zNear*zFar,
0, 0, 1, 0;
// There is no need for ortho matrix.
Eigen::Matrix4f m2;
float height = zNear * tan(eye_fov / 2) * 2;
float width = height * aspect_ratio;
m2 << 2/height, 0, 0, 0,
0, 2/width, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1;
projection = m2 * m1 * projection;
return projection;
}
最后是第三个任务,要求将三角形绕任意过原点的轴旋转。不过这就是个可选项了。
对于这个过程,虽然我还没有自己推导出来,但还是有现成的公式可以使用的:
$$ R(n,\alpha)=\cos(\alpha)I+(1−\cos(\alpha))nn^T+\sin(α) \begin{pmatrix} 0 & -n_z & n_y \\ n_z &0 & -n_x \\ -n_y & n_x & 0 \\ \end{pmatrix} $$
Eigen::Matrix4f get_model_matrix_axis(float rotation_angle, Eigen::Vector3f axis_start, Eigen::Vector3f axis_end){
Eigen::Matrix4f model = Eigen::Matrix4f::Identity();
// 先求出旋转轴的方向向量
Eigen::Vector3f n;
n[0] = axis_end[0] - axis_start[0];
n[1] = axis_end[1] - axis_start[1];
n[2] = axis_end[2] - axis_start[2];
// 然后对其归一化
float norm = sqrt(n[0] * n[0] + n[1] * n[1] + n[2] * n[2]);
axis[0] /= norm;
axis[1] /= norm;
axis[2] /= norm;
// 将旋转角度转换为弧度
float my_angle = rotation_angle / 180.0 * MY_PI;
// 计算上面公式中的三项
Eigen::Matrix3f m1 = sin(my_angle) * Eigen::Matrix4f::Identity();
Eigen::Matrix3f m2 = (1 - cos(my_angle)) * n * n.transpose();
Eigen::Matrix3f t;
t << 0, -n[2], n[1],
n[2], 0, -n[0],
-n[1], n[0], 0;
Eigen::Matrix3f m4 = sin(my_angle) * t;
// 将上面的3x3矩阵转换成4x4矩阵。
Eigen::Matrix4f rotate = Eigen::Matrix4f::Identity();
rotate.block(0, 0, 3, 3) = (m1 + m2 + m4);
model = rotate_martix * model;
return model;
}
未完待续。。。。。。
References
[Game101现代计算机图形学作业1
](https://blog.csdn.net/Genius_J/article/details/118440804)
[Game101现代计算机图形学入门学习笔记(三)
](https://blog.csdn.net/Genius_J/article/details/118067448?spm=1001.2014.3001.5501)
[计算机图形学二:视图变换(坐标系转化,正交投影,透视投影,视口变换)
](https://blog.csdn.net/qq_38065509/article/details/105309174)
评论 (0)