Games101-Homework1

本章内容

本章主要讲述Games101的作业1,涉及MVP矩阵变换内容。

作业内容

实现以下三个内容

  • Eigen::Matrix4f get_model_matrix(float rotation_angle): 逐个元素地构建模型变换矩阵并返回该矩阵。在此函数中,你只需要实现三维中绕 z 轴旋转的变换矩阵,而不用处理平移与缩放。
  • Eigen::Matrix4f get_projection_matrix(float eye_fov, float aspect_ratio, float zNear, float zFar): 使用给定的参数逐个元素地构建透视投影矩阵并返回该矩阵
  • Eigen::Matrix4f get_rotation(Vector3f axis, float angle):main.cpp 中构造一个函数,该函数的作用是得到绕任意过原点的轴的旋转变换矩阵。

具体实现

作业1已经给出了Eigen::Matrix4f get_view_matrix(Eigen::Vector3f eye_pos)的实现方法,即mvp矩阵中的v,我们需要实现的就是m和p矩阵

Model矩阵

作业1只需要实现三维中绕 z 轴旋转的变换矩阵, 而不用处理平移与缩放,参考下图计算公式即可。

Projection矩阵

根据视图变换的学习笔记可知,公式如下,注意公式里的(l,r,t,b,n,f)都是具体的坐标,有正负符号的。

\[ M_{persp->ortho}^{(4*4)} = \begin{bmatrix}n & 0 & 0 & 0 \\0 & n & 0 & 0 \\0 & 0 & n+f & -nf \\0 & 0 & 1 & 0 \\\end{bmatrix} \]

\[ M_{persp} = M_{ortho} * M_{persp->ortho} \]

代码

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
Eigen::Matrix4f get_view_matrix(Eigen::Vector3f eye_pos)
{
Eigen::Matrix4f view = Eigen::Matrix4f::Identity();

Eigen::Matrix4f translate;
translate << 1, 0, 0, -eye_pos[0], 0, 1, 0, -eye_pos[1], 0, 0, 1,
-eye_pos[2], 0, 0, 0, 1;

view = translate * view;

return view;
}

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

Eigen::Matrix4f translate;
rotation_angle = rotation_angle * MY_PI / 180.0f;

translate << std::cos(rotation_angle), -std::sin(rotation_angle), 0, 0,
std::sin(rotation_angle), std::cos(rotation_angle), 0, 0,
0, 0, 1, 0,
0, 0, 0, 1;

model = translate * model;

return model;
}

Eigen::Matrix4f get_projection_matrix(float eye_fov, float aspect_ratio,
float zNear, float zFar)
{
Eigen::Matrix4f projection = Eigen::Matrix4f::Identity();

Eigen::Matrix4f persp, persp2ortho, scaleOrtho, translateOrtho;
std::cout << zNear << std::endl;
float r, l, t, b, n, f;
t = -zNear * std::tan(eye_fov / 2.0 * MY_PI / 180.0f);
r = t * aspect_ratio;
b = -t, l = -r, n = zNear, f = zFar;

translateOrtho << 1.0, 0, 0, 0,
0, 1.0, 0, 0,
0, 0, 1.0, -(n + f) / 2.0,
0, 0, 0, 1.0;

scaleOrtho << 2.0 / (r - l), 0, 0, 0,
0, 2.0 / (t - b), 0, 0,
0, 0, 2.0 / (n - f), 0,
0, 0, 0, 1.0;

persp2ortho << n, 0, 0, 0,
0, n, 0, 0,
0, 0, n + f, -n * f,
0, 0, 1, 0;

persp = scaleOrtho * translateOrtho * persp2ortho;
projection = persp * projection;

return projection;
}

Eigen::Matrix4f get_rotation(Vector3f axis, float angle)
{
Eigen::Matrix4f rotation = Eigen::Matrix4f::Identity();
Eigen::Matrix3f normalMat3f = Eigen::Matrix3f::Identity(), R, tmpMat;

float angleRadian = angle * MY_PI / 180.0f;

tmpMat << 0, -axis[2], axis[1],
axis[2], 0, -axis[0],
-axis[1], axis[0], 0;

R = std::cos(angleRadian) * normalMat3f + (1 - std::cos(angleRadian)) * axis * axis.transpose()
+ std::sin(angleRadian) * tmpMat;

rotation.block(0, 0, 3, 3) = R;
std::cout << rotation << std::endl;
return rotation;
}

运行结果

自己将点画在坐标系上,以及摆好相机位置后,看到的三角形应该是朝上方向的,之前由于没有注意n和f的符号,导致得到的是开口朝下的三角形,这是错误的。