Manim制作动画之快速上手

本来想着使用亿图生成一张一张图片做成gif来演示算法, 但是最近发现一个演示算法的好东西: Manim. 这是一个python的库, 专门用来生成复杂的数学图形和动画. 那么接下来一段时间我准备和大家分享一下Manim的使用.

这篇文章简单介绍了Manim的使用, 帮助小白快速上手. 接下来, 我们将直接进入实际操作部分.

使用Manim之前需要安装, 执行命令pip install manim即可. 如果对环境搭建有疑问, 可以在网上搜索相关教程. 如果仍有问题, 欢迎留言, 我会考虑撰写一篇详细的环境搭建教程.

画一个圆

新建一个文件create_circle.py

复制下面代码:

from manim import *


class CreateCircle(Scene):
    def construct(self):
        circle = Circle()  # 创建一个圆
        circle.set_fill(PINK, opacity=0.5)  # 设置颜色和透明度
        self.play(Create(circle))  # 在画布上播放创建圆的动画

CreateCircle继承了Scene, Scene就表示一个画布. 类中重写了construct()方法.

Circle是一个Mobject, Mobject就表示一个图形.

所有的动画都要在Scene子类中的重写的construct()中实现.

控制台执行命令:

manim -pql create_circle.py CreateCircle

就可以看到动画了.

从一个正方形转换成圆形

新建一个文件square_to_circle.py

复制下面代码:

from manim import *


class SquareToCircle(Scene):
    def construct(self):
        circle = Circle()  # 创建一个圆
        circle.set_fill(PINK, opacity=0.5)  # 设置颜色和透明度

        square = Square()  # 创建一个正方形
        square.rotate(PI / 4)  # 逆时针旋转45度

        self.play(Create(square))  # 播放动画: 创建正方形
        self.play(Transform(square, circle))  # 播放动画: 正方形转换成圆
        self.play(FadeOut(square))  # 播放动画: 正方形消失

注意代码第14行传入的参数是square而非circle. 因为13行执行的转换代码是让square对象的形状变成圆形, 而非指向了一个新对象.

Square和Circle一样都是Mobject的子类.

Create, Transform, FadeOut. 都是Animation的子类.

控制台执行命令:

manim -pql square_to_circle.py SquareToCircle

动画:

定位Mobject

新建一个文件square_and_circle.py

复制下面代码:

from manim import *


class SquareAndCircle(Scene):
    def construct(self):
        circle = Circle()
        circle.set_fill(PINK, opacity=0.5)

        square = Square()
        square.set_fill(BLUE, opacity=0.5)

        # 正方形在圆的右面
        # RIGHT表示正方形在圆的右面. 其他可选值: LEFT, UP, DOWN
        # buff=0.5表示使用一个小的距离缓冲
        square.next_to(circle, RIGHT, buff=0.5)

        self.play(Create(circle), Create(square))  # 同时播放两个动画: 创建圆, 创建正方形

Scene类的play()方法同时传入2个Animation对象就表示同时执行2个动画.

控制台执行命令:

manim -pql square_and_circle.py SquareAndCircle

动画:

使用.animate让静态变成动态

新建一个文件animate.py

复制下面代码:

from manim import *


class AnimatedSquareToCircle(Scene):
    def construct(self):
        circle = Circle()
        square = Square()

        self.play(Create(square))
        self.play(square.animate.rotate(PI / 4))  # 播放动画: 将正方形逆时针旋转45度
        self.play(Transform(square, circle))
        self.play(square.animate.set_fill(PINK, opacity=0.5))  # 播放动画: 将圆形上色

.animate是Mobject的方法, 在调用修改Mobject的方法前面添加.animate就会让这个修改变成动画.

控制台执行命令:

manim -pql animate.py AnimatedSquareToCircle

动画:

.animate的怪癖

新建一个文件different_rotations.py

复制下面代码:

from manim import *


class DifferentRotations(Scene):
    def construct(self):
        # shift(2 * LEFT)表示向左移动2个单位
        left_square = Square(color=BLUE, fill_opacity=0.7).shift(2 * LEFT)
        right_square = Square(color=GREEN, fill_opacity=0.7).shift(2 * RIGHT)
        # 第一个参数是.animate实现的动画, 第二个参数是直接使用Animation的子类Rotate实现动画
        # run_time=2 表示动画的持续时间为2秒
        self.play(left_square.animate.rotate(PI), Rotate(right_square, angle=PI), run_time=2)
        # 在动画播放完毕后, 场景会暂停一段时间, 默认是1秒
        self.wait()

控制台执行命令:

manim -pql different_rotations.py DifferentRotations

动画:

奇怪了, 为什么左面的正方形没有旋转呢?

因为当使用.animate时, Manim实际上会获取Mobject的开始状态和结束状态, 并在中间添加过渡效果.

在实际使用时, 如果出现了这种情况, 可以使用传统的Rotate动画对象来产生旋转效果.

Transform 和 ReplacementTransform

Transform和ReplacementTransform都用来表示变换, 区别在于:

  • Transform(a, b)是将图形a的点和颜色等属性转换成图形b的点和颜色等属性.
  • ReplacementTransform是将图形b代替了图形a.

下面的代码, transform()方法和replacement_transform()的效果是一样的.

class TwoTransforms(Scene):
    def transform(self):
        a = Circle()
        b = Square()
        c = Triangle()
        self.play(Transform(a, b))
        self.play(Transform(a, c))
        self.play(FadeOut(a))

    def replacement_transform(self):
        a = Circle()
        b = Square()
        c = Triangle()
        self.play(ReplacementTransform(a, b))
        self.play(ReplacementTransform(b, c))
        self.play(FadeOut(c))

    def construct(self):
        self.transform()
        self.wait(0.5)
        self.replacement_transform()

然而, 在某些场景更推荐使用Transform, 因为可以避免使用变量保存变换后的形状. 示例代码如下:

from manim import *

class TransformCycle(Scene):
    def construct(self):
        a = Circle()
        t1 = Square()
        t2 = Triangle()
        self.add(a)
        self.wait()
        for t in [t1,t2]:
            self.play(Transform(a,t))

总结

  • Mobject表示图形, 它的子类: Circle, Square, Triangle
  • Mobject的方法:
    • set_fill(): 填充颜色, 透明度
    • rotate(): 旋转
    • next_to(): 设置相对位置
    • .animate: 放在Mobject其他方法前面, 让静态变成动态
  • Scene表示画板, 它的方法:
    • play(): 播放动画
    • wait(): 在播放动画过程中暂停
  • Animation表示动画, 它的子类: Create, Transform, FadeOut, ReplacementTransform

如果你觉得本篇内容对你有用, 欢迎关注我的微信公众号: 算法铁金库, 我会持续更新Manim的教程.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值