manim边做边学--动画联动

锦通  金牌会员 | 2025-1-14 08:43:13 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 880|帖子 880|积分 2640

本日先容Manim中的动画联动的本领,在数学动画中,动画联动是常用的功能,
比如讲解平面几何中三角形与圆的位置关系变化,通过动画联动可以让圆沿着三角形的边滚动,或者让三角形的顶点在圆上移动,从而直观地展示内切、外接等几何关系。
总之,通过动画联动,可以将复杂的概念、关系或变化过程以动态的方式展示出来。
这种动态展示比静态的图像或文字描述更具吸引力,能让观众更轻易理解抽象的知识。
1. 联动原理

在Manim中,每个Mobject对象都有一个add_updater函数,这个函数是实现动画联动的关键。
add_updater这个更新函数会在每一帧渲染之前被调用,用于更新Mobject的属性。
例如,你可以用它来改变一个图形的位置、颜色、大小等属性,从而创建动态的动画效果。
当你有多个Mobject而且希望它们的动画相互关联时,add_updater就非常有用。
比如,你有一个圆形和一个正方形,你想让正方形的位置始终跟随圆形的位置变化,就可以通过为正方形添加一个updater函数,在函数内部根据圆形的位置来更新正方形的位置。
add_updater是Mobject类的一个方法。其基本函数原型如下:
add_updater(update_function, index=None, call_updater=False)
此中:

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

示例是最好的学习资料,之前做尺规作图的动画时,模拟圆规动作的动画就是一个联动动画。
下面的示例主要先容如何通过联动动画来完成此中的圆规动作。
圆规动画目的是画一个 圆弧,只是在绘制的圆弧的过程中还需要展示了圆弧的起点,终点,
以及绘制过程中动态更新起点终点之间的线。
首先,定义绘制函数:
  1. def ruler(sc: Scene, p1, p2, color=GREEN, angle=PI, axis=OUT):
  2.     """
  3.     圆规动画
  4.     Parameters
  5.     ---------
  6.     sc
  7.         绘制动画的场景
  8.     p1
  9.         代表圆规的针,绘制时不动的点
  10.     p2
  11.         代表圆规的笔芯,绘制圆弧的点
  12.     color
  13.         圆弧的颜色,默认绿色
  14.     angle
  15.         绘制圆弧的角度,默认PI,相当于绘制半个圆
  16.     axis
  17.         只有2个值 IN/OUT,分别表示顺时针还是逆时针作弧
  18.     """
  19.     # 省略。。。
  20.     return arc
复制代码
实现动画的思路如下:

  • 构建3个元素,即:

    • d1(根据参数中p1坐标绘制的点)
    • d2(根据参数中p2坐标绘制的点)
    • dl(毗连p1和p2的虚线)

  • 设置dl的动画,随着 d1和d2变化不断重新绘制(这里 d1其实是不会变的)
  • 再设置圆弧的动画,随着 d2的变动,不断绘制新的圆弧(圆弧就是起点到d2的弧)
  • 通过 Manim自带的动画函数让 d2先动,其他动画随之运动
  • 最后删除不必要的元素,只保存圆弧在 场景(sc)中
  1. def ruler(sc: Scene, p1, p2, color=GREEN, angle=PI, axis=OUT):
  2.     d1 = Dot(point=p1, color=RED)
  3.     d2 = Dot(point=p2, color=color)
  4.     dl = DashedLine(d1.get_center(), d2.get_center())
  5.     r = np.linalg.norm(p2 - p1)
  6.     arc = ArcBetweenPoints(p2, p2, stroke_width=2)
  7.     dl.add_updater(lambda z: z.become(DashedLine(d1.get_center(), d2.get_center())))
  8.     if np.array_equal(axis, OUT):
  9.         arc.add_updater(
  10.             lambda z: z.become(
  11.                 ArcBetweenPoints(
  12.                     p2, d2.get_center(), radius=r, stroke_color=color, stroke_width=2
  13.                 )
  14.             )
  15.         )
  16.     if np.array_equal(axis, IN):
  17.         arc.add_updater(
  18.             lambda z: z.become(
  19.                 ArcBetweenPoints(
  20.                     d2.get_center(), p2, radius=r, stroke_color=color, stroke_width=2
  21.                 )
  22.             )
  23.         )
  24.     sc.add(d1, d2, dl, arc)
  25.     sc.play(
  26.         Rotate(
  27.             d2,
  28.             about_point=d1.get_center(),
  29.             axis=axis,
  30.             angle=angle,
  31.             rate_func=linear,
  32.         )
  33.     )
  34.     arc.clear_updaters()
  35.     dl.clear_updaters()
  36.     sc.remove(d1, d2, dl)
  37.     return arc
复制代码
调用这个函数的效果如下:
  1. ruler(self, np.array([-1, 0, 0]), np.array([-1, 1, 0]))
  2. ruler(self, np.array([1, 0, 0]), np.array([1, 1, 0]), axis=IN)
复制代码

画两个圆弧的交织效果:
  1. ruler(self, np.array([-1, -1, 0]), np.array([1.1, -0.2222, 0]), angle=PI / 3)
  2. ruler(
  3.     self,
  4.     np.array([1, -1, 0]),
  5.     np.array([-1.1, -0.2222, 0]),
  6.     axis=IN,
  7.     angle=PI / 3,
  8. )
复制代码

3. 留意事项

使用add_updater函数时,首先需要留意的是性能问题,由于add_updater函数会在每一帧渲染前被调用,所以要避免在updater函数中进行复杂的计算。
例如,在一个场景中有大量的Mobject,如果在updater函数中进行高复杂度的矩阵运算或者嵌套循环来更新每个Mobject的位置,会导致动画渲染速度变慢,甚至可能出现卡顿。
其次,当多个Mobject之间存在复杂的依靠关系而且都使用add_updater方法时,要确保更新函数的逻辑正确。
要留意更新函数内部不要出现无意的无限循环或递归情况。
最后,当动画的某个阶段不再需要updater函数来更新Mobject时,要及时使用remove_updater方法移除更新器。
如果不及时移除不再需要的更新器,可能会导致内存泄漏和资源浪费。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

锦通

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表