Manim - 用 Python 做出漂亮的數學動畫
Manim 是一套做數學動畫影片的 Python 函式庫。或許你在 Youtube 看過大佬 3Blue1Brown (Grant Sanderson) 的精美影片:這就是他開發,後來社群 fork 出來維護的
只要你會一點程式,就能簡單做出非常漂亮的影片。我會以程式範例 + 影片結果做 Manim 入門介紹。下面是我簡陋的成果,不過強烈建議去 Manim 官方網站 與 3Blue1Brown 的頻道看看究竟可以做得多精美
- Manim 是一個 python 函式庫
- 是用程式碼當劇本,不是在圖形介面上拖拉元件
- 你用 Manim 附的指令把劇本轉成影片
一個用 Manim 做動畫的程式長得像這樣
### demo.py
from manim import *
DEMO_POINTS_1 = [
(0.8, 4.3), (2.4, 9.7), (3.1, 2.2), (4.1, 5.1), (5.7, 1.5),
(6.3, 8.9), (7.5, 3.4), (8.1, 7.2), (9.8, 6.4), (10.2, 10.1)
]
class ProblemIllustration(Scene):
def construct(self):
ax = Axes(
x_range=[-1, 11, 1],
y_range=[-2, 11, 1],
axis_config={"include_ticks": False, "color": GRAY_D},
tips=True
)
dots = [
Dot(ax.coords_to_point(x, y), radius=DEFAULT_DOT_RADIUS*1.5)
for x, y in DEMO_POINTS_1
]
# Show points in a plane
self.add(ax)
self.play(FadeIn(*dots, runtime=1.0))
from manim import *
就是使用這個函式庫,然後你定義「場景」,也就是 Scene
的子類別。所有影片內容都在 construct()
這個方法裡實作
Manim 有幾種物件,例如實體(演員)跟動畫(怎麼表演)
Axes
(座標軸) 跟Dot
(點) 是實體,創造時決定演員一開始的長相、位置等等FadeIn
(淡入) 是動畫,可以把實體的物件給他:FadeIn 這個物件就代表著「這個實體應該怎麼表演」這個敘述
光是創造物件還不會演出;那只是劇本、指示「有什麼」而已。必須把他們加入場景之中才會動起來
self.add(實體物件)
self.play(動畫物件)
最後再用 manim 的指令把劇本變成影片
$ manim -p demo.py ProblemIllustration
就會出現下面的影片。注意到座標軸是 add
上去,所以影片一開始就出現。而十個點是包在 FadeIn
動畫裡面再以 play
加進去,所以有淡入的效果
為什麼要用 Manim, 要用程式碼寫劇本控制動畫,而不是用其他影片製作軟體拖拉的方式?
因為用程式可以很準確、不用自己換算座標、有幾百個物件也可以幾行程式碼解決
例如要畫三角函數 Sin 曲線、一元二次方程式的圖、坐標系上面的點線…,用 Manim 能非常準確地畫出來,而你只要寫數學式就好
所以反過來,他並不是漫畫、電影那種影片。他是為了數學: Math animation
實體物件創造出來以後,仍能改變他們的屬性,例如要他位置往上移 .shift()
,或是形狀剛好包圍著另外的實體 .surround()
。利用該物件的一些 method, 還可以 chain 起來
# Position text and show
problem_text = MarkupText("4↗ <span foreground='yellow'>or</span> 4↘")
problem_text.shift(UP * 3.2)
self.play(Write(problem_text))
self.wait(1.5)
self.play(Unwrite(problem_text))
# Highlight some points
highlight_points = [
Circle(color=YELLOW).surround(dots[i])
for i in [2, 3, 7, 9]
]
self.play(*[Create(hp) for hp in highlight_points], run_time=0.5)
self.wait()
self.remove(*highlight_points)
self.wait()
要注意,改變屬性並不是動畫,只是補充說明這個實體應該長怎麼樣。例如雖然用了 .shift()
,影片並不會看到文字出現後往上跑的動畫,而是一開始就出現在上方
而 Write
/ Unwrite
跟 Create
都是動畫類別:你會看到文字寫出來的過程跟畫圓圈的過程。注意 Create
並不是創造物件,而是把「畫出來」這件事作成動畫
當你 play
了一個實體物件的動畫時,顯然你也把它加進場景了,所以動畫完畢還是看得到。FadeOut
淡出之類的「動畫」能把物件拿掉,不過如果要直接拿掉的話可以用 .remove()
題外話場景的 .add()
, .remove()
是瞬間的指示不是動畫;如果是本來程式的最後一步,必須在後面多加 .wait()
,也就是讓場景等一秒,攝影機繼續拍才喊卡,才能在影片看到效果
Manim 內建了非常多的動畫 class,抽象掉了很多內部細節操作(你能想像 Write
描邊+填色 把文字由左到右慢慢寫出來 要怎麼做嗎?),不過也有另一種動畫的方式是:操作實體物件的屬性
# ...
dots = [
Dot(ax.coords_to_point(x, y), radius=DEFAULT_DOT_RADIUS*1.5)
for x, y in DEMO_POINTS_1
]
# ...
dots_move = [
dots[i].animate.move_to(
ax.coords_to_point(i+1, 10-i)
)
for i in range(len(dots))
]
self.play(*dots_move)
前面說過,改變實體物件的屬性不是動畫。所以這用到了實體物件的 .animate
例如實體物件本來就有 .move_to()
「移動位置」的方法,那在實體物件後先接 .animate
後面也可以接 .move_to()
,表示要把「移動位置」用動畫呈現出來 – 其實 Manim 的動畫就是把兩個實體物件「內插」(interpolate) 的過程
用 .animate
做動畫的優缺點
- 優點:如果 Manim 沒提供你想要的動畫實作
- 優點:利用
ValueTracker
+.add_updater()
同步控制多個物件的動畫 - 缺點:會有你意料之外的效果
以官方的例子
class Scene4(Scene):
def construct(self):
square_1 = Square(color=BLUE).shift(2 * LEFT)
square_2 = Square(color=GREEN).shift(2 * RIGHT)
self.play(
square_1.animate.rotate(PI),
Rotate(square_2, angle=PI), run_time=2
)
self.play(
square_1.animate.rotate(PI/2),
Rotate(square_2, angle=PI/2), run_time=2
)
self.wait()
看程式,兩個正方形都是旋轉 180 度 (PI),但左邊的是縮小再放大。
因為動畫是把起點到終點的物件形狀先算出來,然後中間用內插的方式,看看形狀每個點從頭到尾怎麼走,畫出來。正方形轉 180 度後看起來還是一樣,只不過「點」都跑到對面,例如在左上做個記號,旋轉後會到右下。
如果沒有指定好中間怎麼走,內插就以為是直線跑:效果看起來像四個角在中間集合後繼續跑到對面,這就是 .animate
而 Rotate
這個動畫類別,實作有考慮每個點的移動路徑,所以最後效果看起來形狀大小都沒有變(同理接下來轉 90 度時,你仔細觀察兩個正方形在途中的大小)
因為動畫是兩個實體物件內插,所以也可以做這種酷炫的變形
class Scene5(Scene):
def construct(self):
square = Square(color=RED, fill_opacity=1)
circle = Circle(color=GREEN, fill_opacity=0.2)
triangle = Triangle(color=BLUE, fill_opacity=0.5)
self.play(ReplacementTransform(square, circle))
self.play(ReplacementTransform(circle, triangle))
官方文件上有更多更酷更實用的例子: https://docs.manim.community/en/stable/examples.html , 上面只是我隨便玩的
總之 Manim 的官方網站與文件寫得滿不錯,感覺得出社群很熱心,有興趣的話一定要看看 https://www.manim.community/
The videos in this page are made using Manim: The Manim Community Developers. (2023). Manim – Mathematical Animation Framework (Version v0.18.0) [Computer software]. https://www.manim.community/