
简介一份面向GAMES101课程作业0的官方指南PDF重点解决图形学初学者在虚拟机环境搭建与作业框架使用上的常见问题。内容从Oracle VM VirtualBox安装、虚拟硬盘文件下载与配置到Guest Additions增强功能的安装逐步引导读者搭建统一作业环境同时介绍作业框架从主机导入虚拟机并推荐使用VSCode查看编辑、命令行编译运行。压缩包内共1个文件类型为PDF大小874KB轻量便携。已有433人学习浏览适合准备完成作业0或需要统一开发环境的课程学员。除操作步骤外PDF还补充了C头文件与函数体编写、编译错误与段错误等常见问题排查以及Eigen线性代数库的使用注意事项帮助读者避开典型坑点顺利进入后续图形学作业。1. 拿到 GAMES101 作业0先别怕这其实是一份图形学入门热身第一次听说 GAMES101 的人多半是在找图形学入门资料的时候撞见它的。而当你终于打开课程页面第一个跳出来的不是炫酷的渲染效果而是一份叫做作业0的PDF通篇是虚拟机、Ubuntu、cmake、Eigen还没开始学图形学先被环境配置吓一跳。别慌这恰恰是这门课最友好的一步。作业0不要求你做任何图形学算法它只做三件事让你把虚拟机环境跑起来、编译运行一个最小的 C 程序、顺便解一道旋转加平移的小题。本篇文章就把整份作业0从头到尾讲透——每一步该点什么、每行代码在干什么、报错怎么处理都按零基础能跟上的节奏来。适合人群想学图形学、但被环境配置和 C 吓得不敢动手的新手。2. 为什么图形学第一课要折腾虚拟机统一环境才是真正的目的先说实话我第一次看到请使用虚拟机完成作业这句话时心里是拒绝的。明明自己电脑用得好好的为什么非要再装一个 Ubuntu后来才知道这不是课程故意刁难你而是图形学这个方向的环境依赖实在太容易出问题。图形学程序要依赖一大堆库比如后面作业里会频繁用到的 Eigen 线性代数库、OpenCV、OpenGL 之类的工具。每个人的操作系统、编译器版本、库的安装路径稍有不同同一个代码就可能在你电脑上跑得好好的在他电脑上报一堆错。课程直接给你一个装好一切的 Ubuntu 虚拟机等于把千人千面的环境问题一次消灭掉。你要做的不是自己从零配环境而是把别人配好的环境跑起来。2.1 虚拟机不是玄学它就像一台随时可以重来的备用电脑你可以把虚拟机理解成一台装在你电脑里的假电脑。它有自己的操作系统这份作业里是 Ubuntu 18.04有自己的桌面、文件系统、终端甚至有自己的开机密码。你在里面干什么都不会影响到宿主机——也就是你真实的 Windows 或 Mac 系统。这份作业的精髓在于课程提供的是一个虚拟硬盘文件扩展名是 .vdi它就像这台假电脑的硬盘。里面已经装好了 Ubuntu 系统、VSCode 编辑器、cmake、Eigen 库连环境变量都配好了。你拿到这个文件用虚拟机软件把它挂载起来就能直接开机进入一个配置好的 Linux 系统。这比自己装 Ubuntu、再手动装一堆图形学依赖要省事一百倍也几乎不会翻车。2.2 跟着走一遍在 VirtualBox 里创建你的第一台虚拟机虚拟机软件这里用的是 Oracle VM VirtualBox免费且跨平台。安装软件这一步没什么可讲的去官网下对应系统的安装包一路下一步就行。需要注意的一点Windows 用户下载 .exeMac 用户下载 .dmgLinux 用户看自己发行版的对应说明。版本号不用纠结课程文档里提到的 6.1.4 能用官网更新的稳定版也能用。接下来是下载虚拟硬盘文件。课程提供的网盘链接和密码在作业文档首页下载完你会得到一个压缩包解压后就是那个 .vdi 文件。这里有个小坑文件名里带空格和括号比如GAMES101_Ubuntu 18.04.2 (64bit).vdi解压之后最好把它放到一个路径简单、没有中文的文件夹里后面选文件时不容易找不到。然后打开 VirtualBox点新建按下面的参数配置名称随便起比如 myGraphics101类型Linux版本Ubuntu 64-bit内存大小建议 2GB课程文档特别强调这个值虚拟硬盘选择使用已有的虚拟硬盘文件然后选中你解压好的 .vdi 文件最后点创建虚拟机会出现在左侧列表里。选中它点顶部的启动等系统进入桌面后输入登录密码即可。密码在课程文档里有是一串固定的字符串注意区分大小写特别是第一个字母是大写的 i很容易被看成小写 L输错了系统会提示密码错误。提示如果密码怎么输都不对先去确认是不是把 I大写 i和 l小写 L看混了。这是新手最容易犯的视觉错误。2.3 安装增强功能让鼠标和文件传输不再别扭刚启动的 Ubuntu 虚拟机有个很别扭的状态鼠标被锁在虚拟机窗口里按右边 Ctrl 键才能释放回来窗口也不会自适应分辨率文件也没办法直接拖进去。这一切的解决办法是安装 Guest Additions——你可以把它理解成官方出的驱动增强包装了它虚拟机才和宿主机配合得顺畅。安装方法很简单进入 Ubuntu 系统后在虚拟机窗口顶部的菜单栏里点设备→安装增强功能系统会自动挂载一个光盘镜像按提示运行里面的安装脚本完成后重启虚拟机即可。如果上面这个方法失败了比如点了之后没反应或者提示找不到光盘可以打开终端快捷键 CtrlAltT手动执行下面这几行命令sudo mkdir -p /media/cdrom # 创建一个挂载目录-p 表示目录已存在也不报错 sudo mount -t auto /dev/cdrom /media/cdrom/ # 把虚拟光驱挂载到这个目录 cd /media/cdrom/ # 进入光驱目录 sudo sh VBoxLinuxAdditions.run # 运行增强功能的安装脚本命令执行完重启虚拟机增强功能就生效了。重启之后记得再做一件事在设备菜单里把拖放设置为双向。这样你后面从宿主机下载的作业框架直接拖进虚拟机窗口就能拷贝进去不用再折腾 U 盘或共享文件夹。这一步做完你的虚拟机环境就真正可用了。接下来可以打开 VSCode 开始写代码。3. 先在虚拟机里跑通一个 C 样例Eigen 和 cmake 没有想象中难环境准备好了下一步是把课程提供的作业框架跑起来。作业框架是下载虚拟硬盘时一起提供的文件包你在宿主机上把它解压拖进虚拟机里然后用 Ubuntu 里自带的 VSCode 打开。打开方式很多最省事的方式是右键点击解压出来的文件夹选择使用其他应用打开然后选 Visual Studio Code或者在 VSCode 里点 File → Open Folder选中那个文件夹。这一步不要跳过。哪怕你觉得自己已经会 C 了也要亲手编译运行一遍样例程序。因为作业0的真正目的不是考算法而是让你熟悉一条完整的工作流写代码 → 编译 → 运行 → 看结果。这条流程后面每一份作业都要用现在跑通它后面你就专心调逻辑不用再跟环境搏斗。3.1 先读懂样例程序头文件、主函数和那个弧度制的陷阱打开样例程序 main.cpp你会发现它很短大约十几行。第一次看 C 程序的人不用害怕我们一行一行拆开看。#include cmath // 数学函数库sqrt、sin、cos、acos 都在这 #include iostream // 输入输出库std::cout 在这 int main() { // main 是程序入口程序从这里开始执行 float a 1.0, b 2.0; std::cout a std::endl; // 输出 1 std::cout a / b std::endl; // 输出 0.5 std::cout std::sqrt(a) std::endl; // sqrt(1) 1 std::cout std::acos(-1) std::endl; // acos(-1) 是圆周率 π std::cout std::sin(30.0 / 180.0 * acos(-1)) std::endl; // sin(30°) 0.5 return 0; // 返回 0 表示程序正常结束 }#include的作用是引入别人写好的模块不用自己造轮子。std::cout是往屏幕上输出内容的命令std::endl是换行。float定义了一个单精度浮点数变量a / b就是普通的除法。这些都属于 C 基础知识你不需要一下子全记住见到能猜个大概就行写作业时会反复遇到。最后一行是重点std::sin(30.0 / 180.0 * acos(-1))看起来复杂其实就是在算 sin(30°) 的值。课程故意在这里埋了个提醒——C 的三角函数用的是弧度制不是角度制。30.0 / 180.0 * acos(-1)是把 30 度换算成弧度的标准写法因为 180 度 π 弧度。如果你图省事直接写 sin(30.0)程序会把 30 当作弧度来算结果约等于 -0.988非常离谱。这个坑在作业0里不致命但后面做旋转矩阵时角度和弧度写错会让整个图像变形那时候再发现就晚了。3.2 在终端里编译运行mkdir、cmake、make 究竟是什么看懂代码之后来把它跑起来。在 VSCode 里打开终端菜单栏 Terminal → New Terminal确保当前路径停在 main.cpp 所在的文件夹。然后依次输入下面这些命令mkdir build # 新建一个叫 build 的文件夹 cd build # 进入 build 文件夹 cmake .. # 让 cmake 去上一级目录读取 CMakeLists.txt生成编译配置 make # 根据配置编译代码生成可执行文件 ./Transformation # 运行生成出来的程序./ 表示当前目录下这一步的操作顺序是固定的请先别改。它的逻辑是这样的build文件夹专门用来放编译产生的中间文件不污染你的源码目录cmake ..里的..表示上一级目录因为 CMakeLists.txt 在 build 的上一级make才是真正执行编译的程序最后./开头是因为 Linux 默认不会在当前目录找可执行文件需要显式告诉它路径。如果一切顺利终端里会依次输出那 5 行数字。如果报错记住一个原则看报错信息永远先看第一行。编译器会告诉你在哪个文件哪一行出了什么问题照着改就行。比较常见的错误我会在第 4 章的避坑部分集中讲这里先不展开。还有一个关键文件你可能注意到了CMakeLists.txt。它就是编译说明书告诉 cmake 这个项目要生成什么名字的可执行文件、要用哪些代码。比如里面会有这样一行add_executable(Transformation main.cpp)这一行定义了可执行文件叫 Transformation。你想让编译产物换个名字改这一行就行想在作业1里加新的源文件也要在这个文件里加一行。只有改了 CMakeLists.txt才需要重新执行cmake ..如果只改了代码直接用make重新编译就够了。3.3 认识 Eigen向量和矩阵就是图形学的算盘样例程序里还有一部分是 Eigen 的使用示例。Eigen 是 C 的一个线性代数库图形学里几乎所有东西——点的位置、旋转、缩放、投影——本质上都是在做向量和矩阵的运算。手写矩阵运算容易错Eigen 把这些操作封装成简单的类和方法你直接调用就行。看这段代码#include eigen3/Eigen/Core // Eigen 的核心模块向量和矩阵都在这 #include iostream int main() { // 定义三维向量 v (1, 2, 3)w (1, 0, 0) Eigen::Vector3f v(1.0f, 2.0f, 3.0f); Eigen::Vector3f w(1.0f, 0.0f, 0.0f); std::cout v w std::endl; // 向量加法每个分量分别相加 std::cout v * 3.0f std::endl; // 数乘每个分量都乘以 3 // 定义 3x3 矩阵用逗号按行填入元素 Eigen::Matrix3f i; i 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0; std::cout i std::endl; // 输出整个矩阵 std::cout i * v std::endl; // 矩阵乘向量得到一个新的三维向量 return 0; }Eigen::Vector3f表示三个 float 组成的向量Eigen::Matrix3f表示3 行 3 列的 float 矩阵。你可能注意到头文件名是eigen3/Eigen/Core多了一层eigen3目录这是 Ubuntu 系统里 Eigen 的安装路径决定的后面写代码照抄这个头文件就行不要自己改成Eigen/Core否则编译会报找不到文件。这段代码里的i 是 Eigen 特有的初始化方式把 9 个数字按行填进矩阵。不用急着理解它的底层实现你只需要知道按行填这个行为就够了。后面作业里大量会出现定义矩阵 → 填数字 → 做运算的套路多写几次自然就熟了。4. 作业0正题与避坑指南用齐次坐标算出旋转加平移的答案环境跑通了C 和 Eigen 的基本用法见过了现在来看作业0真正的算法题。题目是这样的给定一个点 P (2, 1)绕原点先逆时针旋转 45°再平移 (1, 2)计算出变换后点的坐标而且明确要求用齐次坐标计算。这道题在图形学里非常典型。图形学本质上是研究一堆点怎么在空间里变换的学科旋转、平移、缩放都是对点做运算。作业0的题虽然只有 2 个步骤但它把图形学变换最核心的两块——旋转矩阵和平移矩阵——都覆盖了。把这一题做明白作业1 里做三角形旋转、后续做相机变换理解起来都会顺畅很多。4.1 先搞懂齐次坐标为什么一个点要写成三个数字在齐次坐标里二维平面上的点 (x, y) 会被写成 (x, y, 1)多出来一个固定的 1。你可能会问这不是多此一举吗答案是不多。因为平移这件事用普通的 2×2 矩阵根本表达不了。你可以试一下任何 2×2 矩阵乘一个二维向量结果的每个分量都是原分量的线性组合常数项加不进去。而平移需要的是x 加上一个常数、y 加上一个常数。为了解决这个问题图形学引入了齐次坐标把点升到三维用一个 3×3 矩阵去作用它。这个多出来的第三维平时不起眼但恰恰让平移变成矩阵乘法成为可能。对应这道题我们要构造两个 3×3 矩阵。绕原点逆时针旋转 45° 的旋转矩阵 R 长这样R [ cos45° -sin45° 0 ] [ sin45° cos45° 0 ] [ 0 0 1 ]向右平移 (1, 2) 的平移矩阵 T 长这样T [ 1 0 1 ] [ 0 1 2 ] [ 0 0 1 ]注意先旋转再平移的顺序变换是从右往左读的T * R * p表示先让 R 作用在 p 上再让 T 作用在结果上。如果写反成R * T * p含义就变成了先平移再旋转结果完全不同。顺序搞错是图形学里最常见的错误之一没有例外记住这个规则矩阵越靠右越先执行。4.2 写出作业0的 main.cpp矩阵怎么定义、乘法怎么写有了矩阵代码就顺理成章了。打开 VSCode把 main.cpp 改成下面这样#include eigen3/Eigen/Core #include iostream #include cmath int main() { // 点 P (2, 1)用齐次坐标表示成三维向量 (2, 1, 1) Eigen::Vector3f p(2.0f, 1.0f, 1.0f); // 45 度转成弧度C 的三角函数全部使用弧度制 float angle 45.0f / 180.0f * acos(-1.0f); // 旋转矩阵 R绕原点逆时针旋转 45 度 Eigen::Matrix3f R; R cos(angle), -sin(angle), 0.0f, sin(angle), cos(angle), 0.0f, 0.0f, 0.0f, 1.0f; // 平移矩阵 Tx 方向平移 1y 方向平移 2 Eigen::Matrix3f T; T 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 2.0f, 0.0f, 0.0f, 1.0f; // 先旋转再平移所以矩阵从右往左读T * R * p Eigen::Vector3f result T * R * p; // 输出结果前两个分量就是变换后的 x 和 y std::cout result std::endl; return 0; }这里有几处细节要说明。acos(-1.0f)算出来的是 π用它来做角度到弧度的换算比自己手写 3.14159 更精确。Eigen::Matrix3f R;定义之后没有默认值必须用把所有 9 个元素都填满漏填一个编译时不一定报错但运行结果会莫名其妙这是 Eigen 新手很容易踩的雷。Eigen::Vector3f result T * R * p;这行是整个程序的核心。T * R * p是一个矩阵乘一个矩阵、再乘一个向量Eigen 会按照数学规则算出结果。这个结果向量有三个分量前两个是变换后点的 x 和 y 坐标第三个分量会是 1代表它还是一个齐次坐标表示。4.3 编译运行并检查结果输出什么样才算对代码写完保存回到终端执行编译四连mkdir build cd build cmake .. make ./Transformation如果一切正常你会看到终端输出一个三维向量大概是这样的1.70711 4.12132 1这个结果对吗我们快速手动验算一下。cos45° 和 sin45° 都等于 √2/2 ≈ 0.7071。先算旋转R * (2, 1, 1) 的 x 分量是 2×0.7071 − 1×0.7071 ≈ 0.7071y 分量是 2×0.7071 1×0.7071 ≈ 2.1213。再算平移x 加 1 得 1.7071y 加 2 得 4.1213。和程序输出一致说明代码写对了。这里推荐你做一个动作把./Transformation的输出和手算结果对照一下。作业0 不评分提交的目的只是走通流程但如果你连结果对不对都没验证过后面作业出问题时会很难定位——到底是算法错了还是代码写错了还是环境有问题。4.4 新手最容易踩的 5 个坑现象、原因、解决以下 5 个坑是我见过和经历过最多的每一条都按现象 → 原因 → 解决的顺序说明你遇到时直接对照排查。坑 1mkdir build提示File exists。现象命令执行失败提示 build 文件夹已经存在。原因之前编译过一次或者误删了 build 里的部分文件导致残留。解决先执行rm -rf build删掉旧文件夹再重新mkdir build。注意rm -rf很危险删除前务必确认当前路径就是项目目录不要在根目录或家目录乱敲。坑 2cmake ..报错说找不到 CMakeLists.txt。现象cmake 提示CMakeLists.txt: No such file or directory。原因你所在的位置不是 build 文件夹或者 build 建在了别的地方。解决用pwd查看当前路径用ls查看当前目录内容确认 main.cpp 和 CMakeLists.txt 在上一级目录。规范的做法是永远在 build 文件夹里执行cmake ..不要把 build 挪地方。坑 3make报undefined reference to xxx。现象编译过程中出现一串带undefined reference的错误。原因这不是 C 语法错误而是链接错误——代码里用了某个函数或库但 CMakeLists.txt 没有把它链进来。解决打开 CMakeLists.txt检查有没有target_link_libraries这一行确认需要链接的模块写进去了。Eigen 是头文件库一般只需要target_include_directories指向/usr/include/eigen3。坑 4编译通过运行时报Segmentation fault。现象程序编译没问题一运行就崩终端提示Segmentation fault (core dumped)。原因段错误通常是数组越界、访问了空指针、或者栈空间开得过大。解决先检查代码里有没有下标越界比如访问了 i[10] 而矩阵只有 3 个元素。再检查定义的大数组是不是放在了main函数内部超大数组应该声明为全局变量或改用动态分配。坑 5把文件拖进虚拟机没有反应。现象拖拽文件时鼠标变成禁止符号或者文件根本没出现在虚拟机里。原因Guest Additions 没装成功或者拖放功能没有设置为双向。解决重启虚拟机确认设备菜单里的拖放是双向再点一次安装增强功能等待安装完成。如果还是不生效回到 2.3 节的命令行方式手动安装一次。5. 作业0交完之后怎么学给零基础的三步图形学入门路径作业0 提交之后很多人的第一反应是终于结束了可以松口气。但其实这是整个课程里最轻松的一次作业趁着流程还热乎有件小事值得做把角度从 45° 改成其他值比如 90°重新编译运行看看结果怎么变。再把平移 (1, 2) 改成 (-1, 0)观察坐标变化。这个小小的实验能帮你真正理解矩阵参数变了点的位置就变了这层直觉比死记矩阵公式有用得多。接下来如果想继续往图形学走我的建议是三步走。第一步补 C 基础不需要啃完整个语法重点看函数、类、头文件、编译报错这几块够你读作业框架就行。第二步把线性代数的几何意义捡起来——向量点积、叉积、矩阵乘法的几何含义这些是图形学的地基。第三步趁热做作业1那是第一次真正接触三角形光栅化你会发现作业0里学的 cmake 流程和 Eigen 用法全部用得上到时候你会感谢自己当初没有跳过作业0。从那次之后我每次在虚拟机里写图形学相关的代码都强制自己走一遍固定流程先mkdir build建好编译目录写完代码先保存再编译报错了只看第一行错误信息运行结果先和手算对照再继续调算法。这个习惯帮我避开过很多次环境问题和技术问题混在一起的灾难现场毕竟图形学越到后面代码越复杂把环境稳定住才有余力去调渲染算法。希望帮到你。本文还有配套的精品资源点击获取