EasyShader——重新定义变换矩阵
4.0 前言
- 本篇是在重心坐标与深度检测成功绘制了前后关系正常的苹果图像,和后一节也就是本次图形学基础课实践部分的最终章节——漫反射材质导入的起承转合章节。本章我们将重构我们的变换代码,主要涉及一下几个部分
- geometry 类
- main.cpp
- 我们将实际将矩阵应用在我们的光栅化渲染器中,最后实现效果,为后续进阶的可变换视角的渲染器版本做铺垫。
4.1 Geometry类
- 首先是geometry类,我们对其进行了简单的重构,增加了Matrix类的定义,以及方法实现。相关的代码你可以在我们的库中找到,记住要找到矩阵分支~。
- 我们来看矩阵类的实现。
- 首先我们定义了一个数组,和两个int类型的值分别代表行和列。接着我们定义了基本的初始化方法以及一些基本的运算,如矩阵的乘法,矩阵的转置,逆阵等。
1 | class Matrix { |
- 我们在cpp中实现它们。
- 首先是最基本的两个内联函数,这两个函数只返回其本身的值。
1 | int Matrix::nrows() { |
- 接着,是一个初始化单位阵的函数identity,返回一个单位阵
1 | Matrix Matrix::identity(int dimensions) { |
- 随后,是一个计算符【】,返回矩阵第i 列的值。
1 | std::vector<float>& Matrix::operator[](const int i) { |
- 接着是乘法,我们只需要取每一行每一列数乘即可
1 | Matrix Matrix::operator*(const Matrix& a) { |
- 然后是转置,我们只需要新实例化出一个矩阵,并反向填入目标矩阵的值即可
1 | Matrix Matrix::transpose() { |
- 最后是最为麻烦的逆阵,在这里,我们应用了教科书上的求逆阵方式,也就是所谓的高斯消元法,通过增加一个单位阵并将原矩阵化为最简阶梯形矩阵的方式,得到逆阵。
- 详细代码你可以在我的库里找到~。
4.2 Main
- 现在,我们需要根据我们处理好的矩阵,来对我们的主函数文件进行重构。
- 但首先,我们需要先回顾一下之前是如何处理相关内容的。回顾先前的代码,我们法线,之前我们定义了一个直接将世界空间坐标映射到视口坐标的Worldtoscreen方法。
1 | Vec3f world2screen(Vec3f v) { |
- 并没有中间的裁剪和投影阶段。这很类似正交投影的方法,不过我们希望其能够移动,也就是能有透视
- 因此我们需要实现一系列新方法。
- 首先是两个基础的转换函数。其作用在于将矩阵形式和向量形式相互转换,在后续进行矩阵和向量混合运算时起到关键作用。
- 在这里,我们强调一点,实际上矩阵也就是一个二维数组,向量则是一个一维数组,计算机中存储二维数组的形式同样是线性排布的。
4.2.1
- 以下是两个方法的代码
1 | Vec3f m2v(Matrix m) {//转换函数,将矩阵形式转换为向量形式。 |
- 定义完这两个基础方法后,下一步,我们就需要定义两个重要的转换操作,一个是视图变换矩阵一个是透视投影矩阵。
4.3 视图变换与透视投影变换
- 首先是外部的视图变换,教程中将这一步与下一步合并,形成了新的视图变换矩阵。
1 | Matrix viewport(int x, int y, int w, int h) {//视口+正交变换 |
4.4 main函数中的变化
- 在main函数中,我们首先初始化了一个透视矩阵,随后调用了先前写好的视图变化矩阵方法,得到了一个视图变化矩阵,随后,我们余弦设定了相机的位置朝向,并以此初始化了透视矩阵中第四行第三列的值。
1 | Vec3f camera(0,0,-1); |
- 接着,我们需要在绘制模型时做一些改动,回归我们最开始绘制的方法,我们需要两个坐标,分别是屏幕以及世界坐标,之后,我们就可以用矩阵的方式得到屏幕坐标,相比之前更加方便了。
1 | Vec3i screen_coords[3]; |
- 关于矩阵部分的设置,基本上就到此结束了,接下来我们就可以正式进入对于模型加载贴图并绘制的部分了。我们需要修改Model头文件,添加uv坐标以及导入图片纹理的方法。
参考资料
- 计算机图形学入门——3D渲染指南
- https://github.com/ssloy/tinyrenderer
- 我的项目地址:
- https://github.com/Pleasant233/EasyRender
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Pleasant233!