凌晨两点半,我盯着屏幕上那条曲线,它在第三和第四个控制点之间走出一条诡异的弧度,像是被风吹歪的棉线。问题的根源后来发现很简单:我在循环里把控制点数组的引用当成了值传递,迭代过程里修改了原始顶点。这种能让人崩溃一整晚的 bug,在 Games102 的作业里几乎每隔几天就出现一次。
Games102 是 GAMES 系列课程里的《几何建模与处理》,和面向渲染入门的 Games101 不同,这门课把重点放在了几何数据表示、曲线曲面、网格和点云处理上。作业也不是写一个光栅化器或者路径追踪器,而是从零实现各种几何算法。听起来不如渲染炫酷,但实际做完一轮之后,我对“一个数学公式如何变成内存里的操作”这件事的理解,比过去看十篇博客都深。
这篇是“作业上”的经验总结,覆盖我从零开始做完前半程作业的全部过程:环境准备、核心算法实现、结果验证,以及几段完整的踩坑排查记录。适合正在写 Games102 作业的人,也适合想自学几何处理、但不确定从哪开始动手的读者。
1. 这门课的作业为什么值得死磕
1.1 “几何建模与处理”到底在训练什么
Games102 的核心内容不是某个渲染算法,而是几何对象的表示、生成、分析和编辑。简单说,就是解决这么几个问题:三维模型在计算机里长什么样;怎么用数学语言描述一条光滑曲线、一张曲面;怎么把一个高精度模型变轻;怎么把一张纹理贴到三维模型上不扭曲。
这些问题的共同点是:数学公式密集,但课程不会帮你把公式翻译成代码。作业就是逼你完成这个翻译过程。前半程的作业通常会覆盖到:
- 曲线部分:Bézier 曲线、B-spline 或 NURBS 的查值和插值;
- 曲面部分:张量积曲面、隐式曲面的采样和网格化;
- 网格基础:网格数据结构的构建与遍历,可能还会涉及网格简化或细分。
我这一轮作业的第一项,就是实现 Bézier 曲线的 de Casteljau 算法。看起来是几行递归插值,实际上涉及控制点保存方式、细分步数、迭代中间量存储、可视化输出一系列问题。等你把所有环节串起来,才发现这不是“写一个算法”,而是“写一个能被人看到结果的完整工具链”。
1.2 前半程作业的难度梯度不是线性的
很多人以为作业是按每周内容线性递进的,实际上难度在曲线到网格之间会跳变。前一两周你还在处理一维参数曲线,切换去写网格数据结构时,马上要面对半边结构、邻接关系、边界条件这些完全不同的思维方式。
举一个例子。曲线代码里,你的对象是 std::vector<Vector2d>,控制点、采样点都往里面塞,逻辑核心是循环里的线性插值。到了网格作业,数据变成顶点表、面表、半边表,一个顶点的所有邻居要靠指针关系串起来,边界边没有“对面”半边,访问之前必须先判空。很多同学第一个网格遍历程序跑起来后直接崩溃,问题几乎都出在没处理边界。
建议把前半程当作三个独立的小项目来安排时间:曲线一个、曲面一个、网格一个。每个项目内部按“数学推导 -> 数据结构设计 -> 裸实现 -> 可视化验证”的顺序推进。不要试图一次性做完所有作业,几何算法一旦堆积到一定规模,查错成本会指数上升。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 动手写算法之前,先把环境和数据管线理顺
2.1 语言、数学库与可视化工具的选型
关于语言,课程虽然不强制,但 C++ 依然是主流选择。我见过有同学用 Python + numpy 复现曲线算法,验证数学原理确实快,但到了网格编辑这种大量指针操作的场景,会非常别扭。我的建议是:C++ 写主体,Python 做快速数学验证。
数学库我推荐 Eigen,3.4 版本。它在 CMake 里是 header-only 的,省去了很多链接麻烦,矩阵运算、线性方程求解、几何变换都能直接拿过来用。作业里涉及最小二乘拟合时,Eigen 的 LDLT、HouseholderQR 这些分解器能起到关键作用。如果你用的是官方模板框架,通常已经集成了 Eigen,但要注意版本不能换来换去。
可视化这块,我强烈建议引入 Polyscope。它不是给作业“锦上添花”,而是解决问题的核心工具。Polyscope 可以直接注册 std::vector<Eigen::Vector3d> 作为点云,注册顶点和面索引作为网格,还有内置的曲线绘制接口。相比每次打开 MeshLab 加载离线模型,Polyscope 可以做到“改完参数立刻看结果”,调试效率高一个
