VirtualBox+VDI搭建Ubuntu虚拟环境:GAMES101作业0与Eigen矩阵变换 简介这是GAMES101计算机图形学课程作业0的PDF文档面向选修闫令琪老师课程、需要完成虚拟环境配置作业的学生。文档完整收录作业要求与虚拟机使用指南涵盖VirtualBox安装、虚拟硬盘文件下载与挂载、Guest Additions增强功能安装、作业框架传输及Visual Studio Code编辑等关键环节并附有C语法要点与Eigen库使用注意事项可帮助初学者避开环境配置常见问题、快速上手课程作业。压缩包为单份PDF文档大小仅874KB便于下载与查阅。该资源已有433人学习下载适合正在入门GAMES101或需要复习虚拟机配置流程的图形学学习者。1. 虚拟化环境图形学作业0的第一步为什么必须统一配置图形学入门的第一道槛通常不是数学而是环境。GAMES101的作业0就干了一件事让所有人在同一套虚拟化的 Ubuntu 18.04 里写 C。理由很简单——不同电脑的 OpenGL、编译器、依赖库版本差异能把一个刚入门的同学拖在配置里一整天而一份打包好的虚拟硬盘VDI直接把环境、库、编辑器全部固定下来。这份 PDF 是作业说明也是完整的虚拟机搭建手册覆盖从下载 VirtualBox、挂载 VDI、安装 Guest Additions 到用 Eigen 写矩阵变换的全流程。适合所有准备开始图形学作业、又对 Linux 环境不熟的人也适合想看看这套课程作业长什么样的自学者。下面的内容按我实际复现的顺序写先讲为什么非要用虚拟机再给完整配置过程、代码、编译命令最后是几个我踩过的坑。2. VirtualBox VDI 搭建虚拟机选型理由与三个关键配置2.1 为什么是 VirtualBox 加 VDI而不是 Docker 或 WSL2很多第一次接触这课的开发者会问图形学作业不是写 C 吗为什么不上 Docker 容器或者 WSL2我当初也这么想过直到真的跑起来才发现问题。Docker 容器默认没有显示环境而作业框架里的 OpenGL、图像窗口、甚至后面几项作业的 GUI 展示都需要 X11/GLX容器里要么手动装 X server要么做 VNC 转发对新手极不友好。WSL2 的问题是 GPU 加速和图形转发配置随 Windows 版本变化很大而且课程提供的 VDI 是完整的 Ubuntu 系统盘WSL2 没法直接挂载。VirtualBox 的做法最直接把整个 Ubuntu 18.04 系统作为虚拟硬盘挂载启动即用不折腾显卡驱动、不折腾依赖版本。选 VirtualBox 而不是别的虚拟机还有一个原因它支持“使用已有的虚拟硬盘文件”直接启动不需要自己安装系统。VDI 文件里已经预装了 GCC、CMake、Eigen、VSCode、Sublime密码也写在文档里。这种模式的最大价值是环境一致性——你和课程作者用的完全是同一份系统镜像报错信息也能对得上。提示如果你已经在用 VMware 或 Parallels不必换直接新建虚拟机并挂载 VDI 文件也可以。常见做法是新建 Linux/Ubuntu-64bit 虚拟机硬盘选择“使用现有虚拟硬盘”并指向 .vdi效果相同。2.2 三个关键配置内存 2GB、Linux 64bit、已有 VDI创建虚拟机时文档要求三处关键配置类型选 Linux版本选 Ubuntu-64bit不要选 32 位课程镜像只有 64 位内存建议 2GB如果主机内存紧张 1GB 也能跑但编译稍慢存储选“使用已有的虚拟硬盘文件”指向解压出的 .vdi下载和解压也是坑点PDF 里的网盘密码是 games101解压后得到 GAMES101_Ubuntu 18.04.2 (64bit).vdi。如果你下载的是一串浏览器自动改名文件务必确认扩展名是 .rar 和解压后是 .vdiVirtualBox 只认 .vdi 结尾。注意新建向导默认会把虚拟硬盘建在系统盘建议先看一眼存储路径。我一般会把 VDI 挪到独立固态盘并保证剩余空间至少 10GB因为后续作业会生成大量编译中间文件。2.3 启动虚拟机第一次开机后的检查清单启动虚拟机后进入 Ubuntu 桌面需要输入登录密码。第一次进桌面我建议按这个顺序检查# 查看系统版本和内核确认 vdi 镜像确实可用 cat /etc/os-release uname -a # 确认关键工具已在镜像内 gcc --version cmake --version ls /usr/include/eigen3/Eigen/Core这三条命令的逻辑os-release 确认 Ubuntu 版本uname 看内核位数最后一条确认 Eigen 头文件路径——后面写作业代码时最常翻车的就在这里。如果 ls 报不存在说明镜像被改过或解压不完整重新解压 VDI 比手动装 Eigen 更省事。注意不要急着敲命令。常见做法是先打开终端切换到普通用户目录因为课程镜像默认的环境已经配好权限直接用即可。3. Guest Additions 与作业框架传输从主机到虚拟机的通道3.1 Guest Additions 到底解决什么问题虚拟硬盘镜像跑起来的 Ubuntu默认只有 800x600 分辨率鼠标捕获后需要按右 Ctrl 释放主机和虚拟机之间不能互相拖文件。Guest Additions增强功能是 VirtualBox 给虚拟机装的驱动包装完之后分辨率自动适配窗口、鼠标平滑进出、还能启用共享剪贴板和双向拖放。这一步很重要因为后续作业框架传输要靠双向拖放日常复制代码也要靠共享剪贴板。文档给的第一种安装方式很简单菜单栏点 设备 → 安装增强功能VirtualBox 会把一个安装光盘镜像挂载到虚拟机然后在光驱里运行安装脚本。如果点击后没反应常见做法是打开终端手动挂载光驱并运行安装脚本。文档原文命令如下sudo mkdir -p /media/cdrom sudo mount -t auto /dev/cdrom /media/cdrom/ cd /media/cdrom/ sudo sh VBoxLinuxAdditions.run参数含义mkdir -p 创建挂载目录-p 表示目录已存在时不报错mount -t auto 让系统自动识别光盘文件系统VBoxLinuxAdditions.run 是光驱里的安装脚本。执行完重启虚拟机才会生效。3.2 安装增强功能失败的补救先准备编译环境再重装一个很常见的情况执行 VBoxLinuxAdditions.run 报错提示缺少 gcc 或 make或者提示内核头文件找不到。原因是 VDI 镜像虽然是完整 Ubuntu但不一定包含与当前内核匹配的全部构建工具。我一般会先执行sudo apt update sudo apt install -y build-essential linux-headers-$(uname -r) sudo sh VBoxLinuxAdditions.run --nox11--nox11 参数跳过 X11 相关的 GUI 组件在很多桌面环境异常的场景下能救一命。安装完重启分辨率如果从 800x600 变成自适应窗口说明增强功能生效。提示99% 的增强功能安装失败都是缺内核头文件。先把 uname -r 输出和安装日志里报缺的文件名比对再决定装什么包。先装 linux-headers-$(uname -r) 再重跑一遍安装脚本成功的概率很高。3.3 双向拖放与 VSCode 打开作业文件夹增强功能装好后菜单栏 设备 → 拖放 → 选择 双向。之后就能从主机直接拖文件进虚拟机桌面。拖进去的文件通常在 ~/桌面 或当前用户目录下我的做法是把作业框架文件夹整个拖进去然后重命名再右键 → 使用其他应用打开 → Visual Studio Code。注意拖放的两个细节拖入的文件夹如果带中文名或空格VSCode 路径处理有时会出问题先重命名为简洁名如果拖放方向失败检查菜单里是否选的“双向”而不是“仅主机到虚拟机”在 VSCode 里打开文件夹的正确方式File → Open Folder → 找到刚才拖入的目录 → OK。作业框架通常包含 main.cpp 和 CMakeLists.txt直接在侧边栏点击即可编辑。4. 作业0核心算法齐次坐标旋转加平移的数学推导与 Eigen 落地4.1 为什么非要用齐次坐标作业0的题目给定点 P(2,1)绕原点先逆时针旋转 45°再平移 (1,2)计算变换后坐标。用普通 2×2 矩阵可以做旋转但平移在 2×2 矩阵里表达不了——平移不是线性变换。把点扩充成齐次坐标 (x, y, 1)用 3×3 矩阵就能同时表达旋转和平移旋转矩阵 R [cosθ -sinθ 0; sinθ cosθ 0; 0 0 1] 平移矩阵 T [1 0 tx; 0 1 ty; 0 0 1]先旋转再平移组合矩阵是 T×R注意矩阵乘法的顺序后应用的变换矩阵放在左侧。代入 θ45°tx1ty2手工算一遍会得到变换后 x ≈ 1.707y ≈ 4.121。留这个手工结果在后面验证代码。4.2 用 Eigen 写变换代码Vector3f 与 Matrix3f 的组合课程镜像里已经装好 Eigen作业模板要求用 eigen3/Eigen/Core 头文件。下面是可直接编译的 main.cpp#include cmath #include iostream #include eigen3/Eigen/Core int main() { // 定义齐次坐标下的点 P(2,1)第三维固定为 1 Eigen::Vector3f p(2.0f, 1.0f, 1.0f); // 逆时针旋转 45 度角度转弧度 float angle 45.0f * M_PI / 180.0f; Eigen::Matrix3f R; R std::cos(angle), -std::sin(angle), 0.0f, std::sin(angle), std::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; // 先旋转再平移T * R * p Eigen::Vector3f result T * R * p; std::cout Transformed point: result.transpose() std::endl; return 0; }代码逻辑Vector3f 表示齐次坐标Matrix3f 是 3×3 变换矩阵。R 和 T 用逗号初始化器按行填充std::cos 和 std::sin 接受弧度。最后 TRp 完成变换transpose() 把列向量转成行向量打印输出更干净。参数说明angle 把 45° 乘上 π/180 转成弧度结果第三维应该是 1.0如果输出不是 1.0说明矩阵拼错了。Eigen 的固定尺寸矩阵默认是列主序存储但 初始化按行逻辑填充这点不需要操心直接按行写就行。4.3 CMakeLists.txt 与编译步骤从 mkdir build 到 ./Transformation作业框架里自带 CMakeLists.txt核心内容如下cmake_minimum_required(VERSION 3.10) project(Transformation) set(CMAKE_CXX_STANDARD 11) include_directories(/usr/include/eigen3) add_executable(Transformation main.cpp)这段 CMake 的逻辑project 声明工程名add_executable 把 main.cpp 编译成名为 Transformation 的可执行文件include_directories 把 /usr/include/eigen3 加进头文件搜索路径。如果你用 find_package(Eigen3 REQUIRED) 报错多半就是这个头文件路径的问题。编译命令按文档顺序执行mkdir build cd build cmake .. make ./Transformationcmake .. 中的 .. 指上一级目录源码目录. 才是当前目录。make 生成的 Transformation 在 build 目录下所以要在 build 里运行 ./Transformation。预期输出Transformed point: 1.70711 4.12132 1如果第三个分量不是 1回去检查 T 矩阵第三行。如果前两个分量和手工算的 1.707、4.121 不一致优先怀疑旋转方向——绕原点逆时针 45° 对应矩阵左上角 sin 值为正写成负值就变成顺时针了。5. 避坑与常见问题虚拟机环境和 Eigen 编译的五个典型踩坑5.1 双向拖放在菜单里是灰色不可点现象设备 → 拖放 选项是灰色无法切换成双向。 原因Guest Additions 没有安装成功VirtualBox 不知道当前虚拟机支持增强功能。 解决先按第 3 章的命令行方式安装增强功能重启后菜单立即变可用。如果重启后还是灰色检查是否登录到镜像默认用户而不是其他用户——权限不对时菜单项会禁用。5.2 虚拟机分辨率卡在 800x600现象桌面小得离谱窗口不能自适应调整大小。 原因增强功能内核模块未加载通常与内核头文件版本不匹配有关。 解决在终端执行 sudo apt install -y linux-headers-$(uname -r)然后重跑安装脚本最后重启。验证方式拖动虚拟机窗口边缘桌面应平滑放大缩小。5.3 编译报错fatal error: eigen3/Eigen/Core: No such file or directory现象make 时头文件找不到编译直接失败。 原因CMakeLists.txt 里少了 include_directories或 Eigen 安装路径不在默认搜索路径。 解决确认 /usr/include/eigen3 是否存在执行 ls /usr/include/eigen3/Eigen/Core 验证。如果这个目录不存在执行 sudo apt install -y libeigen3-dev 安装后重试。然后在 CMakeLists.txt 里加上 include_directories(/usr/include/eigen3)。5.4 链接阶段报 undefined reference现象编译通过但 make 的最后一步报 undefined reference to xxx。 原因链接错误意味着某个目标文件没被加入 add_executable比如你新增了 .cpp 文件但没写进 CMakeLists.txt。 解决检查 add_executable 那一行把所有源码文件都列进去。作业0只有一个 main.cpp通常不会遇到但后面几项作业框架文件多起来这个坑基本必现。5.5 运行 ./Transformation 报段错误 Segmentation Fault现象程序编译成功运行直接崩。 原因Eigen 矩阵未初始化直接参与运算或者对数组越界访问。作业0里最常见的是声明了一个空 Matrix3f 没赋值就直接乘。 解决所有 Eigen 对象声明即初始化或至少用 Eigen::Matrix3f::Zero() 零初始化。作业0的代码建议在声明处直接给值不声明空对象。提示Eigen 对固定尺寸和动态尺寸的处理不一样作业0用固定尺寸 3×3 不会有问题。但如果你改成 4×4 时行列不匹配Eigen 会在运行时 assert 报错而不是静默出错看到 Assertion failed 别慌查矩阵维度。6. 进阶验证把作业0扩展成三维仿射变换并核验中间结果作业0只要求 2D 齐次坐标但图形学管线里的模型变换几乎都是 4×4 齐次矩阵。花十分钟把作业0扩展成三维能同时验证你对 Eigen 和齐次坐标的理解。做法是把 P 变成 Vector4f(2,1,0,1)旋转绕 Z 轴矩阵拼成 4×4Eigen::Vector4f p4(2.0f, 1.0f, 0.0f, 1.0f); Eigen::Matrix4f R4; R4 std::cos(angle), -std::sin(angle), 0.0f, 0.0f, std::sin(angle), std::cos(angle), 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f; Eigen::Matrix4f T4; T4 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 2.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f; std::cout (T4 * R4 * p4).transpose() std::endl;验证方法把前两个分量和你手工算的 1.707、4.121 对比第三维应为 0第四维应为 1。如果对不上先检查旋转矩阵绕 Z 轴的结构——只有第三行第三列为 1 时Z 分量才不变。再进一步把一次变换拆成两次先用 R4 * p4 得到中间结果再用 T4 乘它打印两次中间量。这对排查“先平移还是先旋转”的次序错误很有用——很多入门图形学的开发者在这里翻车先平移再旋转旋转矩阵会对平移量也做旋转结果完全不同。顺序问题在图形学里贯穿始终模型变换、视图变换、投影矩阵处处都是矩阵乘法的次序问题。作业0虽然不评分但把“手工推导 → 代码实现 → 拆分验证”这条流程走一遍后面写 Phong 光照、做光栅化时的矩阵拼接会顺手很多。自从那一次被旋转顺序坑过之后我每次写变换代码都强制先手工算一遍再打印中间矩阵核对这个习惯帮我省下的调试时间远超预期。希望帮到你。本文还有配套的精品资源点击获取