Manim動畫久了,你是否厭倦了那萬年不變的黑色虛空?

很多初學者(甚至老手)都想給動畫加個背景圖,但往往會遇到兩個問題:

  1. 怎麼加? 是把圖片放進去,還是設置相機?
  2. 看不清! 背景花裏胡哨,前面的文字公式瞬間“隱身”了。

今天,我們就來揭開Manim動畫中一個簡單卻強大的技巧--為動畫添加背景。

通過幾個小示例,分別演示兩種完全不同的背景處理思路。

1. 舞台佈景法

使用ImageMobject類,這是最直觀、最常用的方法。

它的邏輯是:背景圖片只是舞台上的一個普通演員,只是它長得特別大,而且站得特別靠後。

這種方式的特點是:

  • 高度靈活:背景就是個對象(Mobject),所以它可以動!你可以讓背景旋轉、平移、縮放,甚至改變顏色。
  • 層級管理:需要手動把它的 z_index 設低,或者最先添加它。

下面的第一個示例中,實現一個簡單的動態背景,操作背景和操作一般的Mobject是一樣的。

class Method1ImageMobject(Scene):
    def construct(self):
        # 1. 加載圖片(確保這個圖片是存在的)
        bg = ImageMobject("./assets/紫色夢幻星空.jpg")

        # 2. 核心操作:撐滿屏幕並允許超出
        # 我們把高度設為屏幕高度的 2 倍,這樣才有移動的空間
        bg.scale_to_fit_height(config.frame_height * 2)

        # 3. 核心操作:放到最底層
        bg.set_z_index(-100)

        self.add(bg)

        # 前景物體
        text = Text("方法一:ImageMobject", font_size=40, color=WHITE)
        sub = Text("背景可以動!", font_size=24, color=YELLOW).next_to(text, DOWN)

        self.play(Write(text), FadeIn(sub))

        # 4. 演示優勢:讓背景緩慢移動
        self.play(bg.animate.shift(LEFT * 2), rate_func=linear)
        self.play(bg.animate.shift(UP * 2), rate_func=linear)
        self.play(bg.animate.shift(RIGHT * 2), rate_func=linear)
        self.play(bg.animate.shift(DOWN * 2), rate_func=linear)
        self.wait()

manim的一些進階方法_manim arc_改變顏色

下面的示例也很簡單,就是顯示一段簡單的公式。

不過,大家可以比較看看,相比於默認的黑色背景,加一個學校的黑板背景,是不是更有親和力?

class Method2ImageMobject(Scene):
    def construct(self):
        # 1. 加載圖片
        bg = ImageMobject("./assets/黑板.jpg")

        # 2. 調整大小鋪滿屏幕
        bg.scale_to_fit_height(config.frame_height)
        bg.scale_to_fit_width(config.frame_width)

        # 3. 核心操作:放到最底層
        bg.set_z_index(-100)
        self.add(bg)

        # 前景物體
        math = MathTex(r"\int_0^\infty e^{-x^2} dx = \frac{\sqrt{\pi}}{2}")
        self.play(Write(math))

manim的一些進階方法_manim arc_加載圖片_02

2. 主角光環法

除了上面兩種,還有一種比較特殊的方式,也就是BackgroundColoredVMobjectDisplayer類。

它是一個負責渲染的類,專門處理一種特殊情況:當物體擁有“背景色描邊”時,如何遮擋住它背後的東西

我們通過 set_background_stroke() 來調用這個機制。

嚴格來説不是 “設置全屏背景”,而是 “給物體加一個局部背景(Matte)”,這是在花哨背景下生存的必備技能。

它的特點是:

  • 局部遮擋:在文字或公式周圍生成一圈不透明的輪廓。
  • 增強對比:專門用於解決“背景太花,文字看不清”的問題。

下面的示例故意構造了一個混亂的背景,然後比較看看,這兩個一樣的公式,是不是加了局部背景的公式更加清晰。

class ReadableFormulaOnImage(Scene):
    def construct(self):
        # 1. 先設置一個很花的背景(這裏為了演示,我們用隨機噪點模擬一張複雜的圖)
        # 實際使用中,請換成你的 image.jpg
        noise = Rectangle(width=16, height=10)
        noise.set_fill(color=[BLUE, RED, GREEN, YELLOW], opacity=0.5)
        # 把它搞得亂一點
        for _ in range(20):
            line = Line(
                start=[np.random.uniform(-7, 7), np.random.uniform(-4, 4), 0],
                end=[np.random.uniform(-7, 7), np.random.uniform(-4, 4), 0],
                color=random_color(),
                stroke_width=5,
            )
            self.add(line)
        self.add(noise)

        # 2. 普通的文字(在花背景下很難看清)
        bad_text = MathTex(r"\frac{-b \pm \sqrt{b^2 - 4ac}}{2a}")
        bad_text.shift(UP)

        # 3. 【核心技巧】使用 BackgroundColoredVMobject 機制
        # set_background_stroke 會給文字加一層“描邊”
        # 這層描邊是不透明的,會利用 Displayer 類遮擋住背景!
        good_text = MathTex(r"\frac{-b \pm \sqrt{b^2 - 4ac}}{2a}")
        good_text.set_background_stroke(color=BLACK, width=8)  # 黑色描邊,寬度設大一點
        good_text.shift(DOWN)

        # 動畫演示對比
        self.play(Write(bad_text))

        self.play(Write(good_text))  # 清晰可見!
        self.wait()

manim的一些進階方法_manim arc_改變顏色_03

3. 兩種方式比較

兩種方式各有自己的應用場景,對比如下:

特性

舞台佈景法

主角光環法

本質

場景中的一個巨大物體

物體自身的描邊屬性

主要用途

動態背景、視差滾動、多層背景

高亮主體、對抗花哨背景

動畫能力

⭐⭐⭐⭐⭐ (極強)

⭐⭐⭐ (跟隨物體運動)

代碼複雜度

中 (需手動調大小/層級)

低 (一行設置)

文檔對應

Mobject

BackgroundColoredVMobjectDisplayer

最佳場景

漂浮的雲、移動的星空

字幕、複雜背景下的公式

4. 總結

簡單來説,如果你想做一段電影感的片頭,背景需要緩慢推移,請用 舞台佈景法

如果你發現文字看不清了,請使用 主角光環法 (set_background_stroke) 給文字加個 “光環”