摘要
贝塞尔曲线是一种通过控制点生成光滑曲线的数学工具,常用于游戏开发和图形设计。它可以通过简单的控制点生成复杂的曲线,例如一次贝塞尔曲线是直线,二次和三次贝塞尔曲线则分别由三个和四个控制点生成。贝塞尔曲线的应用广泛,包括角色和物体的平滑运动轨迹、动画插值、路径编辑以及特效绘制等。本文还提供了在Unity、Godot和Unreal Engine中实现贝塞尔曲线的代码示例,展示了其在不同游戏引擎中的实际应用。无论是让角色沿曲线移动,还是创建自然的动画过渡,贝塞尔曲线都是一个强大而灵活的工具。
一、什么是贝塞尔曲线?(故事+比喻)
1. 故事开头:魔法画笔
想象你有一支魔法画笔,只要你在纸上点几个点,这支画笔就能自动画出一条光滑优美的曲线,穿过这些点附近。
这支画笔的魔法,就是贝塞尔曲线!
2. 比喻:拉橡皮筋
- 你在桌上钉了几个钉子(控制点)。
- 用橡皮筋把这些钉子串起来,然后拉紧。
- 橡皮筋自然形成一条光滑的曲线,这条曲线就是贝塞尔曲线的形象化理解。
二、贝塞尔曲线的推导原理(动画想象+公式)
1. 最简单的:一次贝塞尔曲线(直线)
有两个点P0和P1,t从0到1,点的位置就是:
[
B(t) = (1-t)P_0 + tP_1
]
t=0时在P0,t=1时在P1,中间就是直线。
2. 二次贝塞尔曲线(最常用)
有三个点P0、P1、P2。
动画想象:
- 先在P0和P1之间画一条线,P1和P2之间画一条线。
- t从0到1时,在这两条线上分别找到点A和B:
- A = (1-t)P0 + tP1
- B = (1-t)P1 + tP2
- 再在A和B之间画一条线,t时刻在这条线上找到点C:
- C = (1-t)A + tB
- 点C就是曲线在t时刻的位置!
公式推导:
[
B(t) = (1-t)^2 P_0 + 2(1-t)t P_1 + t^2 P_2
]
3. 三次贝塞尔曲线(最常用)
有四个点P0、P1、P2、P3。
动画想象:
- 先对P0-P1、P1-P2、P2-P3分别做一次插值,得到A、B、C。
- 再对A-B、B-C做一次插值,得到D、E。
- 最后对D-E做一次插值,得到F。
- F就是曲线在t时刻的位置!
公式推导:
[
B(t) = (1-t)^3 P_0 + 3(1-t)^2 t P_1 + 3(1-t)t^2 P_2 + t^3 P_3
]
三、代码演示(Python)
def bezier_quadratic(P0, P1, P2, t):
return (1-t)**2 * P0 + 2*(1-t)*t * P1 + t**2 * P2
def bezier_cubic(P0, P1, P2, P3, t):
return (1-t)**3 * P0 + 3*(1-t)**2 * t * P1 + 3*(1-t) * t**2 * P2 + t**3 * P3
# 例子:三次贝塞尔曲线
P0, P1, P2, P3 = 0, 1, 2, 3 # 这里用一维,二维/三维同理
for t in [0, 0.25, 0.5, 0.75, 1]:
print(bezier_cubic(P0, P1, P2, P3, t))
四、贝塞尔曲线在游戏中的实际作用
1. 角色/物体的平滑运动轨迹
- 让子弹、赛车、飞机、角色等沿着优美的曲线运动,而不是死板的直线。
- 例:弹幕游戏中,子弹沿贝塞尔曲线飞行,轨迹多变又平滑。
2. 动画插值
- 角色动作、UI元素移动、摄像机运动等,贝塞尔曲线让动画过渡自然。
- 例:UI弹窗弹出/收回,按钮点击的弹性动画。
3. 路径编辑器
- 游戏关卡编辑器里,设计师用控制点画出怪物、NPC、摄像机的移动路线。
- 例:塔防游戏中怪物的行进路线。
4. 绘图与特效
- 画笔、激光、绳索、藤蔓等特效,贝塞尔曲线让它们自然弯曲。
- 例:画线小游戏、物理绳索模拟。
五、形象总结
- 贝塞尔曲线就像一根被控制点牵引的橡皮筋,能画出各种优美的曲线。
- 在游戏开发中,贝塞尔曲线是“让一切动起来更自然”的魔法工具,无论是角色运动、动画过渡、路径设计还是特效绘制,都离不开它!
下面我分别用Unity(C#)、Godot(GDScript)、Unreal(蓝图和C++)举例,展示如何在主流游戏引擎中实现和使用贝塞尔曲线。每个例子都以三次贝塞尔曲线为例,二维/三维都适用,便于你直接上手。
1. Unity(C#)实现三次贝塞尔曲线
代码实现
using UnityEngine;
public class BezierCurve : MonoBehaviour
{
public Transform p0, p1, p2, p3; // 四个控制点
// 获取t时刻的曲线点
public Vector3 GetPoint(float t)
{
float u = 1 - t;
return u * u * u * p0.position +
3 * u * u * t * p1.position +
3 * u * t * t * p2.position +
t * t * t * p3.position;
}
// 在Scene视图中可视化曲线
private void OnDrawGizmos()
{
if (p0 && p1 && p2 && p3)
{
Vector3 prev = p0.position;
for (int i = 1; i <= 20; i++)
{
float t = i / 20f;
Vector3 point = GetPoint(t);
Gizmos.color = Color.green;
Gizmos.DrawLine(prev, point);
prev = point;
}
}
}
}
用法
- 新建空物体,挂上脚本。
- 拖入4个控制点(可用空物体表示)。
- 在Scene视图会看到一条绿色的贝塞尔曲线。
实际用途
- 让角色/物体沿曲线运动:
transform.position = bezierCurve.GetPoint(t);
- 路径编辑器、动画插值等。
2. Godot(GDScript)实现三次贝塞尔曲线
代码实现
extends Node2D
export var p0 := Vector2(100, 300)
export var p1 := Vector2(200, 100)
export var p2 := Vector2(400, 100)
export var p3 := Vector2(500, 300)
func _bezier_cubic(t, p0, p1, p2, p3):
var u = 1 - t
return u * u * u * p0 + 3 * u * u * t * p1 + 3 * u * t * t * p2 + t * t * t * p3
func _draw():
var prev = p0
for i in range(1, 41):
var t = i / 40.0
var point = _bezier_cubic(t, p0, p1, p2, p3)
draw_line(prev, point, Color.green, 2)
prev = point
# 可视化控制点
for p in [p0, p1, p2, p3]:
draw_circle(p, 5, Color.red)
用法
- 新建Node2D,挂上脚本。
- 运行后会看到一条绿色的贝塞尔曲线和红色控制点。
- 可通过拖动控制点变量调整曲线形状。
实际用途
- 角色/物体沿曲线运动:
position = _bezier_cubic(t, p0, p1, p2, p3)
- UI动画、路径编辑等。
3. Unreal Engine(蓝图和C++)
蓝图实现(Blueprint)
- 创建变量:添加4个
Vector
变量(P0, P1, P2, P3)。 - 实现贝塞尔公式:
- 用
Lerp
节点实现线性插值。 - 按照三次贝塞尔曲线的分步插值法(De Casteljau算法):
- A = Lerp(P0, P1, t)
- B = Lerp(P1, P2, t)
- C = Lerp(P2, P3, t)
- D = Lerp(A, B, t)
- E = Lerp(B, C, t)
- F = Lerp(D, E, t) // F即为曲线点
- 用
- 可视化:用
Draw Debug Line
节点在Tick中画出曲线。
C++实现
FVector CubicBezier(const FVector& P0, const FVector& P1, const FVector& P2, const FVector& P3, float t)
{
float u = 1 - t;
return u*u*u*P0 + 3*u*u*t*P1 + 3*u*t*t*P2 + t*t*t*P3;
}
- 在Tick或自定义函数中调用,生成曲线点。
实际用途
- 角色/摄像机/特效沿曲线运动。
- 关卡编辑器中可视化路径。
- UI动画、弹道轨迹等。
4. 总结
- Unity:用C#脚本,直接用Transform做控制点,Scene视图可视化。
- Godot:用GDScript,Node2D上画线,变量控制点。
- Unreal:蓝图用Lerp节点拼接,C++直接写公式,Debug Line可视化。
贝塞尔曲线在三大主流引擎中都非常容易实现,且用途极广:运动轨迹、动画插值、路径编辑、特效绘制等。