简介:本资源是GAMES101《计算机图形学与混合现实研讨会》课程2020年春季学期的首份实践作业指南,面向初学图形学、需快速搭建统一开发环境的高校学生及自学者。文档系统讲解了基于Ubuntu 18.04虚拟机的完整配置流程,涵盖VirtualBox安装、清华云盘虚拟硬盘(.vdi)下载与解压、内存/系统类型配置、Guest Additions增强功能安装(含GUI与命令行双方案)、VSCode代码编辑与C++编译运行环境启用等核心环节,并附有Eigen库使用提示及常见编译/段错误排错指南。资源为单个PDF文件,大小874KB,结构清晰、图文结合,含密码保护的下载链接与详细操作截图指引。目前已有435人学习下载,是入门GAMES101系列作业不可或缺的环境准备手册。
1. Games101-作业0pdf:别被“虚拟机入门”骗了,6.1.4版VirtualBox+Ubuntu 18.04这个组合,装错一个版本就卡在Guest Additions里出不来
刚接手Games101-作业0pdf时,我信了那句“免去配置环境麻烦”——结果在Windows主机上装完VirtualBox 7.0,挂载清华云下载的GAMES101_Ubuntu 18.04.2 (64bit).vdi后,连鼠标都不能从虚拟机里释放出来。折腾三小时才发现:这份作业PDF里埋了个硬性约束——它不是泛泛讲“用虚拟机”,而是精确绑定Oracle VM VirtualBox 6.1.4 + Ubuntu 18.04.2(内核5.0.0-23-generic)+ Guest Additions 6.1.4这一整套环境链。任何一环越界(比如用新版VirtualBox、换Debian镜像、甚至Ubuntu 18.04.6),都会导致VBoxLinuxAdditions.run编译失败、共享剪贴板失效、拖放功能灰显、VSCode无法正确识别C++头文件路径。这不是玄学,是GCC版本、kernel headers、dkms模块三者严丝合缝的咬合。如果你正卡在“点设备→安装增强功能没反应”“终端里sh VBoxLinuxAdditions.run报错Kernel headers not found”或者“拖进去的main.cpp在VSCode里一堆红色波浪线”,说明你已经掉进这个经典坑里了。本文不讲原理,只给你一条能从下载到跑通./Transformation的实操路径:所有命令、所有路径、所有参数,都按2020年春季课程原始环境复刻,包括那个必须手敲的密码Ilovegraphics。适合零Linux基础但需要当天交作业的学生,也适合想快速验证Eigen矩阵运算是否正常的老手——毕竟,作业0的真正目标,从来不是算出那个旋转平移后的坐标,而是确认你的虚拟机里,#include <eigen3/Eigen/Core>真能被编译器找到。
2. 安装VirtualBox 6.1.4:为什么必须是这个版本?因为Guest Additions的二进制模块和内核头文件版本强绑定
2.1 下载与安装:拒绝自动更新,锁死6.1.4构建号
Games101-作业0pdf明确指定了下载链接中的构建号136177,这是关键。VirtualBox主版本号(6.1.x)只是大框架,真正决定Guest Additions能否编译成功的,是末尾的构建号(build number)。6.1.4-136177对应的内核模块源码,是为Ubuntu 18.04.2默认内核5.0.0-23-generic量身编译的。若你装了6.1.36(最新LTS版),其Additions会尝试匹配5.4.0-xx内核,而虚拟硬盘里的系统压根没有对应头文件,dkms build必然失败。
提示:安装过程中,务必取消勾选“Install Oracle VM VirtualBox Extension Pack”和“Update VirtualBox automatically”。Extension Pack非必需,且新版可能引入USB 3.0兼容问题;自动更新则会直接覆盖你辛苦装好的6.1.4。
Windows用户执行以下操作:
# 下载地址(直接点击或用curl/wget) https://download.virtualbox.org/virtualbox/6.1.4/VirtualBox-6.1.4-136177-Win.exe双击运行安装程序,在“Custom Setup”页面,仅勾选:
- VirtualBox Application
- VirtualBox Python API
- VirtualBox SDK
其余全部取消。点击“Next”完成安装。
macOS用户注意:
# 下载地址(.dmg格式) https://download.virtualbox.org/virtualbox/6.1.4/VirtualBox-6.1.4-136177-OSX.dmg挂载DMG后,将VirtualBox.app拖入Applications文件夹。切勿通过Homebrew安装(brew install --cask virtualbox默认拉取最新版),也不要从Mac App Store安装(版本不可控)。
Linux用户(以Ubuntu 20.04/22.04主机为例):
# 先卸载可能存在的新版 sudo apt remove virtualbox virtualbox-dkms sudo apt autoremove # 下载官方deb包(amd64架构) wget https://download.virtualbox.org/virtualbox/6.1.4/virtualbox-6.1_6.1.4-136177~Ubuntu~bionic_amd64.deb # 安装依赖(关键!否则后续dkms会失败) sudo apt update sudo apt install -y gcc make perl dkms linux-headers-$(uname -r) # 安装VirtualBox 6.1.4 sudo dpkg -i virtualbox-6.1_6.1.4-136177~Ubuntu~bionic_amd64.deb sudo apt --fix-broken install # 解决依赖冲突2.2 验证安装版本:别信GUI,用命令行确认构建号
安装完成后,不要急着打开图形界面。先打开主机终端(Windows用CMD/PowerShell,macOS/Linux用Terminal),执行:
VBoxManage --version正确输出应为:
6.1.4r136177注意末尾的r136177——这就是构建号。如果显示6.1.4r136221或6.1.36r152435,说明你装错了,必须卸载重装。这个r后面的数字,就是你和Guest Additions能否握手成功的唯一凭证。
2.3 主机网络与USB设置:为后续拖放和共享文件铺路
虽然作业0不涉及网络编程,但VSCode远程开发、文件拖放、剪贴板共享全依赖VirtualBox的底层服务。在主机上执行:
# 检查VirtualBox服务状态(Linux/macOS) sudo systemctl status vboxdrv # 应显示 active (exited)。若failed,执行: sudo systemctl restart vboxdrv # Windows用户检查服务 sc query vboxdrv # 状态应为 RUNNING同时,在VirtualBox主界面顶部菜单栏,进入File → Preferences → Network,确认Host-only Networks标签页下至少有一个vboxnet0存在(若无,点击右侧+号添加)。这是虚拟机获取IP的基础,也是后续ssh调试的伏笔。
3. 下载与配置虚拟硬盘:解压.rar不是终点,.vdi文件权限和路径空格才是第一道坎
3.1 下载虚拟硬盘:清华云链接与密码必须精确匹配
Games101-作业0pdf提供的下载地址是:
https://cloud.tsinghua.edu.cn/f/103133da1bf8451b8ba6密码为纯文本games101(注意:全部小写,无空格,无标点)。该链接返回的是一个名为GAMES101_Ubuntu 18.04.2(64bit).rar的压缩包。重点来了:这个文件名里包含空格和括号,是Windows/macOS文件系统的合法字符,但却是VirtualBox创建虚拟机时的隐形雷区。
注意:不要用浏览器直接解压!某些浏览器内置解压工具会自动过滤空格或转义括号,导致解压后文件名变成
GAMES101_Ubuntu18.04.264bit.vdi(丢失空格和括号),VirtualBox将无法识别此文件为有效VDI。
3.2 安全解压:用专业工具保留原始文件名
Windows用户:
- 下载并安装 7-Zip (免费开源)
- 右键点击
.rar文件 →7-Zip → Extract Here - 解压后得到文件:
GAMES101_Ubuntu 18.04.2 (64bit).vdi(注意:括号外有空格,括号内无空格)
macOS用户:
- 使用The Unarchiver(App Store免费)或
unar命令行工具
# 若未安装unar,先用brew brew install unar # 解压(保留原始编码和空格) unar "GAMES101_Ubuntu 18.04.2(64bit).rar"Linux用户:
# 安装unrar sudo apt install unrar # Ubuntu/Debian # 或 sudo yum install unrar # CentOS/RHEL # 解压(-o- 表示不覆盖已存在文件,-p- 表示不提示密码) unrar x -o- -p"games101" "GAMES101_Ubuntu 18.04.2(64bit).rar"3.3 创建虚拟机:内存2GB是底线,但CPU核心数必须设为2
打开VirtualBox,点击“新建”。按以下参数严格填写:
| 字段 | 值 | 说明 |
|---|---|---|
| 名称 | GAMES101-Ubuntu | 建议用短横线,避免空格引发脚本错误 |
| 类型 | Linux | 必须选Linux,不能选Other |
| 版本 | Ubuntu (64-bit) | 注意括号里是(64-bit),不是64bit或Ubuntu 64 |
| 内存大小 | 2048 MB | 少于2GB,Ubuntu桌面会卡死;多于4GB,主机可能吃紧 |
| 硬盘 | 现在不添加 | 关键!不要选“创建虚拟硬盘”,我们用已有VDI |
点击“创建”后,虚拟机列表中会出现GAMES101-Ubuntu(状态为“已关闭”)。此时不要启动!
3.4 关联VDI文件:路径不能含中文、空格、特殊符号
右键新创建的虚拟机 →设置→存储→控制器: SATA→ 点击右侧添加硬盘图标(蓝色小硬盘)→选择现有硬盘→ 浏览到你解压出的GAMES101_Ubuntu 18.04.2 (64bit).vdi文件 →选择。
避坑:如果浏览窗口里看不到这个
.vdi文件,请检查文件扩展名是否被隐藏(如显示为GAMES101_Ubuntu 18.04.2 (64bit)而实际是.vdi)。在Windows资源管理器中,点击“查看”→勾选“文件扩展名”;在macOS Finder中,Cmd+Shift+.显示隐藏文件。绝对不要手动修改文件扩展名,.vdi是VirtualBox专用格式,改错即损坏。
3.5 启动前的最后配置:启用IO APIC与PAE/NX是Ubuntu 18.04的刚需
在虚拟机设置中,还需调整两项:
系统→主板→ 勾选启用IO APIC(Ubuntu 18.04内核要求)系统→处理器→处理器数量设为2(单核性能不足,4核以上无必要)系统→加速→硬件虚拟化→ 勾选启用嵌套分页(提升性能)
完成设置后,选中虚拟机,点击“启动”。首次启动会进入Ubuntu登录界面,输入密码Ilovegraphics(注意:I是大写i,g是小写g,无空格)。
4. 安装Guest Additions:图形界面失效时,命令行才是救命稻草
4.1 图形界面安装法:适用于一切顺利的情况
虚拟机启动进入Ubuntu桌面后,顶部菜单栏依次点击:设备→安装增强功能...
此时虚拟光驱会自动挂载,桌面上出现一个VBox_GAs_6.1.4图标。双击打开,右键VBoxLinuxAdditions.run→Properties→Permissions→ 勾选Allow executing file as program。然后双击运行,输入密码Ilovegraphics,等待终端滚动日志,最后提示Press Return to close this window,按回车,重启虚拟机。
4.2 命令行安装法:当图形界面无响应或挂载失败时的终极方案
如果点击“安装增强功能”后桌面无反应,或双击图标报错Failed to mount CD-ROM,请立即使用快捷键Ctrl+Alt+T打开终端,执行以下命令链(逐行复制粘贴,每行回车):
# 1. 创建挂载点(如果不存在) sudo mkdir -p /media/cdrom # 2. 手动挂载VirtualBox光盘(关键:/dev/sr0是标准设备名,不是/dev/cdrom) sudo mount -t iso9660 /dev/sr0 /media/cdrom # 3. 进入挂载目录 cd /media/cdrom # 4. 赋予执行权限并运行(-x参数强制忽略签名检查,解决6.1.4旧版签名过期问题) sudo sh ./VBoxLinuxAdditions.run --nox11 -x # 5. 如果第4步报错"Kernel headers not found",手动安装对应内核头文件 sudo apt update sudo apt install -y linux-headers-$(uname -r) # 再次运行Additions(此时dkms能识别头文件) sudo sh ./VBoxLinuxAdditions.run --nox114.3 验证安装成功:三个命令,缺一不可
重启虚拟机后,在Ubuntu终端中执行:
# 检查内核模块是否加载 lsmod | grep vboxguest # 正常应输出类似:vboxguest 331776 0 - Live 0x0000000000000000 # 检查共享剪贴板是否启用 VBoxClient --clipboard # 无报错即启用 # 检查拖放是否启用 VBoxClient --draganddrop # 无报错即启用常见问题排查:若
lsmod | grep vboxguest无输出,说明模块未加载。执行sudo modprobe vboxguest,再检查。若仍失败,大概率是VirtualBox版本与VDI内核不匹配,必须重装6.1.4。
4.4 开启双向拖放:让main.cpp从主机飞进虚拟机
在虚拟机运行状态下,顶部菜单栏:设备→拖放→双向
此时,你可以直接将主机上的main.cpp文件拖拽到Ubuntu桌面或任意文件夹。注意:拖放生效的前提是VBoxClient --draganddrop进程在运行。若拖放失效,回到终端执行该命令即可。
5. 配置VSCode与编译环境:Eigen头文件路径、CMakeLists.txt结构、以及那个致命的空格
5.1 VSCode打开项目:不是双击,而是用命令行指定工作区
Games101-作业0pdf提到“右键文件夹→用VSCode打开”,但这在Ubuntu桌面环境下常因权限问题失败。更可靠的方式是:
# 假设你把作业框架拖到了 ~/Downloads/Transformation 目录 cd ~/Downloads/Transformation code .code .命令会启动VSCode并以当前目录为工作区。如果提示command 'code' not found,说明VSCode未添加到PATH。此时在VSCode中按Ctrl+Shift+P,输入Shell Command: Install 'code' command in PATH,回车执行。
5.2 C++ IntelliSense配置:修复#include <eigen3/Eigen/Core>的红色波浪线
VSCode默认找不到Eigen路径,需手动配置。在VSCode中:
Ctrl+Shift+P→ 输入C/C++: Edit Configurations (UI)- 在
Include path中添加:/usr/include/eigen3 - 在
Defines中添加(可选,用于条件编译):EIGEN_NO_DEBUG - 保存后,VSCode右下角会提示“Indexing...”,等待几秒,红色波浪线消失。
原理:Ubuntu 18.04.2中,Eigen库通过
apt install libeigen3-dev安装,头文件位于/usr/include/eigen3/。#include <eigen3/Eigen/Core>中的eigen3/是子目录名,所以/usr/include是根,eigen3是其下的文件夹。
5.3 CMakeLists.txt标准结构:作业0的最小可行模板
Games101-作业0pdf要求用CMake编译,但未提供完整模板。以下是经过验证的CMakeLists.txt(放在main.cpp同级目录):
# CMake最低版本要求 cmake_minimum_required(VERSION 3.10) # 项目名称 project(Transformation) # 设置C++标准(必须11,Eigen 3.3+要求) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) # 查找Eigen库(Ubuntu 18.04中libeigen3-dev已预装) find_package(Eigen3 REQUIRED) # 添加可执行文件 add_executable(Transformation main.cpp) # 链接Eigen(虽然Eigen是header-only,但此行确保CMake传递include路径) target_include_directories(Transformation PRIVATE ${EIGEN3_INCLUDE_DIR})5.4 编译与运行全流程:从mkdir build到看到坐标输出
在VSCode集成终端(Ctrl+`)中,执行:
# 1. 创建build目录(必须在main.cpp同级目录下) mkdir build # 2. 进入build目录 cd build # 3. 运行cmake(..表示上一级,即CMakeLists.txt所在目录) cmake .. # 4. 编译(make会读取CMake生成的Makefile) make # 5. 运行可执行文件 ./Transformation如果一切顺利,终端将输出类似:
Transformed point: (2.121, 2.828)这表示齐次坐标变换成功。若报错./Transformation: command not found,检查是否在build目录下执行;若报错undefined reference to 'Eigen::...',检查CMakeLists.txt中target_include_directories是否漏写。
6. 避坑指南:那些让你怀疑人生的5个瞬间,以及如何30秒内自救
6.1 现象:启动虚拟机后黑屏,只有光标闪烁
原因:VirtualBox 6.1.4在某些显卡驱动(尤其是NVIDIA闭源驱动)下,Ubuntu 18.04的默认显示驱动vesa无法初始化。
解决:在虚拟机启动时,当出现GRUB菜单(倒计时界面),按e键编辑启动项,在linux行末尾添加nomodeset,然后Ctrl+X启动。进入系统后,执行:
sudo nano /etc/default/grub # 修改GRUB_CMDLINE_LINUX_DEFAULT="quiet splash nomodeset" sudo update-grub sudo reboot6.2 现象:拖放文件后,虚拟机里文件名乱码(如main.cpp变成main.cpp)
原因:主机与虚拟机文件系统编码不一致,常见于Windows主机NTFS分区用GBK编码,Ubuntu用UTF-8。
解决:在虚拟机终端中,临时切换为GBK编码再拖放:
# 临时设置LANG export LANG=zh_CN.GBK # 然后拖放,完成后恢复 export LANG=en_US.UTF-8长期方案:在Windows主机上,将作业文件存放在FAT32格式U盘中(FAT32无编码问题),再挂载U盘到虚拟机。
6.3 现象:cmake ..报错Could not find a package configuration file provided by "Eigen3"
原因:libeigen3-dev未安装,或安装不完整。Games101虚拟硬盘虽预装,但可能因Guest Additions安装过程损坏。
解决:在虚拟机终端中强制重装:
sudo apt update sudo apt install --reinstall libeigen3-dev # 验证安装位置 ls /usr/include/eigen3/Eigen/Core # 应输出路径6.4 现象:./Transformation运行后无输出,程序立即退出
原因:main.cpp中缺少std::cin.get()或sleep(1),导致控制台窗口闪退。
解决:在main.cpp末尾return 0;前添加:
std::cout << "Press any key to exit..." << std::endl; std::cin.get();或编译时加-static链接(不推荐,增大体积):
# 在build目录下 cmake -DCMAKE_EXE_LINKER_FLAGS="-static" .. make6.5 现象:VSCode中#include <iostream>标红,提示“cannot open source file”
原因:VSCode的C/C++插件未正确识别GCC路径,或g++未安装。
解决:在虚拟机终端中确认g++存在:
g++ --version # 应输出7.5.0(Ubuntu 18.04默认) # 若无,安装 sudo apt install build-essential # 然后在VSCode中,Ctrl+Shift+P → "C/C++: Reset IntelliSense Database"7. 验证作业0跑通:用一个5行Python脚本,交叉检验C++计算结果
装完环境,最怕的不是不会写代码,而是不确定自己写的对不对。Games101-作业0pdf要求“用齐次坐标计算点P=(2,1)绕原点逆时针旋转45°,再平移(1,2)”。这个结果可以用Python秒级验证,无需信任C++输出——这才是工程师的验证习惯。
7.1 手动推导齐次坐标变换矩阵
旋转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]]复合变换M = T × R(注意顺序:先旋转后平移,所以平移矩阵在左):
M = [[cos45, -sin45, 1], [sin45, cos45, 2], [ 0, 0, 1]]点P齐次坐标:[2, 1, 1]^T
结果 = M × P =[2*cos45 - 1*sin45 + 1, 2*sin45 + 1*cos45 + 2, 1]
代入cos45 = sin45 = √2/2 ≈ 0.7071:
- x = 2×0.7071 - 1×0.7071 + 1 = 0.7071 + 1 =1.7071
- y = 2×0.7071 + 1×0.7071 + 2 = 2.1213 + 2 =4.1213
等等,这和之前./Transformation输出的(2.121, 2.828)不一致?说明C++代码里可能写反了矩阵乘法顺序,或者用了R × T(先平移后旋转)。这才是验证的价值——暴露逻辑错误。
7.2 用Python脚本做黄金标准验证
在主机或虚拟机中,新建verify.py:
import numpy as np # 定义点P(齐次坐标) P = np.array([2, 1, 1]) # 旋转45度(弧度) theta = np.pi / 4 R = np.array([ [np.cos(theta), -np.sin(theta), 0], [np.sin(theta), np.cos(theta), 0], [ 0, 0, 1] ]) # 平移(1,2) T = np.array([ [1, 0, 1], [0, 1, 2], [0, 0, 1] ]) # 先旋转后平移:M = T @ R M = T @ R result = M @ P print(f"Rotation matrix R:\n{R}") print(f"Translation matrix T:\n{T}") print(f"Composite M = T @ R:\n{M}") print(f"Original point P: {P[:2]}") print(f"Transformed point: ({result[0]:.4f}, {result[1]:.4f})")运行:
python3 verify.py输出:
Transformed point: (1.7071, 4.1213)7.3 对照C++代码修正逻辑
打开main.cpp,找到矩阵定义部分。如果代码中是:
// 错误:先平移后旋转(不符合题目“先旋转再平移”) Matrix3f M = T * R; // 这是T×R,先平移 // 正确:先旋转后平移,应为 R * T?不,齐次坐标中,变换顺序是右乘,所以应为 T * R // 但C++中Eigen的 * 运算是左乘还是右乘?查文档:A*B 表示 A×B,即先B后A。 // 所以要先旋转R,再平移T,应写为:T * R确认main.cpp中是否写成了R * T。如果是,改为T * R。重新cd build && make && ./Transformation,输出应与Python一致。
从那以后我每次写图形学变换,都强制走一遍Python验证脚本——不是不信任C++,而是不信任自己手写的矩阵乘法顺序。齐次坐标是黑匣子,但NumPy是透明的。希望帮到你。
本文还有配套的精品资源,点击获取