Skip to content

几何(曲线与曲面)

上一章把几何表示分成点云、线框、三角网格、隐式表面、参数表示和体数据。三角网格适合实时渲染,但它毕竟是离散的:一个圆用很多线段近似,一个曲面用很多三角形近似。

本章关注另一类几何:曲线与曲面。它们通常用少量控制点和数学函数描述连续形状,然后在需要渲染、碰撞或制造时再离散成线段或三角网格。

这种思想在图形学中非常重要。字体轮廓、动画路径、相机轨迹、角色建模、汽车外壳、工业 CAD、曲面细分,都离不开曲线与曲面。


最直接的曲线描述方式是参数方程。二维或三维曲线可以写成:

P(t)=(x(t),y(t),z(t))P(t) = (x(t), y(t), z(t))

其中 tt 是参数,通常位于某个区间内,例如 t[0,1]t \in [0, 1]。当 tt00 变化到 11 时,点 P(t)P(t) 在空间中移动,轨迹就形成一条曲线。

例如二维圆可以写成:

P(t)=(rcost,rsint)P(t) = (r\cos t, r\sin t)

参数曲线的优点是连续、紧凑、容易求导。导数可以表示曲线在某一点的切线方向:

P(t)=dP(t)dtP'(t) = \frac{dP(t)}{dt}

这对动画路径、相机运动、曲面法线和物体沿曲线移动都很有用。


直接写出 x(t)x(t)y(t)y(t)z(t)z(t) 的函数在数学上很清楚,但对建模和设计并不友好。艺术家或设计师更希望通过拖动少量点来控制形状,而不是手写复杂方程。

于是就有了控制点 (Control Points) 的思想:曲线不一定穿过所有控制点,但控制点会像磁铁一样影响曲线走向。

控制点带来几个好处:

  • 形状可视化编辑。
  • 曲线可以局部或整体调整。
  • 曲线能保持平滑。
  • 可以用统一算法生成许多不同形状。

Bezier 曲线就是最经典的控制点曲线之一。


一条 nn 次 Bezier 曲线由 n+1n+1 个控制点决定:

P0,P1,...,PnP_0, P_1, ..., P_n

曲线可以写成 Bernstein 多项式形式:

B(t)=i=0n(ni)(1t)nitiPiB(t) = \sum_{i=0}^{n} \binom{n}{i}(1-t)^{n-i}t^iP_i

其中 t[0,1]t \in [0, 1]

二次 Bezier 曲线有三个控制点:

B(t)=(1t)2P0+2(1t)tP1+t2P2B(t) = (1-t)^2P_0 + 2(1-t)tP_1 + t^2P_2

三次 Bezier 曲线有四个控制点:

B(t)=(1t)3P0+3(1t)2tP1+3(1t)t2P2+t3P3B(t) = (1-t)^3P_0 + 3(1-t)^2tP_1 + 3(1-t)t^2P_2 + t^3P_3

三次 Bezier 非常常见,因为它既足够简单,又能表达丰富形状。SVG 路径、字体轮廓、矢量绘图工具和许多动画曲线都大量使用三次 Bezier。


Bezier 曲线还有一种非常直观的构造方式:反复线性插值。这就是 de Casteljau 算法

以三次 Bezier 为例,先在相邻控制点之间插值:

P01=lerp(P0,P1,t)P_{01} = lerp(P_0, P_1, t) P12=lerp(P1,P2,t)P_{12} = lerp(P_1, P_2, t) P23=lerp(P2,P3,t)P_{23} = lerp(P_2, P_3, t)

再继续插值:

P012=lerp(P01,P12,t)P_{012} = lerp(P_{01}, P_{12}, t) P123=lerp(P12,P23,t)P_{123} = lerp(P_{12}, P_{23}, t)

最后:

B(t)=lerp(P012,P123,t)B(t) = lerp(P_{012}, P_{123}, t)

这个过程只用了线性插值,却生成了平滑曲线。它不仅数值稳定,而且几何意义非常清楚:Bezier 曲线可以看作控制多边形不断“收缩插值”后留下的轨迹。

拖动控制点观察曲线如何变化。橙色点是当前参数 t 对应的曲线点;灰色折线是控制多边形;构造线展示 de Casteljau 算法如何通过连续线性插值得到曲线点。

拖动控制点时,可以观察两个现象:曲线端点固定在 P0P_0 和最后一个控制点上;中间控制点通常不在曲线上,但会影响曲线进入和离开端点的方向。


Bezier 曲线有几个非常实用的性质。

首先,它会经过首尾控制点:

B(0)=P0,B(1)=PnB(0) = P_0,\quad B(1) = P_n

其次,曲线被控制多边形的凸包包围。也就是说,曲线不会跑到控制点围成的整体范围之外太远。这让编辑曲线时更可预测。

第三,端点切线由相邻控制点决定。对于三次 Bezier:

B(0)=3(P1P0)B'(0) = 3(P_1 - P_0) B(1)=3(P3P2)B'(1) = 3(P_3 - P_2)

这解释了为什么矢量绘图工具中,拖动端点旁边的控制柄可以改变曲线进入或离开端点的方向。


单条高次 Bezier 曲线可以表达复杂形状,但高次曲线不容易控制。实际应用中更常见的是把多段低次曲线拼接起来,例如多段三次 Bezier。

拼接时需要关心连续性 (Continuity)

  • C0C^0 连续:两段曲线端点相接,位置连续。
  • C1C^1 连续:端点相接,并且一阶导数方向和大小连续,速度也连续。
  • G1G^1 连续:切线方向连续,但导数大小可以不同,视觉上仍然比较平滑。
  • C2C^2 连续:二阶导数也连续,曲率变化更平滑。

字体轮廓和图标绘制通常至少需要视觉上的切线连续;相机轨迹和机械运动则常常需要更高阶连续性,否则会出现速度或加速度突变。


Bezier 曲线的一个局限是控制点影响范围较大。移动一个控制点可能影响整段曲线。对于复杂模型,设计者更希望“局部修改只影响附近区域”。

B 样条 (B-Spline) 通过分段基函数解决这个问题。它仍然由控制点控制,但每个控制点只影响曲线的一部分区域,因此更适合复杂曲线和曲面建模。

NURBS (Non-Uniform Rational B-Splines) 在 B 样条基础上加入权重和有理表达,能够精确表示圆、椭圆等二次曲线,因此在 CAD、工业设计和精密建模中非常重要。

本章不展开 NURBS 的完整公式,只需要先记住:

  • Bezier 简洁直观,适合讲解和局部曲线段。
  • B 样条更适合长曲线和局部编辑。
  • NURBS 更适合精确工业曲面。

曲线由一个参数 tt 控制,曲面通常由两个参数 uuvv 控制:

P(u,v)=(x(u,v),y(u,v),z(u,v))P(u, v) = (x(u, v), y(u, v), z(u, v))

其中 (u,v)(u, v) 可以理解为曲面上的二维坐标。上一章中 UV 用来访问纹理;在参数曲面中,uuvv 可以直接生成曲面上的空间位置。

例如一个简单平面可以写成:

P(u,v)=P0+uA+vBP(u, v) = P_0 + uA + vB

而更复杂的 Bezier 曲面可以使用二维控制点网格生成:

S(u,v)=ijBi(u)Bj(v)PijS(u, v) = \sum_i \sum_j B_i(u)B_j(v)P_{ij}

这里 PijP_{ij} 是控制点网格,BiB_iBjB_j 是基函数。直观上,曲面就像一张被控制点拉动的弹性薄膜。


参数曲面不仅能给出位置,还能给出切线方向。对曲面 P(u,v)P(u, v) 分别求偏导:

Pu=PuP_u = \frac{\partial P}{\partial u} Pv=PvP_v = \frac{\partial P}{\partial v}

这两个方向分别表示曲面沿 uuvv 方向的变化。曲面法线可以由它们叉乘得到:

N=normalize(Pu×Pv)N = normalize(P_u \times P_v)

这和前面学习的法线、切线空间、TBN 矩阵联系起来了:曲面参数方向可以提供自然的切线和副切线,进而帮助计算法线和纹理映射。


无论曲线和曲面在数学上多么连续,要进入传统实时渲染管线,通常仍要离散化。

曲线会被采样成线段:

P(t0),P(t1),P(t2),...P(t_0), P(t_1), P(t_2), ...

曲面会被采样成顶点网格,再拆成三角形:

(u0, v0) -> P00
(u1, v0) -> P10
(u0, v1) -> P01
(u1, v1) -> P11
quad(P00, P10, P11, P01) -> two triangles

采样密度越高,曲线或曲面越接近真实连续形状,但顶点和三角形数量也越多。实际系统会在质量和性能之间做取舍,有时还会使用自适应细分:弯曲剧烈或靠近相机的地方采样更密,平坦或远处的地方采样更稀。

  1. 确定参数范围:例如 u,v[0,1]u,v \in [0,1]
  2. 按分辨率采样参数点:生成一组规则或自适应的 (u,v)(u, v)
  3. 计算空间顶点:把每个参数点代入 P(u,v)P(u,v)
  4. 计算属性:根据偏导或邻域估计法线、切线和 UV。
  5. 生成三角形索引:把采样网格连接成可渲染三角形。
  6. 送入渲染管线:像普通三角网格一样执行变换、光栅化和着色。

细分曲面 (Subdivision Surface) 从一个粗糙控制网格出发,通过反复细分和调整顶点位置生成更光滑的表面。

直观地说:

  • 控制网格决定整体形状。
  • 每次细分会产生更多顶点和面。
  • 顶点位置根据邻域规则被重新计算。
  • 多次细分后,表面趋向平滑。

这类方法很适合角色、动画和有机形状建模。建模时可以保留较简单的控制网格,渲染时再生成更高细节的表面。它和 Bezier / B 样条一样,体现了一个共同思想:用少量控制结构描述更平滑、更复杂的连续形状


曲线与曲面在图形系统中随处可见:

应用常见表示
字体轮廓二次或三次 Bezier
SVG 图形Bezier 路径
动画缓动一维 Bezier 曲线
相机轨迹样条曲线
道路和轨道分段样条
工业产品外壳NURBS 曲面
角色有机表面细分曲面
实时渲染输出离散三角网格

这些应用看起来不同,但都围绕一个核心问题:如何用可编辑、可计算、可控的方式描述连续形状。


本章介绍了曲线与曲面的基础思想。请重点记住以下结论:

  1. 参数曲线用 P(t)P(t) 描述点随参数变化的轨迹;参数曲面用 P(u,v)P(u,v) 描述二维参数域到三维空间的映射。
  2. Bezier 曲线由控制点决定,常用 Bernstein 多项式或 de Casteljau 线性插值算法计算。
  3. Bezier 曲线经过首尾控制点,中间控制点主要影响切线方向和弯曲趋势。
  4. 分段曲线需要关注连续性,位置连续不等于视觉平滑,切线和曲率连续会带来更自然的连接。
  5. B 样条和 NURBS 更适合复杂曲线曲面与局部编辑;细分曲面则通过反复细分控制网格生成平滑表面。
  6. 连续曲线和曲面进入实时渲染前通常要离散成线段或三角网格,再交给光栅化管线处理。

下一章会回到网格本身,讨论网格处理的基本问题,并引入阴影图如何利用深度信息判断光源可见性。