Manim Transform 家族:Transform、ReplacementTransform、MatchingTex 用法与区别
Transform is where Manim beginners lose track of object identity, so this chapter fixes the mental model first: Transform(a, b) mutates a so that it ends up looking like b — afterwards the object on screen is still a, and b was never added. ReplacementTransform(a, b) removes a and inserts b as the new identity. Choose by what you will reference next scene. Then the family tour: TransformFromCopy keeps the original, FadeTransform cross-fades instead of point-morphing, TransformMatchingShapes aligns submobject geometry automatically, and TransformMatchingTex is the star for equation derivations — it matches LaTeX fragments so unchanged parts stay rock-still while moved terms slide. Also covered: .animate chains, shift/rotate/scale shortcuts, clock/counterclockwise variants, and the documented pitfall of mixing .animate on a group and its submobjects in a single play() call.
先搞懂:Transform 之后,对象是谁?
这是 Manim 变换的第一坑。Transform 改变的是"外观",不替换"身份":
sq = Square()
ci = Circle()
self.play(Transform(sq, ci))
# 此后画面上是"长得像圆的 sq", 继续 play(sq.animate...) 才有效
# ci 从未真正出现在画面上
ReplacementTransform 则相反——旧对象销毁,新对象接管画面,之后的操作要对着新对象写:
self.play(ReplacementTransform(sq, ci))
# 此后请操作 ci, sq 已被移除
选择标准:变换完成后你要继续用哪个变量操作,就选对应语义的那个。教学中最常用 ReplacementTransform(公式推导)和 Transform(同概念变形,比如一个方块一直变到结尾)。
家族成员速览
| 动画 | 行为 | 典型用途 |
|---|---|---|
| Transform(a, b) | a 变形为 b 的样子,身份不变 | 同一对象的形变叙事 |
| ReplacementTransform(a, b) | a 消失,b 接管 | 公式推导、状态切换 |
| TransformFromCopy(b, a) | 从 b 的复制体变到 a | "从这个式子提出一项" |
| FadeTransform(a, b) | 交叉淡化,不逐点变形 | 差异太大、变形会乱的场景 |
| TransformMatchingShapes(a, b) | 按子对象几何自动配对 | 普通图形互变 |
| TransformMatchingTex(a, b) | 按 LaTeX 片段配对 | 公式推导首选 |
| ClockwiseTransform | 顺时针路径变形 | 强调旋转关系 |
公式推导:TransformMatchingTex 实战
推导二次方程求根公式的关键两步:
from manim import *
class Derivation(Scene):
def construct(self):
eq1 = MathTex("x^2", "+", "4x", "=", "5")
eq2 = MathTex("x^2", "+", "4x", "+", "4", "=", "5", "+", "4")
eq3 = MathTex("(x+2)^2", "=", "9")
self.play(Write(eq1))
# 配平: 相同片段原地不动, 新增的 +4 从天上长出来
self.play(TransformMatchingTex(eq1, eq2))
self.wait()
self.play(TransformMatchingTex(eq2, eq3))
self.wait()
MatchingTex 按 LaTeX 片段对位:写公式时刻意用空格把"想独立移动的部分"拆成不同片段(如 "x^2", "+", "4x" 三段),变形时未变化的片段纹丝不动——这正是 3b1b 公式动画干净利落的秘密。
TransformFromCopy:留下原件
eq = MathTex("a", "=", "b", "+", "c")
target = MathTex("b")
target.next_to(eq, DOWN)
# 从 eq 里的 b 复制一份飞下来, 原式不变
self.play(TransformFromCopy(eq[2], target))
.animate:属性级变换
不换对象、只改属性时,.animate 比 Transform 干净得多:
self.play(square.animate.scale(1.5).rotate(PI / 4).set_color(RED))
# 移动到某点 / 对齐某物也行
self.play(square.animate.next_to(circle, LEFT, buff=0.5))
官方文档明确的坑(0.22.1 版还在强调):同一次 play() 里,不要对"一个组"和"组内的子对象"同时使用 .animate——插值会互相打架出现残影。要么整组一起动,要么拆成两次 play。
节奏与路径控制
# 指定变形路径弧度: 弧线飞行而不是直线
self.play(TransformFromCopy(a, b), path_arc=-90 * DEGREES)
# 时长与缓动
self.play(Transform(s, c), run_time=2, rate_func=there_and_back)
更多编排手段(LaggedStart、Succession)见动画编排。