GAMES101学习记录
GAMES101学习记录
本博客用于记录学习GAMES101时碰到的问题与记录
GAMES101的作业实现也会记录在此
同时,完成作业的过程碰到的问题与解决方案也会记录在此,包括但不限于环境配置、库的基本使用、稀奇古怪的bug
Assignment-0
此次作业是配置环境相关内容
由于我在做NJU的icsPA时已经装好了一个Ubuntu的虚拟机,因此这一系列作业都将使用Ubuntu虚拟机完成
下载安装VS Code
用火狐进入VS
Code官网,选择.deb
文件进行下载,默认应该保存在~/Downloads/
目录下
进入对应目录,运行sudo dpkg -i code_1.89.1-1715060508_amd64.deb
这里code_1.89.1-1715060508_amd64.deb
是刚下载的.deb
文件,不同版本名字不一样,记得替换
配置VS Code
还是跟Windows上的配置一样
设置字体为Consolas(Linux默认这个太难看了),参考链接将 Linux 上的 VSCode 改为 Consolas 字体
下载Consolas字体的具体执行过程如下:
1
2
3
4
5
6
7 >wget https://down.gloriousdays.pw/Fonts/Consolas.zip
>unzip Consolas.zip
>sudo mkdir -p /usr/share/fonts/consolas
>sudo cp consola*.ttf /usr/share/fonts/consolas/
>sudo chmod 644 /usr/share/fonts/consolas/consola*.ttf
>cd /usr/share/fonts/consolas
>sudo mkfontscale && sudo mkfontdir && sudo fc-cache -fv
再设置中文字体为微软雅黑,这个字体可以从Windows系统里偷过来,不过这个字体后缀名是.ttc
而不是常见的.ttf
:
.ttf
和.ttc
都是字体文件的格式,但它们之间有一些区别:
.ttf
(TrueType Font):这是由Apple和Microsoft共同推出的一种字体文件格式。每个.ttf
文件只包含一种字形。凡是支持矢量字体的平台,基本都支持.ttf
格式字体。.ttc
(TrueType Collection):这是Microsoft开发的一种新的字体格式标准。.ttc
文件可以在同一文件结构中包含多个字体,以便更有效地共享轮廓数据,缩减字体文件大小。TTC档会含超过一种字型,例如繁体 Windows 的Ming.ttc
就包含细明体及新细明体两种字型 (两款字型不同处只是英文固定间距),而 TTF 就只会含一种字型字体文件后缀。TTC是几个TTF合成的字库,安装后字体列表中会看到两个以上的字体。所以,你看到的微软雅黑字体文件后缀是
.ttc
,是因为它包含了多种字形。
把微软雅黑下载到Download目录下后,再执行与上文几乎相同的操作:
1 | sudo mkdir -p /usr/share/fonts/msyh |
字体安装完后,直接在VS Code的设置里搜索“Font
Family”,将'Consolas', 'Microsoft YaHei', monospace
写入,就完成了这两个字体的设置(还得是visual
studio的字体配置,真的好看又优雅,Ubuntu自带的字体太难绷了)
在设置里选上"Format on Save",即在保存时自动排版
安装C++拓展
安装Code Runner插件,并设置"Code-runner: Run In Terminal",即在终端里显示运行结果
安装Eigen
库
Eigen是本课程使用的线性代数运算库
直接运行sudo apt install libeigen3-dev
即可
Eigen
库基本用法
这里是Eigen库的官方文档
头文件
首先是头文件#include <eigen3/Eigen/Dense>
Eigen库的基础使用,只需要用到Eigen/Dense
这个文件,官方文档的解释是:
#include <Eigen/Dense>
Includes Core, Geometry, LU, Cholesky, SVD, QR, and Eigenvalues header files
即<Eigen/Dense>
包含了全部基本运算
因为我是Ubuntu系统,安装的是libeigen3-dev
,因此需要在/usr/include/eigen3
目录下找到Eigen
目录
矩阵
1 |
|
输出结果为
1 | 3 -1 |
由此可见,MatrixXd
是任意维度的矩阵(由倒数第二个字符X
表示任意维度,任意指初始化时决定维度),其中每个条目都是双精度的浮点数(由倒数第一个字符d
表示double
)
同理,MatrixXi
为任意维度的int
矩阵
同时,如果不初始化数值,默认是“未定义”的,在我机子上结果是0
问了bing,如果想生成全零矩阵怎么做:
如果你想创建一个所有元素都为0的矩阵,你可以使用
Zero
函数例如:
1 >Eigen::MatrixXd m = Eigen::MatrixXd::Zero(3, 3); // 创建一个3x3的全零矩阵
矩阵要用(i,j)
运算符来访问第i
行第j
列元素
向量
1 |
|
输出为:
1 | m = |
MatrixXd::Random(3, 3)
这个函数生成的是一个3x3矩阵,随机值在-1
和1
之间
MatrixXd::Constant(3, 3, 1.2)
这个函数,生成的是一个3x3矩阵,每一个元素都为双精度浮点数1.2
(因此上文中创建一个所有元素都为0的矩阵也可以用这个函数)
根据输出结果可见,向量默认为列向量
如果想实现行向量,就用RowVectorXd
实现
总结
简单使用方法目前介绍到此为止,后续实验中如果碰到新的内容会在对应位置记录,现阶段总结如下:
一般都是先初始化矩阵或向量,再用<<
运算符赋值,如
1 | MatrixXf m(3, 3); |
初始化时可以用对应的函数,如用MatrixXd
初始化的矩阵m
,可以用MatrixXd
对应的函数初始化,如
1 | MatrixXf m = MatrixXf::Zero(3, 3); |
矩阵和向量可以直接用<<
运算符输出到输出流
矩阵和向量都要用()
运算符访问元素
作业代码
代码如下
1 |
|
注意double angle = (double)45 / 180 * acos(-1);
这一句,如果45
不加(double)
就要写成45.0
,不然会被识别成int
的45,除法结果为0,不符预期
Assignment-1
unzip
中文乱码问题
这次作业给了代码框架,于是就需要在Ubuntu下载这次作业
运行如下指令:
1 | wget http://games-cn.org/wp-content/uploads/2020/02/Assignment1.zip |
就能获得这个zip
压缩包,放到对应位置后解压:
1 | unzip Assignment1.zip |
但是发现输出和最后解压的结果是乱码,我应该安装了中文,只是环境用的英文环境,挺奇怪的
经过一系列查找资料后,发现问题所在:unzip
命令没有指定字符集,于是执行unzip -O CP936 Assignment1.zip
就能正常实现了
但是如果每次unzip
都要加这个那就太麻烦了,于是直接给写进环境变量里:
在环境变量中,指定
unzip
参数,总是以指定的字符集显示和解压文件
/etc/environment
中加入2行
1
2
3 >UNZIP="-O CP936"
>ZIPINFO="-O CP936"
添加完需要重启,才能起效
Ubuntu 22.04中文拼音输入法
我没想到这个还有点烦人
最后发现是没有重启的原因,有点难绷
参考Ubuntu 22.04 Chinese (simplified) pinyin input support
Ubuntu中切换输入法快捷键:win + 空格
Ubuntu上OpenCV
安装
好啊,又折磨了一下午,终于把这个库装好了
比Windows的安装麻烦许多,中途还是踩了一些坑的,最大的坑就是opencv4.pc
这个文件
正确的安装过程
主要参考linux下编译安装opencv生成opencv.pc
首先安装
cmake
和所需依赖环境1
2
3sudo apt-get install cmake
sudo apt-get install build-essential libgtk2.0-dev libavcodec-dev libavformat-dev libjpeg-dev libswscale-dev libtiff5-dev
sudo apt-get install pkg-config然后去官网下载对应版本的Sources,我安装的版本为4.8.0
下载完了直接解压即可,
cd
进入对应目录,如/home/winkyspeed/Libs/opencv-4.8.0
在此目录下新建
build
文件夹,并且进入1
mkdir build && cd build
接下来用
cmake
命令进行配置1
sudo cmake -D CMAKE_BUILD_TYPE=Release -D OPENCV_GENERATE_PKGCONFIG=ON -D CMAKE_INSTALL_PREFIX=/usr/local ..
其中,
-D
用于定义变量,使用-D
选项来设置CMake的变量,这些变量会在CMake运行时被使用CMAKE_BUILD_TYPE=Release
指定构件类型为Release
版,类似于Windows里Visual Studio里选择Debug模式还是Release模式OPENCV_GENERATE_PKGCONFIG=ON
这个可太重要了,选了这个选项就代表少踩一个大坑,这个选项选上的时候,编译过程中会自动生成pkg-config
的配置文件,即opencv4.cp
CMAKE_INSTALL_PREFIX=/usr/local
指定编译结果安装到/usr/local
目录下,这也是默认的编译路径..
:最后还有两个点,指向当前目录的父目录,表示CMake会在父目录中查找CMakeLists.txt
文件进行编译,执行如下指令
1
sudo make -j8
指定多线程编译,会稍微快一点
这里需要编译一段时间,耐心等待即可
进行安装,执行如下指令
1
sudo make install
配置环境
用文本编辑器(如VS Code或vim)打开
/etc/ld.so.conf
,在文件最后一行添加:1
include /usr/local/lib
添加的这个路径就是OpenCV的
lib
库,即动态链接库添加完保存退出,再运行如下指令来更新缓存
1
sudo ldconfig
在Linux系统中,
/etc/ld.so.conf
文件记录了编译时使用的动态库的路径,也就是加载.so
库的路径。默认情况下,编译器只会使用/lib
和/usr/lib
这两个目录下的库文件。如果你的库文件安装在其他路径(比如/usr/local/lib
),那么你需要在/etc/ld.so.conf
文件中添加这个路径。当你在
/etc/ld.so.conf
文件中添加新的库路径后,你需要运行ldconfig
命令来更新动态链接库的缓存。用文本编辑器打开
/etc/bash.bashrc
,在文本末尾添加:1
2
3PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig
export PKG_CONFIG_PATH新添加的这个
PKG_CONFIG_PATH
环境变量指定了pkg-config
工具在指定目录下查找.pc
文件,这个文件包含了库的编译和链接信息pkg-config
的默认路径是:/usr/lib/pkgconfig/
和/usr/share/pkgconfig/
,这里我们新添加一个路径:/usr/local/lib/pkgconfig
因为
cmake
命令配置时OPENCV_GENERATE_PKGCONFIG=ON
这个命令,OpenCV在编译过程中自动生成了这个opencv4.pc
文件,如图因此,我们需要把这个路径加入
pkg-config
的查找路径,使之能查找到我们需要的opencv4.pc
添加完保存退出,再运行如下指令来更新缓存
1
source /etc/bash.bashrc
检验是否安装成功
终端输入如下指令
1
pkg-config opencv4 --modversion
有版本输出,说明安装成功
我经历的折磨
记录最开始未成功的解决方案,成功的解决方案是上文正确的安装过程
最折磨的一点就是opencv4.pc
这个文件,我最开始在编译的时候没选OPENCV_GENERATE_PKGCONFIG=ON
自动生成,而是在出错之后想着手动写入opencv.pc
,但因为库之间是有依赖关系的,所以如果顺序放错也会找不到,最好还是自动生成
主要参考ubuntu安装opencv的正确方法,但是最后那块会出现问题,具体什么问题下文会详细记录,因此又参考在Ubuntu18.04中安装OpenCV4.5这篇文章的部分内容(手动创建opencv.pc
及之后部分),部分解决方案参考opencv2在opencv4文件夹内
前面逻辑大体一致,跟着教程走直到最后pkg-config opencv --modversion
这一步,我发现报错了:
1 | Package opencv was not found in the pkg-config search path. |
可能是因为OpenCV在高版本就不自动生成.pc
文件了
看评论区有人提到了另一篇教程,手动创建opencv.pc
部分,又照着实现,勉强能在控制台输出版本号了,我就以为结束了,殊不知编译代码的时候根本找不到这些链接库,烦死了
然后我再去尝试跑最简单的CV库代码,读取一张图并显示出来,又出问题了:
我们需要包含的头文件<opencv.hpp>
在/usr/local/include/opencv4/opencv2/
目录下
但是正常写代码的时候一般都写#include <opencv2/opencv.hpp>
,而搜索的时候只会在/usr/local/include/
等目录中搜索,理所当然的搜索不到opencv2
目录下的opencv.hpp
文件,导致无法正常运行
我就去找了这样的一篇文章,用创建一个“软链接”的方法,在/usr/local/include/
目录中创建一个指向opencv2
目录的软链接
1 | sudo ln -s /usr/local/include/opencv4/opencv2 /usr/local/include/ |
这样在VS
Code中可以正确找到对应的头文件,我就以为问题解决了(但是并没有),不过这个步骤还是挺有用的
为了避免别人再犯一样的错误,我这里把自动生成的.pc
文件放在这里,如果想手动输入可以参考,但是可能会因为版本号对不上再导致新的问题,还是建议自动生成
1 | # Package Information for pkg-config |
我在知道能自动生成.pc
文件后直接去问bing解决措施:
我现在想重新设置cmake,多加一个
-D OPENCV_GENERATE_PKGCONFIG=ON
我该怎么做?重装OpenCV吗?
你不需要重新安装OpenCV,只需要重新配置并编译即可。你可以按照以下步骤操作:
- 首先,你需要清理之前的构建文件。在你的build目录下执行以下命令:
1 make clean
- 然后,你可以重新运行cmake命令,并添加
-D OPENCV_GENERATE_PKGCONFIG=ON
选项:
1 sudo cmake -D CMAKE_BUILD_TYPE=Release -D OPENCV_GENERATE_PKGCONFIG=ON -D CMAKE_INSTALL_PREFIX=/usr/local ..
- 最后,重新编译和安装OpenCV:
1
2 sudo make -j8
sudo make install完成以上步骤后,你应该可以在
/usr/local/lib/pkgconfig/
目录下找到opencv4.pc
文件了。
于是就安装成功了
这件事告诉我们,有时候走错了路或者选错了方向以后,是可以回头重新审视修改的,不需要为了证明在一个方向是错误的还是正确的而一条路走到黑,退后一步也许就会海阔天空
VS Code配置Code
Runner运行OpenCV
库
我是喜欢用Code Runner来跑代码的,如果喜欢手动编译也是可以的
配置这个还是比较容易的(前提是前文的OpenCV安装成功)
OpenCV安装成功的标志是:在终端运行如下指令
1 | pkg-config --cflags --libs opencv4 |
输出如下:
1 | winkyspeed@VMachine:~$ pkg-config --cflags --libs opencv4 |
就说明成功了
打开VS
Code的设置,选择工作区(比如GAMES101,工作区需要手动添加),搜索Code-runner:Executor Map
,点击Edit in settings.json
这样就会在工作区目录下创建一个.vscode
目录,下面就有一个settings.json
文件
把cpp
一行修改为如下内容:
1 | "cpp": "cd $dir && g++ -std=c++11 $fileName -o $fileNameWithoutExt `pkg-config --cflags --libs opencv4` && $dir$fileNameWithoutExt" |
就可以了
成功跑通最基础的代码,说明OpenCV库安装成功并且代码能够正常执行:
1 |
|
结果如下:

不得不说我选的图真好
本来没考虑那么多,想着选个石头门的全家福用来测试OpenCV库的,结果第一遍配置完成的时候代码却不能正常跑通
当时就给我整不会了,这可是最基本的代码啊,而且我为了装这个库已经花了一个下午的时间了
所以当我解决全部问题,终于跑出来这个结果时,看到了蛋糕上的おめでとう,就感觉这一切值得了(虽然桶子的脑袋只留下了一半)
VS Code找不到头文件
如果#include <opencv2/opencv.hpp>
这一行爆红了,应该是找不到头文件的问题
如果按照上文正确配置了,代码应该是能正常运行的,即编译器在编译时能找到文件,但是编辑器没找到文件
正常使用时需要包含的头文件<opencv.hpp>
在/usr/local/include/opencv4/opencv2/
目录下
搜索的时候只会在/usr/local/include/
等目录中搜索,理所当然的搜索不到opencv2
目录下的opencv.hpp
文件,导致无法正常运行
解决方法也很容易,有以下两种
软链接
我找到了这样一篇文章,用创建一个“软链接”的方法,在/usr/local/include/
目录中创建一个指向opencv2
目录的软链接
1 | sudo ln -s /usr/local/include/opencv4/opencv2 /usr/local/include/ |
这样在VS Code中可以正确找到对应的头文件
设置VS Code工作区
前文中也已经对这个工作区的Code
Runner进行自定义过了,因此也可以再自定义include
路径
打开VSCode的工作区设置(
.vscode/c_cpp_properties.json
文件),如果这个文件不存在,可以通过Ctrl+Shift+P
打开命令面板,然后输入C/C++: Edit Configurations (JSON)
来创建在
c_cpp_properties.json
文件中,找到includePath
字段,然后添加OpenCV头文件的路径,即/usr/local/include/opencv4
1
2
3
4"includePath": [
"${workspaceFolder}/**",
"/usr/local/include/opencv4"
],
这样,VSCode也可以找到opencv2
目录,进而找到文件
作业代码
还是比较容易
最终的算法是viewport * Ortho * Pers->Ortho * ModelView * 原始坐标
,依次左乘一系列矩阵得到最终的答案
基础实现
旋转矩阵:

按照旋转矩阵,得到绕XYZ三个轴旋转的结果如下
我在参数里多加了一个int axis
,默认赋值为0,指明绕Z, Y, X
哪个轴旋转
1 | // 绕XYZ三个轴旋转 |
再看投影矩阵函数
需要根据FOV和宽高比计算出对应大小的立方体,再进行相应计算
我这里是用水平FOV进行计算的
有一点需要注意:GAMES101课程中讲的zNear
和zFar
都是负数
但是主函数调用时代入参数为正数:r.set_projection(get_projection_matrix(45, 1, 0.1, 50));
因此,如果按课程内容进行运算时,就要乘-1
还有一点需要注意:计算对应坐标时,用到了zNear
的长度,故需要调用abs()
函数求绝对值,不然即使改了zNear
和zFar
都是负数以后,也仍然会出现倒三角的情况
代码如下:
1 | Eigen::Matrix4f get_projection_matrix(float eye_fov, float aspect_ratio, |
编译运行
第一次动手用cmake
编译自己的项目,因此记录
在main.cpp
同级目录下(即“代码框架”目录下)运行以下指令:
1 | mkdir build // 创建build文件夹用于保留工程文件 |
结果如下:

按A键三角形逆时针旋转,按D键三角形顺时针旋转
进阶实现——任意轴
这个也不是很难,不过需要注意“任意轴”是任意方向,并且过任意点
“任意轴”的方向可以用一个Vector3f
给定,“任意点”的位置同理
罗德里德斯旋转公式默认是绕过原点(0,0,0)
的轴旋转的
因此需要在旋转前把这个任意点移动到原点,再绕原点旋转,再把点移动回去,就能得到结果
具体做法是:Translate_back * Rotation * Translate
有一点需要注意:按照罗德里德斯旋转公式得到的结果是一个3x3
的矩阵,变换要考虑齐次坐标,即变成4x4
的矩阵
Rodrigues’ Rotation Formula 如下:

注意,罗德里德斯旋转公式的旋转轴要是一个单位向量,因此需要做正则化处理
1 | // 绕任意轴旋转任意角度 |
对应main
函数也需要做修改,把get_model_matrix(angle)
注释掉,换成刚刚写的新函数,并且前面指定“轴”和“任意点”的变量
1 | // 过任意轴, 指定Y正方向,过(0,0,-2) |
我指定了绕过(0,0,-2)
的,沿Y轴正方向的轴旋转,结果如下:

参考资料
将 Linux 上的 VSCode 改为 Consolas 字体