0%

【Games 101】HomeWork 1:旋转与投影

HomeWork 1:旋转与投影

代码:

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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
/*
模型变换:
逐个元素地构建模型变换矩阵并返回该矩阵。
在此函数中,你只需要实现三维中绕 z 轴旋转的变换矩阵,而不用处理平移与缩放。

分析:
这个比较简单,提示也说了我们只需要绕着 z 轴旋转就行;
回顾一下公式:http://fjbq-blog.top/2023/12/30/GAMES%20101%20%E9%9A%8F%E7%AC%94/
*/
Eigen::Matrix4f get_model_matrix(float rotation_angle)
{
// 转换为弧度制
float rotation_angle_rad = rotation_angle / 180.0 * MY_PI;

// 创建一个 模型变换矩阵,默认初始化矩阵为单位矩阵
Eigen::Matrix4f model = Eigen::Matrix4f::Identity();

model << cos(rotation_angle_rad), -sin(rotation_angle_rad), 0, 0,
sin(rotation_angle_rad), cos(rotation_angle_rad), 0, 0,
0, 0, 1, 0,
0, 0, 0, 1;

/*
//绕x轴
model << 1, 0, 0, 0,
0, cos(angle), -sin(angle), 0,
0, sin(angle), cos(angle), 0,
0, 0, 0, 1;

//绕y轴(注意是反的哦)
model << cos(angle), 0, sin(angle), 0,
0, 1, 0, 0,
-sin(angle), 0, cos(angle), 0,
0, 0, 0, 1;
*/

return model;
}

/*
投影变换:
使用给定的参数逐个元素地构建透视投影矩阵并返回该矩阵。

分析:
这个感觉就比较复杂一点了...
首先根据前面的学习,我们知道 透视投影矩阵 = 正交投影矩阵 * 透视压缩矩阵(注意顺序哦)

其中这个 正交投影矩阵 里面用到的参数需要我们去求一下的...
*/
Eigen::Matrix4f get_projection_matrix(float eye_fov, float aspect_ratio, float zNear, float zFar)
{
/*
怎么感觉知乎大佬的代码怪怪的;
这个 zNear,zFar 给的是正数;
下面计算的都是用的负数,先转换一下?
*/
zNear = -zNear;
zFar = -zFar;

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

// 透视投影压缩矩阵
Eigen::Matrix4f M_persp;
M_persp << zNear, 0, 0, 0,
0, zNear, 0, 0,
0, 0, zNear + zFar, -zNear*zFar,
0, 0, 1, 0;

// 求一下正交投影矩阵要用到的参数
float alpha = 0.5 * (eye_fov / 180.0f * MY_PI); // 视野角度的一半
float yTop = -zNear * std::tan(alpha); // 因为这里的z给的是负数,所以加负号之后再转换
float yBottom = -yTop;
float xRight = yTop * aspect_ratio; // aspect_ratio 是 xy 的比例
float xLeft = -xRight;

Eigen::Matrix4f M_trans;
M_trans << 1, 0, 0, -(xLeft + xRight) / 2,
0, 1, 0, -(yTop + yBottom) / 2,
0, 0, 1, -(zNear + zFar) / 2,
0, 0, 0, 1;

Eigen::Matrix4f M_ortho;
M_ortho << 2 / (xRight - xLeft), 0, 0, 0,
0, 2 / (yTop - yBottom), 0, 0,
0, 0, 2 / (zNear - zFar), 0,
0, 0, 0, 1;

// 这个就是 正交投影矩阵
M_ortho = M_ortho * M_trans;

// 透视投影矩阵 = 正交投影矩阵 * 透视压缩矩阵(注意顺序哦)
projection = M_ortho * M_persp * projection;

return projection;
}

/*
进阶 模型变换矩阵:绕任意轴旋转
参考的是知乎大佬的:https://zhuanlan.zhihu.com/p/448904350
用 n 表示一个过原点的向量
*/
Eigen::Matrix4f get_random_model_matrix(Eigen::Vector3f n,float rotation_angle)
{
Eigen::Matrix4f model = Eigen::Matrix4f::Identity();
Eigen::Matrix3f I = Eigen::Matrix3f::Identity();

float angle = rotation_angle / 180.0f * MY_PI ;
float nx = n[0];
float ny = n[1];
float nz = n[2];

Eigen::Matrix3f N;
N << 0, -nz, ny,
nz, 0, -nx,
-ny, nx, 0;

// 公式
Eigen::Matrix3f R = std::cos(angle) * I + (1 - std::cos(angle)) * n * n.transpose() + std::sin(angle) * N;

model << R(0, 0), R(0, 1), R(0, 2), 0,
R(1, 0), R(1, 1), R(1, 2), 0,
R(2, 0), R(2, 1), R(2, 2), 0,
0, 0, 0, 1;

return model;
}

结果:

欢迎关注我的其它发布渠道