引言
在游戏中,物体很少做直线运动。为了让移动看起来自然,我们需要曲线。 最著名的曲线莫过于贝塞尔曲线 (Bézier Curve),它广泛应用于路径规划、UI 动画和 3D 建模。
1. 线性插值 (Linear Interpolation)
一切的起点是 Lerp。 \[ P(t) = P_0 + (P_1 - P_0)t = (1-t)P_0 + tP_1 \] 当 \(t\) 从 0 变到 1 时,点从 \(P_0\) 移动到 \(P_1\)。这是一条直线。
2. 二阶贝塞尔曲线 (Quadratic Bezier)
如果我们想要弯曲,就需要引入一个控制点 \(P_1\)。 原理是:对 Lerp 进行 Lerp。
- 在 \(P_0\) 和 \(P_1\) 之间插值得到 \(A\)。
- 在 \(P_1\) 和 \(P_2\) 之间插值得到 \(B\)。
- 在 \(A\) 和 \(B\) 之间插值得到最终点 \(P(t)\)。
公式: \[ P(t) = (1-t)^2 P_0 + 2(1-t)t P_1 + t^2 P_2 \]
3. 三阶贝塞尔曲线 (Cubic Bezier)
这是最常用的形式(例如 Photoshop 的钢笔工具)。它有两个控制点 \(P_1, P_2\)。
公式: \[ P(t) = (1-t)^3 P_0 + 3(1-t)^2 t P_1 + 3(1-t)t^2 P_2 + t^3 P_3 \]
4. 样条曲线 (Splines)
贝塞尔曲线的一个缺点是:曲线不一定经过控制点(除了起点和终点)。 如果我们希望曲线穿过一系列特定的点(例如巡逻路径),我们需要样条曲线。
Catmull-Rom Spline
这是一种常用的样条,它保证曲线经过所有控制点,并且在点处平滑过渡。 计算 \(P_i\) 和 \(P_{i+1}\) 之间的曲线段时,需要用到 \(P_{i-1}\) 和 \(P_{i+2}\) 来计算切线。
代码实现 (Quadratic)
Vector3 GetPoint(Vector3 p0, Vector3 p1, Vector3 p2, float t) {
t = Mathf.Clamp01(t);
float oneMinusT = 1f - t;
return oneMinusT * oneMinusT * p0 +
2f * oneMinusT * t * p1 +
t * t * p2;
}总结
- Lerp 是直线的基石。
- 贝塞尔曲线通过嵌套 Lerp 实现平滑弯曲,控制点决定形状。
- 样条曲线用于连接多个点形成长路径。