ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

manim入门指南:用Python代码创建数学动画的完整教程

manim入门指南:用Python代码创建数学动画的完整教程 1. manim 是什么它不只是一个动画工具而是一套用代码讲数学的语言接触 manim 的人绝大多数是因为看了 3Blue1Brown 的数学视频——那些流畅旋转的立体图形、逐步推导的公式、恰到好处的镜头切换让很多人第一次意识到数学原来可以这样演出来。manim 正是这套视频背后的动画引擎。我第一次看到 manim 渲染出的效果时第一反应是这玩意儿到底怎么做到让公式自己动起来的第二反应才是我也想试试。manim 的全称是 Mathematical Animation Engine直译过来就是数学动画引擎。它用 Python 描述场景再用内部的渲染管线把描述变成视频。换句话说你写的是场景脚本manim 负责把脚本翻译成一帧一帧的动画画面。它的价值不在于能画图而在于能用代码精确控制动画的每一个时间点、每一个空间位置适合做数学教学演示、科普视频、论文汇报动画以及任何需要把抽象概念具象化的场景。适合谁来学三类人最值得上手数学老师、物理老师想把抽象概念变成课堂上的动态演示科普视频作者、B 站/YouTube 内容创作者需要大量数学动画素材程序员或数据科学从业者想给博客、公众号、内部分享配上可视化讲解。如果你是零编程基础的文科生或学生也不用慌manim 的 Python API 足够简单只要会函数调用、对象创建就能写出第一个动画。这篇文章我从最核心的基本概念讲起先帮你把 manim 的世界观建立起来再带你写第一个可运行的动画最后把我在实际使用中踩过的坑一并列出来。1.1 为什么用代码写动画而不是直接做视频直接用剪辑软件或者 PPT 的动画功能也能做数学演示但有一个致命问题不可重复。昨天做了一个圆今天想改半径你得重新手动调整想复制同样的运动逻辑到另一个图形上还是得手动来。manim 的思路完全不同——一切对象都由代码定义参数变了动画就变了逻辑复用了动画也就复用了。比如你用 manim 写一个圆的半径从 1 变到 3的动画核心代码只有这么一点from manim import * class CircleRadiusDemo(Scene): def construct(self): c Circle(radius1) self.play(GrowFromCenter(c), run_time2) self.play(c.animate.scale(3), run_time2)想改成半径从 0.5 变到 5改一个数字就行。想加个颜色变换加一行 set_color。这种复用性让数学动画的生产效率远远超过传统视频剪辑方式也让试错成本降到几乎为零。后面我会详细拆解这段代码背后的核心概念。1.2 manim 的版本问题Commutity 版和原版的区别新手最容易踩的第一个大坑就是版本混乱。manim 最早是 3Blue1Brown 本人维护的个人项目API 以from manlib import *这种形式导入后来社区基于原版重构了一个社区版也就是现在用的from manim import *。这三个版本 API 差异很大写代码之前一定先确认你用的是什么版本。当前主流选择是社区版Manim Community EditionPython 包名为manimGitHub 项目地址是ManimCommunity/manim。安装命令是pip install manim。社区版的优势是文档全、bug 修复快、API 设计相对统一我这篇文章全部基于社区版展开。原版只能作为历史参考不建议新项目使用。另外一个需要注意的点是 manim 的版本迭代很快不同小版本之间 API 也会微调。比如Text的字体参数、MathTex的排版方式都有过调整。写代码时最好固定一个大版本比如manim0.18.0这种格式锁依赖避免明天安装的版本和今天写的不兼容。2. 核心概念拆解Scene、Mobject、Animation 和坐标系统manim 的设计并不复杂它的整个核心概念可以浓缩成三个词Scene场景、Mobject可移动对象、Animation动画。理解这三个概念就理解了 manim 的全部骨架。2.1 Scene一切动画发生的舞台Scene 是 manim 的最小运行单元。你写的每个动画类都要继承Scene然后实现construct方法manim 在执行时会调用construct内部的所有指令。可以理解为Scene 是舞台construct 是剧本Mobject 是演员Animation 是演员的动作。class MyScene(Scene): def construct(self): dot Dot(ORIGIN) self.play(Create(dot))当你在终端运行manim render 文件名.py MyScene时manim 会实例化 MyScene执行 construct 方法把所有动作渲染成视频。一个文件里可以定义多个 Scene 类比如你想让两个场景独立渲染成两个视频就定义两个类分别对应不同的 construct 实现。Scene 背后还有几个隐藏的系统机制值得新手了解self.play(*animations)播放动画可以同时传多个动画对象self.wait(duration)画面静止等待单位是秒self.add(mobject)/self.remove(mobject)直接添加或删除画面里的对象不带动画效果self.clear()清空当前场景中所有对象。这些方法是你在 construct 里最常用的调度指令。记住一个原则add/remove是瞬间操作play是动画操作。二者结合能实现先瞬间摆好再动起来的效果。2.2 Mobject所有可视化元素的基类Mobject 是 manim 里最重要的类名全称是 Mathematical Object直译数学对象。圆、线、点、文字、公式、图片统统是 Mobject 的子类。它的继承树大致长这样Mobject ├── VMobject基于向量的对象能显示填充和描边 │ ├── Circle Square Line Arc etc. │ ├── Text Paragraph MarkupText │ ├── MathTex Tex │ └── ... ├── Dot LabeledDot ├── NumberLine Axes Plane ├── ImageMobject ├── ...这里最核心的是VMobject它是所有有形状、可填充、可描边对象的基类。Circle、Square、Line、Text 这些图形对象都继承自 VMobject所以它们都有统一的属性接口set_fill设置填充、set_stroke设置描边、set_color设置颜色、scale缩放、rotate旋转、shift平移等。Mobject 的每一个操作返回的都是对象本身所以可以链式调用sq Square().set_fill(BLUE, opacity0.5).scale(2).shift(UP)这一行创建了一个蓝色半透明、放大 2 倍、上移一个单位长度的正方形。链式调用让代码特别紧凑也是 manim 视频里大量图形的来源。Mobject 还有几个重要的属性和方法.center()把对象移动到画布中央.move_to(point)把对象的中心移动到指定坐标.align_to(reference direction)按指定方向对齐另一个对象.height、.width读取或设置对象的高度、宽度VGroup把多个 Mobject 打包成一个组统一操作。VGroup 特别实用。假设你要画一个由三条线、两个点组成的几何图形把每个元素分别管理很麻烦用 VGroup 包起来后一个shift(UP)就能让整个组一起动。2.3 坐标系统理解 manim 的虚拟世界新手照着教程写代码时经常会看到ORIGIN、UP、LEFT、2 * RIGHT这种写法然后懵了这些是啥坐标原点在哪儿manim 的坐标系统相对抽象但概念非常清楚画布中心是原点0 0 0用常量ORIGIN表示画布是一个宽高比 16:9 的虚拟平面X 轴向右为正Y 轴向上为正默认视图下画布能容纳的坐标范围大约 X 从 -7.1 到 7.1Y 从 -4 到 4常量UP对应 (0 1 0)DOWN对应 (0 -1 0)LEFT对应 (-1 0 0)RIGHT对应 (1 0 0)2 * UP就是把对象向上移动 2 个单位长度。所以dot.move_to(2 * RIGHT 1 * UP)的意思是把点移动到坐标 (2 1 0) 的位置。链式组合就像在拼坐标非常直观。有一个新手常问的问题这个单位长度到底是多大答案是它会根据画布动态缩放你不需要关心具体像素值只需要知道 1 个单位长度大约对应画布宽度的 1/14.2。manim 会自动把你的虚拟坐标映射到最终渲染的像素上。这也是 manim 的一个设计哲学你只在抽象的坐标系里思考不用管渲染细节它全都帮你处理了。我实际用下来的建议是尽量用ORIGIN、UP、RIGHT这种常量来表达位置偏移而不要硬编码(3 2 0)这种具体坐标。原因很简单——如果后面你想整体平移所有元素用常量组合可以直接改一个系数硬编码就得逐个改。2.4 Animation让对象动起来的机制Animation 是 manim 里最魔法的部分。一个对象从 A 点移动到 B 点、从透明变不透明、从圆形变成方形全都是靠 Animation 子类实现的。常见的动画类有动画类作用典型用法Create从无到有画出一个对象画一条线、一个圆FadeIn/FadeOut淡入 / 淡出场景切换GrowFromCenter从中心放大出现展示图形对象Transform把 A 对象平滑变形为 B 对象圆形变成正方形ReplacementTransform替换式变换适合文字/公式公式推导换行Indicate高亮闪烁某个对象强调重点Uncreate从有到无反向消除和 Create 对应每个 Animation 都可以接收参数来控制播放方式run_time持续时间单位秒默认 1 秒rate_func速率函数控制加速、减速如smooth平滑加减速、linear匀速、there_and_back过去再回来lag_ratio多个动画的错开比例用于协调多个对象的动作节奏。这里重点解释rate_func。数学动画和普通视频不一样的地方在于它非常依赖节奏感——公式推导时需要慢速铺垫对象平移时可以快速掠过。manim 默认使用smooth函数即先加速后减速再停下画面看起来比较自然。如果你想做一个匀速移动的效果可以传rate_funclinear。如果想让对象先过去再回来可以用there_and_back。Animating 还有一个高级用法是self.play(obj.animate.some_method())。这种语法太常见了比如self.play(circle.animate.scale(2)) self.play(square.animate.shift(RIGHT))这里的.animate是 manim 提供的语法糖把对象的方法调用转化成动画意思就是以动画的方式执行 scale(2) 或 shift(RIGHT)。它比直接写 Transform 要简洁很多我写代码时更常用这种形式代码可读性也更高。3. 环境准备与第一个动画从安装到跑通全流程概念说完了接下来进入实际操作。这个部分我按自己当初从零开始跑通 manim 的路径来写尽量还原你会遇到的所有环节。3.1 正确的安装姿势pip 装机与系统依赖manim 社区版的安装非常简单核心命令只有一个pip install manim但它有几个系统级依赖缺了会在运行时报错。实际需要的有Python 3.8 或更高版本建议 3.10 以上FFmpeg视频编码工具manim 渲染最后一步要调用它把帧序列合成视频一个 LaTeX 发行版渲染数学公式时必需推荐 TeX Live 或 MiKTeXcairo 相关系统库非必须但会影响某些文本渲染。在 Linux 下你需要用包管理器装 FFmpeg 和部分依赖sudo apt update sudo apt install ffmpeg libcairo2-dev libpango1.0-devmacOS 上用 Homebrewbrew install ffmpeg cairo pangoWindows 上 FFmpeg 需要手动下载并配置环境变量这里就不展开了。安装完成后验证一下是否成功manim --version如果你看到类似Manim Community v0.18.0的输出说明主程序已经装好了。这时候再跑一个最简单的测试文件确认渲染管线没问题。特别提醒别在 Jupyter Notebook 里直接运行 manim 的 Scene 类除非你安装了manim[jupyter扩展包并用专门的内嵌模式。常规做法是写一个.py文件然后在终端用 manim 命令行渲染。3.2 LaTeX 配置渲染数学公式的必要条件manim 最吸引人的能力是渲染数学公式比如MathTex(r\frac{a}{b} c)。这个能力依赖 LaTeX。如果你不装 LaTeX运行包含 MathTex 的代码时会直接报错提示找不到latex命令。Linux 下安装 TeX Live 完整版很大裁剪版足够sudo apt install texlive-latex-extra texlive-fonts-recommendedmacOS / Windows 上建议装 MiKTeX它体积小、按需自动下载宏包对 manim 这种使用场景更友好。安装完 LaTeX 后建议先跑一个最小测试from manim import * class FormulaTest(Scene): def construct(self): formula MathTex(re^{i\pi} 1 0) self.play(Write(formula)) self.wait(1)如果能正常渲染出欧拉公式说明 LaTeX 链路没问题。这里r...表示原始字符串里面的\\会被原样传给 LaTeX这是 manim 的固定写法去掉r前缀会导致转义错误。3.3 代码解剖你好manim 的第一个动画现在我把最开始的 CircleRadiusDemo 扩展成一个稍微完整一点的场景然后逐行解释。先看完整代码from manim import * class FirstScene(Scene): def construct(self): title Text(圆的面积推导思路).to_edge(UP) circle Circle(radius2, colorBLUE) self.play(Write(title)) self.play(Create(circle), run_time2) self.wait(0.5) radius_line Line(circle.center, circle.get_right(), colorYELLOW) self.play(Create(radius_line)) self.wait(0.5) self.play( Indicate(title), Indicate(radius_line), run_time1.5 ) self.wait(2)逐行拆解from manim import *导入社区版全部 APIclass FirstScene(Scene)定义场景类def construct(self):入口方法manim 渲染时会执行它Text(...).to_edge(UP)创建文本对象放到画布上边缘Circle(radius2, colorBLUE)创建半径为 2 的蓝色圆self.play(Write(title))用书写动画让标题逐字出现self.play(Create(circle), run_time2)用绘制动画画出圆形持续 2 秒Line(circle.center, circle.get_right(), colorYELLOW)画一条从圆心到圆右边缘的黄色半径线Indicate(...)让对象高亮闪烁用于强调重点。把这个文件保存为first_scene.py然后在终端运行manim render -pql first_scene.py FirstScene其中-p表示渲染完成后自动播放预览-q表示画质等级l低、m中、h高渲染完成后会生成一个 mp4 文件。如果你看到视频窗口弹出恭喜你的 manim 已经正式跑通了。画质等级对渲染时间影响很大新手调试阶段强烈建议始终用-ql低画质能省下好几倍的时间等最终要出片了再用-qh高画质渲染高分辨率版本。3.4 中文显示让 Text 正确渲染中文的两种方案manim 的中文支持是个老大难问题默认字体不包含中文字符直接Text(你好)大概率渲染成方块或者直接报错。这个问题有成熟的解决方案两种方式任选第一种使用系统字体参数。manim 的Text对象接受font参数你只需要指定一个支持中文的字体名title Text(你好manim, fontNoto Sans CJK SC)前提是你的系统里已经装了该字体。Linux 下可以用fc-list :langzh查看已安装的中文字体macOS 下可以用 PingFang SC 或 STHeitiWindows 下可以用 Microsoft YaHei。第二种注册全局默认字体。如果你的项目里大量使用中文每次写font很啰嗦可以提前设置默认字体from manim import config config.tex_template.add_to_preamble(r\usepackage{ctex})等等这个方式针对的是 MathTex 中的中文Text 场景更推荐直接设置环境变量export MANIM_FONTNoto Sans CJK SC不过这个环境变量在早期版本中不稳定想省心还是建议显式传font。另外一个常被忽略的点如果你的文本中包含中文标点或者特殊符号建议把Text封装成一个全局函数统一传入字体方便后续维护。4. 实操踩坑与排查技巧那些教程不会告诉你的经验这部分是我真正想写的内容。网上关于 manim 的教程很多但大多只教怎么写代码几乎不讲出了问题怎么办。我把自己反复踩过的坑整理成一张速查表希望你能绕开。4.1 版本差异带来的 API 错乱新手最容易遇到的一个报错是AttributeError: module manim has no attribute Circle或者No module named manimlib。前者通常是因为装错了版本装成了原版而不是社区版后者则是因为代码是从原版教程里抄的导入了manimlib包。判断自己装的是哪个版本pip show manim看 Name 和 Version 字段。社区版的 name 是manim原版在 PyPI 上的包名是manimlib。装了原版的先卸载再装社区版pip uninstall manimlib pip install manim另外社区版不同小版本之间也有 API 差异。比如 0.16 到 0.18 之间config.media_dir的行为有变化-p参数在不同版本上表现也不一致。建议项目里固定版本pip install manim0.18.0然后在 README 里记录你用的版本号方便日后复现。4.2 渲染速度太慢怎么调优manim 渲染视频的本质是逐帧渲染图片然后用 FFmpeg 合成视频所以对 CPU 和内存的负担都不小。低画质下一个 10 秒的动画可能只需要几十秒但高画质 复杂公式 大量对象一帧甚至可能耗时上万毫秒这时候就得想办法优化了。我的建议是分层处理写作阶段全程用-ql把画面内容、动画节奏调好确定内容没问题后再单独用-qh渲染最终版如果动画里某个部分特别复杂可以拆成多个 Scene 分别渲染再用剪辑软件拼起来减少不必要的对象数量。比如画一个网格默认 20 条线就够没必要生成 200 条。还有个隐藏技巧config.frame_rate可以手动设置帧率从默认 60fps 降到 30fps渲染时间直接减半。对于数学动画来说30fps 在人眼看来依然流畅但渲染成本大幅下降。在 construct 里或者命令行传入--fps 30都能实现。4.3 调试定位只看一帧别每次都全套渲染每次渲染完整动画等待太久是新手会反复经历的低效状态。manim 提供了一些调试参数配合使用效率翻倍。--save_last_frame只渲染最后一帧相当于截图当前场景状态。适合检查对象位置、颜色、文字是否显示正确--preview渲染完成后自动打开视频文件省去手动找输出目录--formatgif渲染成 GIF 而不是 mp4适合内容分享但画质会差一些-q组合调试时可以用-ql最终出片再换-qh。我个人强烈推荐这样一个工作流写代码 →python 文件名.py快速检查是否有语法错误 →manim render -ql -p 文件名.py SceneName预览动画 → 调整 → 最后manim render -qh 文件名.py SceneName出成品。这套流程顺畅后你几乎不会在调试上浪费超过三分之一的时间。4.4 输出文件去哪了media 目录结构详解很多新手第一次渲染成功后找不到生成的 mp4 在哪里。manim 社区版默认会在当前目录下生成一个media文件夹内部结构按场景类名 版本 画质分层存放。典型的目录结构长这样media/ └── videos/ └── first_scene/ └── 480p15/ └── FirstScene.mp4最外层的videos存视频images存图片tex存 LaTeX 编译产生的中间文件text存文本渲染缓存。这些缓存文件可以删除manim 会在下次渲染时重新生成。如果你磁盘空间紧张直接删掉整个media/videos和media/images目录最省事。不过在多人协作或自动化脚本中依赖默认 media 目录会有隐患——不同机器上生成路径可能不一样。我建议在代码里显式指定输出目录from manim import config config.media_dir ./output放在 construct 之前执行所有渲染产物都会统一输出到./output下。这个习惯越早养成越好。4.5 依赖缺失类错误LaTeX 和 FFmpeg 的排查手册命令行渲染时如果报LatexError十有八九是 LaTeX 没装好。先手动测一下能不能编译latex --version如果提示找不到命令说明 LaTeX 没装或者没加入 PATH。装好后建议重新打开终端否则环境变量不生效。FFmpeg 的问题一般表现为渲染到 100% 后卡住或者报FFmpegMovieWriter相关错误。排查方式ffmpeg -version找不到命令就去装 FFmpeg。某些 Linux 发行版上 ffmpeg 和 ffprobe 是分开的两个包都要装齐manim 合成视频时会同时用到它们。5. 从基本概念到进阶实践下一步该学什么到这里manim 的基本概念你已经摸清了大半Scene 提供舞台Mobject 提供演员Animation 提供动作坐标系定义空间加上一套调试技巧你已经足以写出不少数学演示动画了。接下来可以往这几个方向继续深入Updater 机制让对象持续跟随某个条件自动更新位置或属性适合做物理模拟和函数曲线随参数动态变化的动画三维场景ThreeDScenemanim 支持三维对象能旋转视角、展示立体图形这是 B 站很多数学视频的炫技来源ValueTracker一个用来驱动参数变化的追踪器配合 Updater 可以实现滑块式参数调节、动态变化函数图像自定义相机Camera控制视口的缩放、平移、跟随实现从放大公式细节到拉远看全局的镜头语言音频合成与字幕和剪辑软件配合制作完整的科普视频。我个人在实际使用中最推荐先学ValueTracker和Updater这两个组合能让数学概念随参数连续变化的演示效果直线上升。比如你要讲正弦波随相位变化用 ValueTracker 控制相位几行代码就能做出丝滑的动态波形。再者多用官方文档和示例代码。manim 的官方文档有大量Gallery示例每一段示例都附代码是非常好的学习素材。学习方式建议是模仿 → 改造 → 创造先照着跑通再改参数看效果变化最后自己设计一个小场景这样的路径比纯看书高效得多。最后再分享一个小技巧如果你的目标是给教学视频配音和讲解建议动画节奏不要追求炫技优先保证可理解性——公式变换的过程放慢关键对象用 Indicate 高亮锁定观众的视线镜头移动幅度不要过大。毕竟 manim 的初心是让数学变得更生动而不是让动画变得眼花缭乱。
返回列表