博客 / 詳情

返回

讓你的動畫“活”過來:Manim 節奏控制指南 (Rate Functions)

你在製作Manim動畫時,是否遇到過這樣的困境?

“代碼寫得天衣無縫,運行流暢,出來的動畫卻總覺得哪裏不對勁?”

雖然物體確實從 A 移動到了 B,但看起來就像是老舊的工業機器人在幹活——僵硬、死板,甚至有點無聊。

其實,你的動畫離 “絲滑”“專業”,往往只差這一個參數的距離:rate_func (速率函數)

今天,我們就來聊聊 Manim 中這個不起眼但至關重要的參數,看看如何通過控制 “時間的流速”,讓你的數學動畫不僅能動,而且動得有節奏、有靈魂。

1. 什麼是 Rate Function?(給時間的進度條)

Manim 中,當你寫下 .animate.shift(RIGHT) 時,默認發生了什麼?

如果你覺得動畫只是簡單的“在 Run Time 時間內移動距離 RIGHT”,那隻對了一半。Rate Function 本質上是動畫完成度與時間的關係

想象一下你在看視頻時的進度條:

  • 輸入 ($ t $):當前時間過去了多少(從 0 到 1,代表 0% 到 100% 的時間)。
  • 輸出 ($ f(t) $):動畫實際上完成了多少(從 0 到 1,代表 0% 到 100% 的進度)。

默認的魔法Smooth

Manim 的默認 rate_funcsmooth
這符合物理世界的慣性定律:起步時慢(加速),中間快,快結束時慢(減速)

這就是為什麼默認的動畫看起來比較自然。

如果我們把它換成 linear(線性),物體就會瞬間以最大速度啓動,最後瞬間急停,看起來就會很像 “PPT 動畫”

2. 常用函數圖鑑:選對“調味料”

Manim內置了一大堆寫好的函數,位於 manim.utils.rate_functions

我們可以把它們看作是給動畫調味的香料。

為了方便演示,我們假設我們要移動一個小球。

2.1. 基礎三劍客

  • linear (勻速)
    • 效果:機械感強,速度恆定。
    • 適用場景:旋轉的齒輪、循環滾動的背景、勻速掃描的雷達。
  • smooth (默認)
    • 效果:兩頭慢,中間快。
    • 適用場景:絕大多數物體的移動、縮放。
  • rush_into / rush_from
    • 效果
      • rush_into: 越走越快,最後“砰”地撞線(只有加速)。
      • rush_from: 一開始很快,慢慢停下來(只有減速)。
    • 適用場景:連續動作的銜接。比如小球飛入畫面停下(rush_from),或者發射出去(rush_into)。

2.2. 動感特效組

  • there_and_back (往返)
    • 效果:走到終點,又原路返回起點。
    • 適用場景:強調某個東西。比如把公式放大一下再縮回去,告訴觀眾“看這裏!”。
  • wiggle (擺動)
    • 效果:像果凍一樣左右晃動一下。
    • 適用場景:表示“錯誤”、“拒絕”或者引起注意。
  • running_start (助跑)
    • 效果:先向後退一點點,然後猛地向前衝。
    • 適用場景:想要表現物體很有力量感,或者像卡通片裏的衝刺效果。

2.3. 物理模擬組

  • ease_out_bounce(落地反彈)
    • 效果:像籃球落地一樣,到底部後彈跳幾次再停下。
    • 適用場景:文字掉落、物體自由落體。

3. 動手寫個 Demo

光説不練假把式。下面的示例代碼可以直觀感受不同函數的區別:

from manim import *


class RateFuncComparison(Scene):
    def construct(self):
        # 定義我們想對比的函數
        funcs = [
            linear,
            smooth,
            rush_from,
            rush_into,
            there_and_back,
            rate_functions.ease_out_bounce,
        ]
        labels = [
            "Linear",
            "Smooth",
            "Rush Into",
            "Rush From",
            "There & Back",
            "Bounce",
        ]

        # 創建圓點和文字
        group = VGroup()
        for i, (func, label_text) in enumerate(zip(funcs, labels)):
            dot = Dot(color=TEAL)
            label = Text(label_text, font_size=20).next_to(dot, LEFT)
            row = VGroup(label, dot)
            group.add(row)

        # 豎直排列
        group.arrange(DOWN, buff=0.5).to_edge(LEFT)
        self.add(group)

        # 製作動畫:讓所有點同時向右移動
        # 注意:我們在這裏分別指定了不同的 rate_func
        anims = []
        for item, func in zip(group, funcs):
            dot = item[1]  # 獲取組裏的 Dot
            anims.append(dot.animate(rate_func=func, run_time=3).shift(RIGHT * 4))

        self.play(*anims)

運行後你會發現,雖然大家的 run_time 都是3秒,移動距離一樣,但“性格”截然不同。


4. 進階:自定義與時間扭曲

作為會 Python 的老手,如果內置函數滿足不了你怎麼辦?

4.1. 自定義函數 (Lambda大法)

rate_func 接受任何一個 Python 函數。

比如,你想做一個簡單的“先慢後快”的加速效果,可以直接用 Lambda

# y = x^2,典型的加速曲線
class CustomRateFuncDemo(Scene):
    def construct(self):
        # 創建一個圓
        circle = Circle(radius=0.5, color=BLUE).shift(LEFT * 2)
        self.add(circle)

        # 使用自定義 rate_func(t**2)讓圓向右移動
        self.play(circle.animate(rate_func=lambda t: t**2).shift(RIGHT * 4), run_time=3)
        self.wait()

4.2. 時間擠壓 (Squish Rate Func)

這是 Manim 中最強大的黑科技之一:squish_rate_func

假設你寫了一個 run_time=6 的動畫,但你希望某個特定的變換(比如變色),

在第 1.2 秒到第 3 秒之間(即整個進度的 0.20.5)由白色變成紅色

在第 3 秒到第 4.8 秒之間(即整個進度的 0.50.8)由紅色變成綠色

你不需要把動畫拆成多段寫,只需要:

class SquishRateFuncDemo(Scene):
    def construct(self):
        # 創建一個圓點
        dot = Dot(color=WHITE).shift(LEFT * 2)
        self.add(dot)

        # 使用UpdateFromAlphaFunc來同時控制位置和顏色變化
        def update_dot(obj, alpha):
            # 位置變化 - 使用默認的linear速率
            obj.move_to(LEFT * 2 + RIGHT * 5 * alpha)

            # 顏色變化 - 使用squish_rate_func控制變色的時間段
            squished_alpha = squish_rate_func(smooth, 0.2, 0.5)(alpha)
            squished_alpha2 = squish_rate_func(smooth, 0.5, 0.8)(alpha)

            if alpha < 0.5:
                obj.set_color(interpolate_color(WHITE, RED, squished_alpha))
            else:
                obj.set_color(interpolate_color(RED, GREEN, squished_alpha2))

        self.play(
            UpdateFromAlphaFunc(dot, update_dot),
            run_time=6,
        )
        self.wait()

這個技巧在製作複雜的多重同步動畫時非常有效!

5. 總結

Manim 不僅僅是動畫工具,它更像是一個導演工具。

  • linear 是為了表現機械、循環。
  • smooth 是為了表現自然、物理。
  • there_and_back / wiggle 是為了引導觀眾的注意力。
  • squish_rate_func 是為了精準控制時間軸。

下次當你的動畫看起來略顯生硬時,不妨停下來想一想:“這個動作的節奏對嗎?是不是該換個 rate function 了?”

user avatar mylxsw 頭像 xiaojiu_625c14980f596 頭像
2 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.