环境说明
- 作业下载地址:GAMES在线课程(现代计算机图形学入门)讨论区 › 作业1发布公告
- 课程观看地址:GAMES101-现代计算机图形学入门-闫令琪
- 平台:Windows11
- IDE:Visual Studio 2022 + VA番茄助手插件
- 第三方库:
作业说明
本次作业的任务是填写一个旋转矩阵和一个透视投影矩阵。给定三维下三个点 v0(2.0, 0.0, −2.0), v1(0.0, 2.0, −2.0), v2(−2.0, 0.0, −2.0), 你需要将这三个点的坐标变换为屏幕坐标并在屏幕上绘制出对应的线框三角形 (在代码框架中,我们已经提供了 draw_triangle 函数,所以你只需要去构建变换矩阵即可)。简而言之,我们需要进行模型、视图、投影、视口等变换来将三角形显示在屏幕上。在提供的代码框架中,我们留下了模型变换和投影变换的部分给你去完成。
作业讲解
第一个模型旋转矩阵没什么难点,正常套公式就行了
static double PI = acos(-1);
static double Ang2Rad = PI / 180.0;
static double Rad2Ang = 180.0 / PI;
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.
double rad = rotation_angle * Ang2Rad;
double costheta = std::cos(rad);
double sintheta = std::sin(rad);
model <<
costheta, -sintheta, 0, 0,
sintheta, costheta, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1;
return model;
}
难点在第二个函数,我发现很多人画出来的图都是倒着的,就是这部分矩阵出了一点小问题,这里稍微再复习一下公式
总共需要这三个矩阵,问题就出在规范化那里
在已经写好的代码中,我们可以看到传入的 n = 0.1
,f = 50
,这点很符合常识,离得近数值就小,离得远自然距离就远,但是我们使用的是右手坐标系,传入的这个数值其实是按照 z 轴反方向作为参考系来看,与我们实际的坐标体系相悖,在做 r - l
的时候其实是做 l - r
,因为坐标已经规范化,所以 r = -l
,这里可以等价替换
右边位移的矩阵,几个 r + l
,t + b
都可以直接写成 0
,这里再给出一个计算成像屏幕大小的公式,这里的 d
是 distance
的缩写,在这里就是 n
ok,万事俱备可以写代码了
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 persp2ortho;
persp2ortho <<
zNear, 0, 0, 0,
0, zNear, 0, 0,
0, 0, zNear + zFar, -zNear * zFar,
0, 0, 1, 0;
float RenderHeight = std::tan(eye_fov * Ang2Rad / 2) * zNear * 2;
float RenderWidth = RenderHeight * aspect_ratio;
Eigen::Matrix4f orthoa;
Eigen::Matrix4f orthob;
orthoa <<
-2 / RenderWidth, 0, 0, 0,
0, -2 / RenderHeight, 0, 0,
0, 0, 2 / (zNear - zFar), 0,
0, 0, 0, 1;
orthob <<
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, -(zFar + zNear) / 2,
0, 0, 0, 1;
// 这个矩阵类符号被重载过了,不需要加括号手动调整计算优先级,内部已经写好了算法
return orthoa * orthob * persp2ortho;
}