Manim贝塞尔曲线:路径生成与平滑处理
引言
在数学可视化领域,贝塞尔曲线(Bezier Curve)是构建平滑路径的核心工具。Manim(Mathematical Animation Engine)作为3Blue1Brown视频背后的动画引擎,提供了强大的贝塞尔曲线支持,让用户能够创建精确的数学动画。本文将深入探讨Manim中贝塞尔曲线的实现原理、使用方法以及高级技巧。
贝塞尔曲线基础
什么是贝塞尔曲线?
贝塞尔曲线是一种参数化曲线,由控制点定义。在Manim中,主要支持两种类型的贝塞尔曲线:
- 二次贝塞尔曲线(Quadratic Bezier):由3个控制点定义(起点、控制点、终点)
- 三次贝塞尔曲线(Cubic Bezier):由4个控制点定义(起点、控制点1、控制点2、终点)
数学表达式
对于n次贝塞尔曲线,其数学表达式为:
$$B(t) = \sum_{i=0}^{n} \binom{n}{i} (1-t)^{n-i} t^i P_i$$
其中 $t \in [0,1]$,$P_i$ 是控制点。
Manim中的贝塞尔曲线实现
核心工具函数
Manim在manimlib/utils/bezier.py中提供了丰富的贝塞尔曲线工具函数:
def bezier(points: Sequence[float | FloatArray] | VectNArray) -> Callable[[float], float | FloatArray]:
"""生成贝塞尔曲线函数"""
if len(points) == 0:
raise Exception("bezier cannot be calld on an empty list")
n = len(points) - 1
def result(t: float) -> float | FloatArray:
return sum(
((1 - t)**(n - k)) * (t**k) * choose(n, k) * point
for k, point in enumerate(points)
)
return result
部分曲线生成
def partial_bezier_points(points: Sequence[Scalable], a: float, b: float) -> list[Scalable]:
"""生成贝塞尔曲线在区间[a,b]上的部分"""
if a == 1:
return [points[-1]] * len(points)
a_to_1 = [
bezier(points[i:])(a)
for i in range(len(points))
]
end_prop = (b - a) / (1. - a)
return [
bezier(a_to_1[:i + 1])(end_prop)
for i in range(len(points))
]
创建贝塞尔曲线
使用VMobject API
Manim通过VMobject类提供了创建贝塞尔曲线的便捷方法:
from manimlib import *
class BezierExample(Scene):
def construct(self):
# 创建二次贝塞尔曲线
curve = VMobject()
curve.start_new_path(LEFT * 3)
curve.add_quadratic_bezier_curve_to(UP * 2, RIGHT * 3)
curve.set_stroke(BLUE, 3)
# 创建三次贝塞尔曲线
cubic_curve = VMobject()
cubic_curve.start_new_path(LEFT * 3 + DOWN)
cubic_curve.add_cubic_bezier_curve_to(
LEFT + UP * 2, # 控制点1
RIGHT + UP * 2, # 控制点2
RIGHT * 3 + DOWN # 终点
)
cubic_curve.set_stroke(RED, 3)
self.add(curve, cubic_curve)
平滑路径生成
Manim提供了自动平滑处理功能:
class SmoothPathExample(Scene):
def construct(self):
# 创建角点路径
points = [LEFT * 3, UP * 2, RIGHT * 3, DOWN * 2, LEFT * 3]
jagged_path = VMobject()
jagged_path.set_points_as_corners(points)
jagged_path.set_stroke(BLUE, 2)
# 自动平滑处理
smooth_path = jagged_path.copy()
smooth_path.make_smooth()
smooth_path.set_stroke(RED, 2)
smooth_path.shift(DOWN * 2)
self.add(jagged_path, smooth_path)
高级贝塞尔曲线技巧
曲线细分与优化
class CurveSubdivisionExample(Scene):
def construct(self):
# 创建复杂曲线
curve = VMobject()
curve.start_new_path(LEFT * 4)
curve.add_cubic_bezier_curve_to(
LEFT * 2 + UP * 3,
RIGHT * 2 + UP * 3,
RIGHT * 4
)
# 细分尖锐曲线(角度阈值30度)
curve.subdivide_sharp_curves(angle_threshold=30 * DEG)
# 添加控制点显示
anchors = curve.get_points()[::2] # 锚点
handles = curve.get_points()[1::2] # 控制点
self.add(curve)
self.add(DotCloud(anchors, color=GREEN, radius=0.1))
self.add(DotCloud(handles, color=YELLOW, radius=0.08))
弧线生成
class ArcExample(Scene):
def construct(self):
# 使用贝塞尔曲线生成弧线
arc = VMobject()
arc.start_new_path(LEFT * 2)
arc.add_arc_to(RIGHT * 2, angle=PI, n_components=8)
arc.set_stroke(PURPLE, 3)
self.add(arc)
贝塞尔曲线在动画中的应用
路径动画
class PathAnimationExample(Scene):
def construct(self):
# 创建贝塞尔曲线路径
path = VMobject()
path.start_new_path(LEFT * 3)
path.add_cubic_bezier_curve_to(
LEFT + UP * 2,
RIGHT + UP * 2,
RIGHT * 3
)
path.set_stroke(WHITE, 2, opacity=0.5)
# 创建沿路径移动的对象
dot = Dot(color=RED)
self.add(path, dot)
# 沿路径移动动画
self.play(MoveAlongPath(dot, path), run_time=3)
形变动画
class MorphingExample(Scene):
def construct(self):
# 创建起始形状(圆形)
circle = Circle(radius=1.5, color=BLUE)
circle.make_smooth()
# 创建目标形状(星形)
star_points = [
np.array([np.cos(angle), np.sin(angle), 0]) *
(1.5 if i % 2 == 0 else 0.6)
for i, angle in enumerate(np.linspace(0, TAU, 10, endpoint=False))
]
star = VMobject()
star.set_points_as_corners(star_points)
star.set_fill(RED, opacity=0.5)
star.make_smooth()
self.play(Transform(circle, star), run_time=2)
性能优化技巧
使用合适的细分级别
class OptimizationExample(Scene):
def construct(self):
# 高质量曲线(更多细分)
high_quality = VMobject()
high_quality.start_new_path(LEFT * 3)
high_quality.add_arc_to(RIGHT * 3, angle=PI, n_components=16)
high_quality.set_stroke(BLUE, 2)
# 低质量曲线(较少细分)
low_quality = high_quality.copy()
low_quality.add_arc_to(RIGHT * 3, angle=PI, n_components=4)
low_quality.set_stroke(RED, 2)
low_quality.shift(DOWN * 2)
self.add(high_quality, low_quality)
批量处理曲线
class BatchProcessingExample(Scene):
def construct(self):
curves = VGroup()
for i in range(5):
curve = VMobject()
curve.start_new_path(LEFT * 3 + UP * (2 - i))
curve.add_cubic_bezier_curve_to(
LEFT + UP * (3 - i),
RIGHT + UP * (3 - i),
RIGHT * 3 + UP * (2 - i)
)
curve.set_stroke(color=[BLUE, GREEN, RED, YELLOW, PURPLE][i], width=2)
curves.add(curve)
# 批量应用平滑处理
curves.make_smooth()
self.add(curves)
常见问题与解决方案
问题1:曲线不平滑
解决方案:
# 确保使用make_smooth()方法
curve.make_smooth()
# 或者增加细分组件数量
curve.add_arc_to(end_point, angle, n_components=12)
问题2:控制点位置不佳
解决方案:
# 使用自动平滑处理
curve.change_anchor_mode("approx_smooth")
# 或者手动调整控制点
handles = curve.get_points()[1::2]
# 手动调整控制点位置...
问题3:性能问题
解决方案:
# 减少细分数量
curve.add_arc_to(end_point, angle, n_components=4)
# 使用简单二次近似
curve.use_simple_quadratic_approx = True
实战案例:复杂路径生成
class ComplexPathExample(Scene):
def construct(self):
# 创建复杂的心形路径
heart_path = VMobject()
# 心形曲线的控制点
points = [
LEFT * 1, LEFT * 2 + UP * 0.5, LEFT * 1.5 + UP * 1.5,
ORIGIN + UP * 2, RIGHT * 1.5 + UP * 1.5, RIGHT * 2 + UP * 0.5,
RIGHT * 1, ORIGIN, LEFT * 1
]
heart_path.set_points_smoothly(points)
heart_path.set_fill(RED, opacity=0.8)
heart_path.set_stroke(WHITE, 2)
self.add(heart_path)
# 添加沿路径移动的动画
dot = Dot(color=YELLOW)
self.play(MoveAlongPath(dot, heart_path), run_time=3)
总结
Manim提供了强大而灵活的贝塞尔曲线支持,从基本的曲线创建到高级的路径处理,都能够满足数学可视化的各种需求。通过掌握本文介绍的技术,你可以:
- 创建各种类型的贝塞尔曲线:二次、三次曲线及其组合
- 实现平滑路径生成:自动处理角点和尖锐曲线
- 优化性能:合理选择细分级别和处理方式
- 创建复杂动画:路径动画、形变动画等
贝塞尔曲线在Manim中的应用不仅限于简单的图形绘制,更是构建复杂数学动画的基础。通过深入理解和熟练运用这些技术,你将能够创建出更加精美和专业的数学可视化内容。
进一步学习
- 探索
manimlib/utils/bezier.py中的更多工具函数 - 研究
manimlib/mobject/types/vectorized_mobject.py中的完整API - 实践不同的曲线组合和动画效果
- 参考3Blue1Brown视频中的曲线应用案例
通过不断实践和探索,你将能够充分发挥Manim贝塞尔曲线的强大功能,创造出令人惊叹的数学动画作品。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



