简介一份PDF文档对应GAMES101计算机图形学课程作业0的虚拟机使用指南适合选课学生、图形学初学者及需要搭建CG开发环境的入门者。资源共1个文件为纯PDF格式大小仅874KB可通过任意PDF阅读器查看便于离线对照操作。内容以作业0为线索系统梳理了虚拟机配置的完整流程包括Oracle VM VirtualBox安装、虚拟硬盘文件下载与解压、虚拟机内存分配与启动、Ubuntu系统登录、Guest Additions增强功能的图形界面与命令行两种安装方法以及作业框架从主机拖入虚拟机、使用Visual Studio Code编辑的具体操作。同时收录了C头文件、函数体、常见编译错误指南和Eigen库使用注意事项能帮助初学者避开环境配置中的常见坑点确保作业流程顺畅推进。当前已有433人学习下载适合作为该课程起步阶段的随身参考资料。1. GAMES101-作业0从这一页PDF开始不评分不代表能跳过GAMES101-作业0是整个图形学课程里最容易被轻视的一份PDF它不参与评分要求也简单到只是“把虚拟机跑起来提交一个编译通过的程序”。但恰恰是这一步把后面所有作业的编译方式、运行环境和代码习惯一次性定了型。拿到这份资源时我第一反应也是“这有什么好写的”直到看见群里隔三差五就有人问“为什么make报错”“为什么虚拟机拖不进文件”——这些都是作业0没走完留下的尾巴。这份PDF能解决的就是一件事让第一次接触Linux、cmake和Eigen的人在半小时内把环境跑通并拿到一个可提交的作业框架。适合刚进课程、以前只用Windows写代码以及想给后续图形学作业省下环境调试时间的同学。2. 虚拟机准备VirtualBox挂载Ubuntu 18.04虚拟硬盘的三个关键参数2.1 为什么要为一份入门作业专门搞虚拟机很多第一次看到作业0的同学会问直接在Windows上装Eigen、配编译器不行吗当然行但课程方选择虚拟机是有明确考虑的。图形学作业依赖的系统组件比普通C作业多不少——OpenGL头文件、Eigen库、cmake工具链、GLEW/GLFW这些第三方库在不同操作系统、不同版本下的安装方式完全不一样。你在一台Windows机器上配好的环境换个同学可能折腾半天都跑不起来而老师评分时也不可能去适配每个人的本机环境。虚拟硬盘文件相当于一个已经把上述所有依赖都预装好的Ubuntu 18.04系统。用VirtualBox挂载这个vdi文件后所有人的编译器版本、库路径、系统配置都是一致的。这种“环境统一”的价值在后面的作业里会体现得很明显作业2、作业3涉及光栅化和着色器框架里一堆CMake配置和OpenGL调用如果本地环境有偏差排查起来是灾难性的。我自己的习惯是凡是要给课程或合作项目用到的资源第一件事就是把干净环境跑通再做功能代码。2.2 下载虚拟硬盘与新建虚拟机的参数选择先把课程提供的虚拟硬盘文件下载下来文件名是GAMES101_Ubuntu 18.04.2(64bit).rar解压后得到一个.vdi文件。注意解压目录不要带中文后面挂载时能少一个变量。解压完打开VirtualBox点“新建”这时有几个参数值得说清楚参数填写值说明名称任意建议用GAMES101只是虚拟机标识不影响功能类型Linux对应Ubuntu系统版本Ubuntu-64bit必须与vdi镜像位数一致内存大小2048 MB低于1024 MB会明显卡顿硬盘使用已有的虚拟硬盘文件选择解压出的vdi文件这里最容易翻车的两个点一是版本选成32-bit启动时直接报“无法启动”之类的兼容性错误二是内存给太少进系统后风扇狂转、鼠标都拖不动。课程文档建议2GB我实测2GB以上都行但笔记本内存紧张时1.5GB也可以撑住再低就不建议了。类型和版本选错时VirtualBox会提示不匹配但提示比较隐晦容易误以为是虚拟硬盘损坏。点“创建”后不用急着改其他设置。选中虚拟机点“启动”进入Ubuntu桌面后系统会提示登录密码课程文档里写着Ilovegraphics注意区分大小写。第一次启动可能要等一段时间系统在做磁盘初始化属于正常现象。2.3 Guest Additions为什么装完系统第一件事是装它进入桌面后的第一件事不是打开VSCode而是安装Guest Additions增强功能。不装它虚拟机和主机之间不能拖放文件、剪贴板不共享、窗口分辨率也调不到合适的值——而这些正是后面传输作业框架要用的。图形界面安装方式很简单虚拟机窗口顶部菜单栏点击“设备”→“安装增强功能”Ubuntu会挂载一个虚拟光驱并弹出安装向导按流程走完重启虚拟机就生效。如果弹出窗口没出现或者安装过程中报错就切换到命令行方式补救sudo mkdir -p /media/cdrom sudo mount -t auto /dev/cdrom /media/cdrom/ cd /media/cdrom/ sudo sh VBoxLinuxAdditions.run这段命令的逻辑是先建立挂载点目录再把虚拟光驱设备挂载到该目录最后执行安装脚本。-p参数表示目录不存在时自动创建-t auto让系统自动识别光驱文件系统类型省去手动指定iso9660的麻烦。执行完脚本后重启虚拟机增强功能才算完全生效。提示如果VBoxLinuxAdditions.run执行时报缺少编译内核模块之类的错误先执行sudo apt update sudo apt upgrade更新系统包再重试很多情况是镜像里的内核版本和VirtualBox版本对不上。安装成功后“设备”菜单里的“拖放”选项会从灰色变成可点状态这一步是后面导入作业框架的前提。3. 编译链路拖放传文件、VSCode编辑、cmake与make的每一步3.1 开启双向拖放把作业框架送进虚拟机作业框架在本机上虚拟机在VirtualBox里两者之间传输文件不用U盘也不用配网络共享最省事的方式就是拖放。前提是上面装好的Guest Additions已经生效然后在虚拟机窗口顶部菜单栏选择“设备”→“拖放”→“双向”原因很简单单向模式只能从主机拖进虚拟机从虚拟机拖出来时会发呆双向直接省掉方向判断。拖放设好之后把包含main.cpp和CMakeLists.txt的作业框架文件夹直接从主机拖进Ubuntu桌面。如果拖进去没反应确认缓存盘路径和文件名是否包含中文一般把文件夹重命名成全英文就能解决。框架不用放在特定目录放桌面或home目录都行反正后面编译时用命令行定位。3.2 命令行编译mkdir、cd、cmake、make四步在做什么作业0最核心的编译流程就是四步命令但每一条都值得拆开看因为后续所有作业都会沿用这套方式。打开终端CtrlAltT先进入main.cpp所在目录然后依次执行mkdir build cd build cmake .. make第一行mkdir build创建了一个名为build的目录作用是把编译产生的中间文件、可执行文件和源码目录隔离开避免一堆.o文件和源码混在一起。这个习惯很重要后面的作业框架也默认使用这种方式不要图省事直接cmake .。第二行cd build进入刚创建的目录接下来所有编译动作都在build里进行。第三行cmake ..中的..指的是上一级目录cmake会在上一级目录寻找CMakeLists.txt并读取配置生成对应的Makefile这里如果手滑写成cmake .cmake会在build目录里找CMakeLists.txt通常找不到就报错。最后make根据生成的Makefile调用编译器真正把源码编译成可执行文件。编译完成后目录里会出现./Transformation这个文件这就是作业要求最终提交时包进去的可执行程序。如果直接运行它./Transformation终端会输出程序的计算结果后面章节会详解这个结果该怎么验证。注意可执行文件名不是自己随便写的它在CMakeLists.txt里有定义想改名的话要同时改CMakeLists和命令行里的调用保持两者一致。3.3 在VSCode里改代码头文件、函数体和Eigen虚拟机里预装了VSCode和Sublime推荐用VSCode因为打开目录后左侧文件树、终端面板和代码高亮都齐全。在VSCode里选择“File → Open Folder”定位到刚才拖进来的作业框架目录就可以开始编辑。main.cpp的骨架不长但三个去掉后会让人摸不着头脑的部分是头文件、主函数、Eigen库。下面是一段最简示例基本覆盖了作业0里会用到的最小集#include cmath #include iostream #include eigen3/Eigen/Core int main() { float a 1.0f, b 2.0f; std::cout a / b std::endl; std::cout std::sqrt(a) std::endl; std::cout std::acos(-1) std::endl; std::cout std::sin(30.0f / 180.0f * acos(-1)) std::endl; Eigen::Vector3f v(1.0f, 2.0f, 3.0f); Eigen::Vector3f w(1.0f, 0.0f, 0.0f); std::cout v w std::endl; return 0; }cmath提供sqrt、sin、acos这些数学函数iostream负责输入输出。#include eigen3/Eigen/Core是Eigen的头部引入注意路径里带着eigen3前缀这是因为Ubuntu下Eigen的头文件默认安装在/usr/include/eigen3目录里直接写Eigen/Core会找不到头文件。Vector3f定义了一个三维浮点向量v w做逐分量加法v * 3.0f做数乘这些在作业0里不直接用但作业1、作业2会频繁用到。另外注意std::sin(30.0f / 180.0f * acos(-1))这句acos(-1)返回的是圆周率30度先转弧度再参与计算。C的三角函数用的是弧度制作业里旋转45度也必须先做同样的转换这是最容易写错的地方。常见错误的速查如下报错或现象常见原因快速处理Compile Error语法、头文件路径错误看编译器定位的行号和列号优先查#include和分号undefined reference to xxx链接错误CMakeLists缺模块检查CMakeLists.txt中的target链接项Segmentation Fault数组越界、栈空间过大或矩阵维度不匹配查索引、查Eigen矩阵定义维度Bus Error成因与段错误类似常涉及内存对齐检查指针和未初始化数据Math Error除数为0或非法运算检查分母和数学函数参数4. 齐次坐标点(2,1)旋转45°再平移(1,2)的推导与矩阵顺序4.1 为什么作业非要你用齐次坐标作业0的题目看起来简单把点P(2,1)绕原点逆时针旋转45°再平移(1,2)算变换后的坐标。如果只用普通的2×2矩阵旋转可以写成矩阵乘法但平移不行——平移是“加一个常量”不是“乘以一个矩阵”。这导致旋转和平移没法用一种统一的表示去叠加每次都得“先乘矩阵、再加向量”代码写起来丑数学推导也绕。齐次坐标的做法是给二维点加一个分量变成(x, y, 1)的三维向量同时把变换写成3×3矩阵。这样旋转、平移全都变成矩阵乘法一连串变换可以预先乘成一个总矩阵再直接作用于点。这个“把多种变换统一成矩阵乘法”的思路是后续作业里模型变换、视图变换、投影变换的地基作业0要求用齐次坐标计算本质上不是故意绕远路而是在第一次作业里就把这个思维模型打进去。实际写代码时你会发现Eigen的Vector3f和Matrix3f刚好和齐次坐标的形式完全对应一行矩阵乘法就能完成整条变换链。4.2 先旋转再平移矩阵顺序是T * R * p先给出旋转矩阵和平移矩阵的齐次形式。绕原点逆时针旋转45°的矩阵是R [ cos45 -sin45 0 ] [ sin45 cos45 0 ] [ 0 0 1 ]平移(1,2)的矩阵是T [ 1 0 1 ] [ 0 1 2 ] [ 0 0 1 ]题目要求“先旋转再平移”在矩阵乘法里的顺序必须是从右往左读先作用于点的是旋转矩阵R再作用于旋转结果的是平移矩阵T整体表达式是M T * R最终坐标为M * p。写成代码就是T * R * p注意千万不能写成R * T * p否则含义会变成“先平移再旋转”结果完全不同。很多第一次接触结合变换的人会天然按阅读顺序从左写到右翻车都翻在这里。如果写反了会得到什么先平移(1,2)点(2,1)变(3,3)再旋转45°结果是(0, 4.2426)。而正确顺序的结果是(1.7071, 4.1213)两组坐标差异明显。Eigen里Matrix3f的*运算遵循数学上的矩阵乘法规则不满足交换律所以顺序错了编译器不会提醒你只有对照手算结果才能发现。4.3 手算一遍用1.7071和4.1213当自检基准作业0的评分虽然不严格但你自己得知道答案对不对。手动推导一遍点P(2,1)旋转45°cos45°和sin45°都等于√2/2约0.7071。旋转后的横坐标x 2 * cos45° - 1 * sin45° 2 * 0.7071 - 1 * 0.7071 0.7071旋转后的纵坐标y 2 * sin45° 1 * cos45° 2 * 0.7071 1 * 0.7071 2.1213这里需要注意符号逆时针旋转时用x*cos - y*sin计算横坐标x*sin y*cos计算纵坐标。如果顺时针公式里的正负号会反过来。旋转完再平移(1,2)最终x x 1 0.7071 1 1.7071 最终y y 2 2.1213 2 4.1213所以最终坐标是(1.7071, 4.1213)附近的值。程序跑完如果输出的小数点前三位接近这个数基本就对了。浮点运算会有极小的误差不必强求完全等于1.7071Eigen输出默认保留几位小数肉眼判断足够。后面的作业里这种“先手算一个基准值再看程序输出是否吻合”的习惯会成为排查问题的主要手段。5. 避坑排查虚拟机、CMake和Eigen的五个翻车点5.1 Guest Additions装不上拖放选项一直是灰色现象按“设备→安装增强功能”后界面没有任何反应菜单里的“拖放”、“共享剪贴板”选项也都是灰色不可点。整个虚拟机操作起来非常“孤立”文件传不进去。原因最常见的是虚拟机当前还不能正常识别虚拟光驱里的增强功能安装包或者镜像自带的Guest Additions版本和当前VirtualBox版本不兼容。另一个高频原因是系统缺少编译内核模块所需的依赖包安装脚本执行到一半自己退出。解决先走命令行补救按前面2.3小节的四条命令手动挂载并执行VBoxLinuxAdditions.run。如果报错信息涉及内核模块编译先跑一遍sudo apt update sudo apt upgrade -y把系统包更新到镜像源里的最新版再重新执行安装脚本。装完重启虚拟机再看“设备”菜单里的拖放功能是否是亮的。我遇到过装完脚本却没重启的情况功能也是灰的重启能解决一半的问题。5.2 cmake找不到Eigen头文件现象执行make时报fatal error: eigen3/Eigen/Core: No such file or directory或者直接提示某个Eigen头文件路径不存在编译中断。原因虚拟硬盘预装的Eigen头文件在/usr/include/eigen3目录下代码里#include eigen3/Eigen/Core这个路径带eigen3前缀是Ubuntu的目录结构决定的。而不带前缀的Eigen/Core只在一部分发行版或自行编译安装的Eigen里能用。如果框架代码里写错或者不小心从网上拷贝了不带前缀的写法就会踩这个坑。解决代码里统一写成#include eigen3/Eigen/Core。如果是CMakeLists.txt里用include_directories指定的路径不对打开CMakeLists把Eigen头文件目录指到/usr/include/eigen3。用sudo find /usr -name Core -path *Eigen*可以快速确认Eigen安装在哪路径对不对一查便知不用瞎猜。5.3 新建虚拟机时提示虚拟硬盘文件无法读取现象在VirtualBox“新建”流程里选择已有的vdi文件时弹窗提示无法读取、文件格式不正确或找不到指定路径。有时候还会在点“启动”后黑屏几秒直接退出。原因绝大部分是rar压缩包没解压完整或者解压目录包含中文和空格Linux路径和VirtualBox在解析这类路径时偶尔表现得很诡异。另一个可能是下载过程断流rar文件本身就是坏的解压出来vdi的大小明显不对劲。解决先看解压出来的vdi文件大小和描述里是否一致如果小了几十个GB肯定是没解压干净重新解压。然后把vdi挪到一个全英文且不带空格的路径下比如D:\vms\GAMES101_Ubuntu_18_04_2__64bit_.vdi文件名太长或带括号虽然一般没事但空格、括号在某些VirtualBox版本里确实触发过读取异常。挪完再新建一次虚拟机选择新的路径就行。5.4 编译过了运行./Transformation直接Segmentation Fault现象make顺利通过也生成了可执行文件但一运行就输出Segmentation fault (core dumped)程序被系统强制终止什么都没有打印。原因作业0作业本身代码量很小段错误大概率来自Eigen矩阵或向量的维度不匹配比如给一个Matrix3f直接赋值一个3×1向量再用矩阵乘法虽然编译警告不一定报错但运行时的内存访问越界会直接段错误。另一类原因是数组或容器越界在作业0里少见但也要排查。解决先把main.cpp里除了Eigen运算之外的部分注释掉只留一个固定矩阵乘固定向量看是否还崩溃。加std::cout p std::endl;这类调试输出确认是哪一步访问异常。用Eigen时特别注意固定尺寸类型Matrix3f、Vector3f的维度要匹配不要用Vector2f和Matrix3f直接相乘。改完重新make再运行。5.5 虚拟机运行卡顿、鼠标拖不动现象启动Ubuntu后桌面能进但别说编译连打开系统菜单都要转好几秒鼠标指针飘忽不定整个虚拟机像慢放。原因内存分配不够是最常见的。我之前试过给虚拟机只分配1GB内存Ubuntu 18.04桌面环境加上VSCode、编译器内存直接吃满大量时间花在换页上。另一个原因是虚拟机的显存或图形加速没开桌面渲染全靠软件模拟也会卡。解决关掉虚拟机在VirtualBox设置里把“系统→主板→内存大小”调到2048MB以上。在“显示”里把显存拉到128MB并勾选“启用3D加速”。如果主机内存也不宽裕建议不要在虚拟机里同时开着浏览器和VSCode桌面环境下只留一个编辑器最省资源。设置完重启虚拟机再看卡顿会明显改善。6. 提交前自检把矩阵的值打印出来对照手算基准作业0提交前我习惯在main.cpp里多写几行调试输出把旋转矩阵、平移矩阵和最终结果都打印出来和手算结果逐项核对。这一步的收获不只在作业0后续作业里的模型变换、观察变换都能用同一套方法定位问题。下面是一个可直接用于验证的版本稍作改动就能变成你的提交代码#include cmath #include iostream #include eigen3/Eigen/Core int main() { float angle 45.0f / 180.0f * acos(-1.0f); Eigen::Matrix3f R; R cos(angle), -sin(angle), 0.0f, sin(angle), cos(angle), 0.0f, 0.0f, 0.0f, 1.0f; Eigen::Matrix3f T; T 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 2.0f, 0.0f, 0.0f, 1.0f; Eigen::Vector3f p(2.0f, 1.0f, 1.0f); std::cout R:\n R std::endl; std::cout T:\n T std::endl; std::cout Result:\n T * R * p std::endl; return 0; }这段代码里R是旋转矩阵T是平移矩阵p是用齐次坐标表示的原始点。T * R * p的运算顺序严格对应“先旋转后平移”输出结果里能看到旋转后的坐标。对照上面4.3节手算的(1.7071, 4.1213)只要输出的前三位一致就说明变换矩阵构造和乘法顺序都没问题。注意这里p的第三分量是1.0不是0.0一旦写成0点会被当成方向向量平移分量会被忽略结果差很远。提交前我把检查流程固定成了三件事先把main.cpp完整编译一遍再看最终坐标是否接近手算基准最后确认虚拟机能正常运行可执行文件、终端没有报错输出。这三步走完再把整个作业框架文件夹按课程平台的要求打包提交。从那以后每次拿到新的作业框架我都强制走一遍“先编译后改码、先手算后运行”的自检流程中间矩阵打印的习惯帮我省掉了好几回查结果对不上的时间。希望帮到你。本文还有配套的精品资源点击获取