找回密码
 立即注册
首页 业界区 业界 Manim实现水波纹特效

Manim实现水波纹特效

届表 2025-9-21 08:44:04
本文将介绍如何使用ManimCE框架实现一个水波纹特效,让你的数学动画更加生动有趣。
1. 实现原理

水波纹特效通过WaterRipple类实现,这是一个自定义的Animation子类。让我们从代码角度来分析其实现原理:
1.1. 核心数据结构
  1. class WaterRipple(Animation):
  2.     def __init__(
  3.         self, mobject, scene=None, num_ripples=5, max_outer_radius=3,
  4.         min_inner_radius=1, run_time=2, wave_speed=1.0,
  5.         color=BLUE, fade_out=True, **kwargs
  6.     ):
  7.         # 初始化参数设置
  8.         self.num_ripples = num_ripples
  9.         self.max_outer_radius = max_outer_radius
  10.         self.min_inner_radius = min_inner_radius
  11.         self.wave_speed = wave_speed
  12.         self.color = color
  13.         self.fade_out = fade_out
  14.         self.ripples = []
  15.         self.mobject = mobject
  16.         self.scene = scene
  17.         
  18.         # 颜色处理逻辑
  19.         self.color_list = color if isinstance(color, list) else [color] * num_ripples
  20.         if len(self.color_list) < num_ripples:
  21.             self.color_list = self.color_list * (
  22.                 num_ripples // len(self.color_list) + 1
  23.             )
  24.             self.color_list = self.color_list[:num_ripples]
  25.         
  26.         # 创建波纹对象
  27.         for i in range(num_ripples):
  28.             c = Annulus(
  29.                 inner_radius=0, outer_radius=0,
  30.                 color=self.color_list[i], stroke_width=2, fill_opacity=0,
  31.             )
  32.             c.move_to(mobject.get_center())
  33.             self.ripples.append(c)
  34.         
  35.         # 将波纹添加到场景
  36.         if self.scene is not None:
  37.             for ripple in self.ripples:
  38.                 self.scene.add(ripple)
  39.         
  40.         super().__init__(mobject, run_time=run_time, **kwargs)
复制代码
从代码中可以看出,WaterRipple类采用了以下核心设计:

  • 波纹数据结构:使用Annulus(圆环)作为基本波纹单元,通过self.ripples列表存储多个波纹对象
  • 颜色处理:支持单一颜色或渐变色列表,自动处理颜色不足时的循环使用
  • 场景集成:提供可选的scene参数,方便将波纹直接添加到场景中
1.2. 动画插值算法

动画的核心在于interpolate_mobject方法,它定义了动画如何随时间变化:
  1. def interpolate_mobject(self, alpha: float) -> None:
  2.     # 计算每个波纹的半径和透明度
  3.     for i in range(self.num_ripples):
  4.         # 每个波纹有不同的相位偏移
  5.         phase_offset = i * (np.pi / self.num_ripples)
  6.         # 使用正弦函数计算半径和透明度,实现波动效果
  7.         time_progress = (alpha + phase_offset * 0.2) % 1
  8.         radius = self.max_outer_radius * time_progress
  9.         if self.fade_out:
  10.             # 透明度随半径增大而减小,使用正弦函数使淡出更自然
  11.             opacity = max(0, np.sin(time_progress * np.pi))
  12.         else:
  13.             opacity = 1
  14.         # 应用变换,使用对应的颜色
  15.         new_c = Annulus(
  16.             inner_radius=self.min_inner_radius,
  17.             outer_radius=radius,
  18.             color=self.color_list[i],
  19.             stroke_width=2,
  20.             fill_opacity=opacity,
  21.         )
  22.         new_c.move_to(self.mobject.get_center())
  23.         self.ripples[i].become(new_c)
复制代码
这里的关键技术点包括:

  • 相位偏移:通过为每个波纹分配不同的相位偏移,创造出波纹依次扩散的视觉效果
  • 正弦函数插值:使用正弦函数控制透明度变化,实现更自然的淡出效果
  • 动态更新:在每一帧都创建新的Annulus对象并通过become()方法更新波纹的状态
1.3. 资源清理机制

动画结束后,需要清理创建的波纹对象:
  1. def clean_up_from_scene(self, scene: Scene) -> None:
  2.     # 动画结束后清理波纹
  3.     for ripple in self.ripples:
  4.         if ripple in scene.mobjects:
  5.             scene.remove(ripple)
  6.     super().clean_up_from_scene(scene)
复制代码
这个方法确保动画结束后不会在场景中留下多余的对象,保持场景的整洁。
2. 使用示例

下面通过一个完整的示例场景来展示如何使用水波纹特效:
2.1. 单个水波纹效果
  1. # 示例场景:单个水波纹效果
  2. class Example01(Scene):
  3.     def construct(self):
  4.         # 创建中心点
  5.         center_point = ORIGIN
  6.         center_dot = Dot(center_point, color=BLUE, radius=0.1)
  7.         self.play(FadeIn(center_dot))
  8.         self.wait()
  9.         # 应用水波纹动画,使用渐变色效果
  10.         # 创建颜色渐变列表,从蓝色到紫色再到红色
  11.         gradient_colors = [BLUE, TEAL, GREEN, YELLOW, RED]
  12.         self.play(
  13.             WaterRipple(
  14.                 center_dot,
  15.                 scene=self,
  16.                 num_ripples=5,
  17.                 max_outer_radius=2,
  18.                 run_time=4,
  19.                 wave_speed=1.2,
  20.                 color=gradient_colors,  # 使用渐变色列表
  21.                 fade_out=True,
  22.                 stroke_width=1,
  23.             )
  24.         )
  25.         self.wait(2)
复制代码
1.gif

2.2. 使用步骤详解


  • 准备工作:首先导入必要的库
  1. from manim import *
  2. import numpy as np
复制代码

  • 创建中心点:水波纹效果需要一个中心点作为扩散起点
  1. center_point = ORIGIN
  2. center_dot = Dot(center_point, color=BLUE, radius=0.1)
  3. self.play(FadeIn(center_dot))
复制代码

  • 定义颜色方案:可以使用渐变色列表增强视觉效果
  1. gradient_colors = [BLUE, TEAL, GREEN, YELLOW, RED]
复制代码

  • 应用水波纹动画:配置各项参数并播放动画

    • center_dot:波纹中心点对象
    • scene=self:当前场景引用
    • num_ripples=5:波纹数量
    • max_outer_radius=2:最大半径
    • run_time=4:动画运行时间
    • wave_speed=1.2:波纹传播速度
    • color=gradient_colors:使用渐变色列表
    • fade_out=True:启用淡出效果

2.3. 自定义参数调整

根据实际需求,可以调整以下关键参数以获得不同的视觉效果:

  • num_ripples:控制波纹数量,更多的波纹会使效果更密集
  • max_outer_radius:控制波纹扩散范围
  • min_inner_radius:控制波纹的最小内半径
  • run_time:控制动画持续时间
  • wave_speed:控制波纹传播速度
  • color:可以是单一颜色或渐变色列表
  • fade_out:是否启用淡出效果
3. 总结

3.1. 特效特点


  • 视觉效果丰富:支持单一颜色和渐变色,可创建多种视觉风格
  • 高度可定制:提供多个参数调整波纹数量、大小、速度和颜色
  • 实现简洁:基于Manim的Animation类扩展,代码结构清晰易懂
  • 资源管理完善:包含清理机制,避免场景对象堆积
3.2. 使用场景

水波纹特效在以下场景中特别适用:

  • 几何演示:用于展示圆的概念、扩散过程等几何知识
  • 受力分析:模拟波的传播,展示力学中的波动现象
  • 交互反馈:作为点击或其他交互操作的视觉反馈
  • 强调重点:用于强调画面中的特定元素或区域
  • 过渡效果:作为场景切换或元素出现/消失的过渡动画
通过这个简单但功能强大的水波纹特效,可以为你的数学动画增添更多视觉吸引力和专业感。无论是教学演示、科学解释还是艺术创作,都能发挥重要作用。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

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