在Manim中局部缩放的场景类

在动画制作中,尤其是数学和科学可视化领域,有时我们需要将观众的注意力集中在场景的某个特定部分。Manim提供了一个强大的工具 ZoomedScene,它允许我们在场景中创建一个独立的缩放视图,从而实现对局部细节的深入展示。本文将详细介绍ZoomedScene的作用、参数、方法,并通过实际示例展示其强大功能。

1. ZoomedScene概要

ZoomedSceneManim中一个专门用于局部缩放的场景类。其核心功能是允许我们在主场景中创建一个独立的“缩放窗口”,通过这个窗口,可以清晰地展示场景中某个部分的细节。这种设计特别适用于以下场景:

  • 数学公式推导:在展示复杂的数学公式时,可以使用ZoomedScene对公式中的关键部分进行放大,帮助观众更好地理解
  • 科学实验演示:在展示微观现象(如细胞结构、分子运动)时,通过缩放功能,可以让观众更直观地观察细节。
  • 工程设计展示:对于复杂的机械结构或电路设计,ZoomedScene可以帮助观众聚焦于关键部件
  • 教育动画:在教学视频中,通过局部缩放,可以更有效地引导学生关注重点内容

1.1. 主要参数

ZoomedScene的主要参数有:

参数名称 类型 说明
camera_class class 用于定义场景的相机类,默认为MultiCamera。它决定了场景的渲染方式
zoomed_display_height float 缩放窗口的高度,默认值为 3
zoomed_display_width float 缩放窗口的宽度,默认值为 3
zoomed_display_center array 缩放窗口的中心位置,默认为None,表示自动计算
zoomed_display_corner array 缩放窗口在场景中的角落位置,默认为[1, 1, 0],表示窗口位于右上角
zoomed_display_corner_buff float 缩放窗口与角落的距离,默认值为 0.5
zoomed_camera_config dict 缩放相机的配置参数,例如背景透明度和边框宽度
zoomed_camera_image_mobject_config dict 缩放相机图像的配置参数
zoomed_camera_frame_starting_position array 缩放相机的初始位置,默认为[0, 0, 0]
zoom_factor float 缩放比例,默认值为 0.15。它决定了缩放窗口与主场景的比例关系
image_frame_stroke_width float 缩放窗口边框的宽度,默认值为3
zoom_activated bool 是否激活缩放功能,默认为False

1.2. 主要方法

ZoomedScene的主要方法有:

名称 说明
activate_zooming 激活缩放功能
get_zoom_factor 获取当前的缩放比例
get_zoom_in_animation 返回一个缩放动画
get_zoomed_display_pop_out_animation 返回缩放窗口弹出的动画

2. 使用示例

为了更好地理解ZoomedScene的功能,我们将通过四个实际示例展示其特点。

2.1. 公式的局部放大

视频中展示欧拉公式时,在另一个位置中展示公式的局部放大。在讲解复杂的公式时,可以使用这个功能来突出显示其中的正在讲解的参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
from manim import *

class ZoomedFormulaExample(ZoomedScene):
def __init__(self):
super().__init__(
zoomed_display_height=2,
zoomed_display_width=5,
zoomed_display_center=[0, 1.75, 0],
zoomed_camera_config={"default_frame_stroke_width": 1},
image_frame_stroke_width=1,
)
def construct(self):
# 添加标题
title = Text("公式的局部放大", font="STLiti", font_size=25).to_edge(UP).shift(LEFT)
line = Line(LEFT * 3, RIGHT * 5, color=BLUE).next_to(title, DOWN, buff=0.1)
self.play(Write(title), Create(line))
self.wait(0.5)

# 添加公式
formula = MathTex("e^{i\\pi} + 1 = 0").scale(2)
self.play(Create(formula))
self.wait(0.5)

# 激活放大
self.activate_zooming(animate=True)
self.wait(0.5)

# 放大动画
self.play(self.get_zoom_in_animation(run_time=2))
self.wait(2)

实际的显示效果如下:

我感觉这段代码比较有意思

1
2
3
4
5
6
7
8
def __init__(self):
super().__init__(
zoomed_display_height=2,
zoomed_display_width=5,
zoomed_display_center=[0, 1.75, 0],
zoomed_camera_config={"default_frame_stroke_width": 1},
image_frame_stroke_width=1,
)

这段代码实际上就是对方法框的一个设置,可以对应查阅里面的属性,缩放窗口的高度,缩放窗口的宽度,缩放窗口的中心位置,同时,将 __init__ 方法添加到类中,使用 super().__init__() 初始化父类,在 __init__ 方法中传入放大相关的配置参数:

  1. zoomed_display_height=2: 放大显示区域的高度
  2. zoomed_display_width=5: 放大显示区域的宽度
  3. zoomed_display_center=[0, 1.75, 0]: 放大显示区域的中心位置
  4. zoomed_camera_config: 放大相机的配置
  5. image_frame_stroke_width=1: 图像框的边框宽度

2.2. 不同图形的细节

这个示例交互式切换圆形 / 正方形的局部观察。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
from manim import *

class ZoomedShapesExample(ZoomedScene):
def __init__(self, **kwargs):
super().__init__(
zoomed_display_height=2,
zoomed_display_width=5,
zoomed_display_center=[0, 1.75, 0],
zoomed_camera_config={"default_frame_stroke_width": 1},
image_frame_stroke_width=1,
)

def construct(self):
# 创建图形并设置位置
circle = Circle(color=RED).shift(LEFT * 2)
square = Square(color=BLUE).shift(RIGHT * 2)

# 创建标题
title = Text("图形细节演示", font_size=25).to_edge(UP)
self.play(Write(title))

# 显示图形
self.play(Create(circle), Create(square))

# 激活缩放并设置初始位置
self.activate_zooming(animate=True)
zoom_frame = self.zoomed_camera.frame

# 缩放圆形区域
self.play(zoom_frame.animate.move_to(circle))
self.wait(0.5)

# 缩放正方形区域
self.play(zoom_frame.animate.move_to(square))
self.wait()

来看演示的动画效果

2.3. 切换不同的部分

这个示例演示逐步放大图中不同节点的过程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
from manim import *

class ZoomedDotsExample(ZoomedScene):
def __init__(self, **kwargs):
super().__init__(
zoomed_display_height=2,
zoomed_display_width=5,
zoomed_display_center=[0, 1.75, 0],
zoomed_camera_config={"default_frame_stroke_width": 1},
image_frame_stroke_width=1,
)

def construct(self):
# 创建标题
title = Text("切换不同部分", font_size=25).to_edge(UP)
self.play(Write(title))

# 创建三个点
dots = VGroup(
Dot(color=GREEN),
Dot(color=YELLOW),
Dot(color=BLUE)
).arrange(RIGHT, buff=2)

self.play(Create(dots))

# 激活缩放
self.activate_zooming(animate=True)
zoom_frame = self.zoomed_camera.frame

# 依次缩放每个点
for dot in dots:
self.play(zoom_frame.animate.move_to(dot))
self.wait(0.5)

self.wait()

来看演示的效果

我个人更感兴趣的是这个代码

1
for dot in dots:

for...in 循环 是 Python 中的一种循环结构,用于遍历序列(如列表、元组、字符串)或其他可迭代对象的元素。

1
for 变量 in 可迭代对象:
1
2
3
4
5
6
7
8
# 遍历列表
fruits = ["苹果", "香蕉", "橙子"]
for fruit in fruits:
print(fruit)
# 输出:
# 苹果
# 香蕉
# 橙子

有些时候还是要学一学Python语言的基础知识的,虽然AI可以帮助我们写代码,更多的时候我们还是需要自己适当的调整代码,知识储备还是要有的。