manim边做边学–动画联动

今天介绍Manim中的动画联动的技巧,在数学动画中,动画联动是常用的功能,

比如讲解平面几何中三角形与圆的位置关系变化,通过动画联动可以让圆沿着三角形的边滚动,或者让三角形的顶点在圆上移动,从而直观地展示内切、外接等几何关系。

总之,通过动画联动,可以将复杂的概念、关系或变化过程以动态的方式展示出来。

这种动态展示比静态的图像或文字描述更具吸引力,能让观众更容易理解抽象的知识。

1. 联动原理

Manim中,每个Mobject对象都有一个add_updater函数,这个函数是实现动画联动的关键。

add_updater这个更新函数会在每一帧渲染之前被调用,用于更新Mobject的属性。

例如,你可以用它来改变一个图形的位置、颜色、大小等属性,从而创建动态的动画效果。

当你有多个Mobject并且希望它们的动画相互关联时,add_updater就非常有用。

比如,你有一个圆形和一个正方形,你想让正方形的位置始终跟随圆形的位置变化,就可以通过为正方形添加一个updater函数,在函数内部根据圆形的位置来更新正方形的位置。

add_updaterMobject类的一个方法。其基本函数原型如下:

add_updater(update_function, index=None, call_updater=False)

其中:

  1. update_function:这是最重要的参数,它是一个可调用对象(通常是一个函数),用于更新Mobject的属性
  2. index:当有多个updater联动函数时,index表示updater的调用顺序
  3. call_updater:是否在被调用后立即执行一次,而不仅仅是在每一帧渲染之前执行

2. 联动示例

示例是最好的学习资料,之前做尺规作图的动画时,模拟圆规动作的动画就是一个联动动画。

下面的示例主要介绍如何通过联动动画来完成其中的圆规动作。

圆规动画目的是画一个 圆弧 ,只是在绘制的圆弧的过程中还需要展示了圆弧的起点,终点,

以及绘制过程中动态更新起点终点之间的线。

首先,定义绘制函数:

```python
def ruler(sc: Scene, p1, p2, color=GREEN, angle=PI, axis=OUT):
    """
    圆规动画


    Parameters
    ---------
    sc
        绘制动画的场景
    p1
        代表圆规的针,绘制时不动的点
    p2
        代表圆规的笔芯,绘制圆弧的点
    color
        圆弧的颜色,默认绿色
    angle
        绘制圆弧的角度,默认PI,相当于绘制半个圆
    axis
        只有2个值 IN/OUT,分别表示顺时针还是逆时针作弧
    """
    # 省略。。。
    return arc
```

实现动画的思路如下:

  1. 构建3个元素,即:
    1. d1(根据参数中p1坐标绘制的点)
    2. d2(根据参数中p2坐标绘制的点)
    3. dl(连接p1和p2的虚线)
  2. 设置dl的动画,随着 d1d2变化不断重新绘制(这里 d1其实是不会变的)
  3. 再设置圆弧的动画,随着 d2的变动,不断绘制新的圆弧(圆弧就是起点到d2的弧)
  4. 通过 Manim自带的动画函数让 d2先动,其他动画随之运动
  5. 最后删除不必要的元素,只保留圆弧在 场景(sc)中

    ```python
    def ruler(sc: Scene, p1, p2, color=GREEN, angle=PI, axis=OUT):
    d1 = Dot(point=p1, color=RED)
    d2 = Dot(point=p2, color=color)
    dl = DashedLine(d1.get_center(), d2.get_center())

    r = np.linalg.norm(p2 - p1)
    arc = ArcBetweenPoints(p2, p2, stroke_width=2)
    
    dl.add_updater(lambda z: z.become(DashedLine(d1.get_center(), d2.get_center())))
    if np.array_equal(axis, OUT):
        arc.add_updater(
            lambda z: z.become(
                ArcBetweenPoints(
                    p2, d2.get_center(), radius=r, stroke_color=color, stroke_width=2
                )
            )
        )
    if np.array_equal(axis, IN):
        arc.add_updater(
            lambda z: z.become(
                ArcBetweenPoints(
                    d2.get_center(), p2, radius=r, stroke_color=color, stroke_width=2
                )
            )
        )
    
    sc.add(d1, d2, dl, arc)
    sc.play(
        Rotate(
            d2,
            about_point=d1.get_center(),
            axis=axis,
            angle=angle,
            rate_func=linear,
        )
    )
    
    arc.clear_updaters()
    dl.clear_updaters()
    sc.remove(d1, d2, dl)
    return arc
    

    ```

调用这个函数的效果如下:

```python
ruler(self, np.array([-1, 0, 0]), np.array([-1, 1, 0]))
ruler(self, np.array([1, 0, 0]), np.array([1, 1, 0]), axis=IN)
```

manim边做边学--动画联动

画两个圆弧的交叉效果:

```python
ruler(self, np.array([-1, -1, 0]), np.array([1.1, -0.2222, 0]), angle=PI / 3)
ruler(
    self,
    np.array([1, -1, 0]),
    np.array([-1.1, -0.2222, 0]),
    axis=IN,
    angle=PI / 3,
)
```

manim边做边学--动画联动

3. 注意事项

使用add_updater函数时,首先需要注意的是性能问题 ,由于add_updater函数会在每一帧渲染前被调用,所以要避免在updater函数中进行复杂的计算。

例如,在一个场景中有大量的Mobject,如果在updater函数中进行高复杂度的矩阵运算或者嵌套循环来更新每个Mobject的位置,会导致动画渲染速度变慢,甚至可能出现卡顿。

其次,当多个Mobject之间存在复杂的依赖关系并且都使用add_updater方法时,要确保更新函数的逻辑正确。

要注意更新函数内部不要出现无意的无限循环或递归情况。

最后,当动画的某个阶段不再需要updater函数来更新Mobject时,要及时使用remove_updater方法移除更新器。

如果不及时移除不再需要的更新器,可能会导致内存泄漏和资源浪费。

文章整理自互联网,只做测试使用。发布者:Lomu,转转请注明出处:https://www.it1024doc.com/6682.html

(0)
LomuLomu
上一篇 2025 年 1 月 16 日 上午8:33
下一篇 2025 年 1 月 16 日

相关推荐

  • Java笔记(一)内部类

    这是关于我对内部类理解的笔记,可能写的不怎么好,所以虚心接受大佬的指导 内部类(Nested Class) 定义在一个类中的另一个类被叫做内部类(Inner Class), 内部类有四种类型成员内部类、静态内部类、局部内部类、匿名内部类 成员内部类、局部内部类、匿名内部类中 成员内部类 “`java // inner class public class …

    未分类 2025 年 1 月 7 日
    25300
  • python SQLAlchemy ORM——从零开始学习 04 如何过滤(筛选)数据库中的数据

    04 如何过滤(筛选)数据库中的数据 从数据库中获筛选数据主要应用以下几个接口:filter、filter_by、以及 where。前两个在 02已经展开说过,先展开说where接口 前情提要:依赖03提及的model【本质上就是数据库的链接,有可忽视】 当前的数据库表内容如下,仅作例子,不相同根据自身数据库操作即可: 4-1 通过where进行筛选 同时筛…

    2025 年 1 月 15 日
    45700
  • manim边学边做–改变动画速度

    ChangeSpeed类是Manim库中用于修改动画速度的类。 它提供了一种灵活的方式来控制动画的播放速度,使动画在不同时间段内以不同的速度播放,从而创造出更加丰富多样的动画效果。 比如,在创建包含多个元素动画的场景中,通过ChangeSpeed可以精确控制不同元素在不同时间点的移动速度,实现复杂的动画节奏编排。 1. 动画概述 与之前介绍的那些动画类不同,…

    2024 年 12 月 31 日
    36800
  • 『玩转Streamlit』–集成定时任务

    学习了Streamlit了之后,可以尝试给自己的命令行小工具加一个简单的界面。 本篇总结了我改造自己的数据采集的工具时的一些经验。 1. 概要 与常规的程序相比,数据采集任务的特点很明显,比如它一般都是I/O密集型程序,涉及大量网络请求或文件读写,耗费的时间比较长;而且往往是按照一定的时间间隔周期性地执行。 这样的程序对交互性要求不高,所以我之前都是用命令行…

    2025 年 1 月 16 日
    58500
  • 用 Cursor 写出第一个程序

    大家好,我是汤师爷 最近几个月,Cursor迅速走红,成为一款强大的编程助手。Cursor不仅使用简单,而且通过集成各种大模型技术,编程能力一流。 Cursor是什么? Cursor是一个类似VSCode的编辑器,集成了GPT-4、Claude 3.5等LLM模型。它本质上是在VSCode的基础上添加了AI辅助编程功能。 从界面布局到操作方式都与VSCode…

    2025 年 1 月 1 日
    62700

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信