当前位置: 首页 > news >正文

Manim实现水波纹特效

本文将介绍如何使用ManimCE框架实现一个水波纹特效,让你的数学动画更加生动有趣。

1. 实现原理

水波纹特效通过WaterRipple类实现,这是一个自定义的Animation子类。让我们从代码角度来分析其实现原理:

1.1. 核心数据结构

class WaterRipple(Animation):def __init__(self, mobject, scene=None, num_ripples=5, max_outer_radius=3,min_inner_radius=1, run_time=2, wave_speed=1.0,color=BLUE, fade_out=True, **kwargs):# 初始化参数设置self.num_ripples = num_ripplesself.max_outer_radius = max_outer_radiusself.min_inner_radius = min_inner_radiusself.wave_speed = wave_speedself.color = colorself.fade_out = fade_outself.ripples = []self.mobject = mobjectself.scene = scene# 颜色处理逻辑self.color_list = color if isinstance(color, list) else [color] * num_ripplesif len(self.color_list) < num_ripples:self.color_list = self.color_list * (num_ripples // len(self.color_list) + 1)self.color_list = self.color_list[:num_ripples]# 创建波纹对象for i in range(num_ripples):c = Annulus(inner_radius=0, outer_radius=0,color=self.color_list[i], stroke_width=2, fill_opacity=0,)c.move_to(mobject.get_center())self.ripples.append(c)# 将波纹添加到场景if self.scene is not None:for ripple in self.ripples:self.scene.add(ripple)super().__init__(mobject, run_time=run_time, **kwargs)

从代码中可以看出,WaterRipple类采用了以下核心设计:

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

1.2. 动画插值算法

动画的核心在于interpolate_mobject方法,它定义了动画如何随时间变化:

def interpolate_mobject(self, alpha: float) -> None:# 计算每个波纹的半径和透明度for i in range(self.num_ripples):# 每个波纹有不同的相位偏移phase_offset = i * (np.pi / self.num_ripples)# 使用正弦函数计算半径和透明度,实现波动效果time_progress = (alpha + phase_offset * 0.2) % 1radius = self.max_outer_radius * time_progressif self.fade_out:# 透明度随半径增大而减小,使用正弦函数使淡出更自然opacity = max(0, np.sin(time_progress * np.pi))else:opacity = 1# 应用变换,使用对应的颜色new_c = Annulus(inner_radius=self.min_inner_radius,outer_radius=radius,color=self.color_list[i],stroke_width=2,fill_opacity=opacity,)new_c.move_to(self.mobject.get_center())self.ripples[i].become(new_c)

这里的关键技术点包括:

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

1.3. 资源清理机制

动画结束后,需要清理创建的波纹对象:

def clean_up_from_scene(self, scene: Scene) -> None:# 动画结束后清理波纹for ripple in self.ripples:if ripple in scene.mobjects:scene.remove(ripple)super().clean_up_from_scene(scene)

这个方法确保动画结束后不会在场景中留下多余的对象,保持场景的整洁。

2. 使用示例

下面通过一个完整的示例场景来展示如何使用水波纹特效:

2.1. 单个水波纹效果

# 示例场景:单个水波纹效果
class Example01(Scene):def construct(self):# 创建中心点center_point = ORIGINcenter_dot = Dot(center_point, color=BLUE, radius=0.1)self.play(FadeIn(center_dot))self.wait()# 应用水波纹动画,使用渐变色效果# 创建颜色渐变列表,从蓝色到紫色再到红色gradient_colors = [BLUE, TEAL, GREEN, YELLOW, RED]self.play(WaterRipple(center_dot,scene=self,num_ripples=5,max_outer_radius=2,run_time=4,wave_speed=1.2,color=gradient_colors,  # 使用渐变色列表fade_out=True,stroke_width=1,))self.wait(2)

2.2. 使用步骤详解

  1. 准备工作:首先导入必要的库
from manim import *
import numpy as np
  1. 创建中心点:水波纹效果需要一个中心点作为扩散起点
center_point = ORIGIN
center_dot = Dot(center_point, color=BLUE, radius=0.1)
self.play(FadeIn(center_dot))
  1. 定义颜色方案:可以使用渐变色列表增强视觉效果
gradient_colors = [BLUE, TEAL, GREEN, YELLOW, RED]
  1. 应用水波纹动画:配置各项参数并播放动画
    • 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. 特效特点

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

3.2. 使用场景

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

  1. 几何演示:用于展示圆的概念、扩散过程等几何知识
  2. 受力分析:模拟波的传播,展示力学中的波动现象
  3. 交互反馈:作为点击或其他交互操作的视觉反馈
  4. 强调重点:用于强调画面中的特定元素或区域
  5. 过渡效果:作为场景切换或元素出现/消失的过渡动画

通过这个简单但功能强大的水波纹特效,可以为你的数学动画增添更多视觉吸引力和专业感。无论是教学演示、科学解释还是艺术创作,都能发挥重要作用。

http://www.hskmm.com/?act=detail&tid=11724

相关文章:

  • 深入解析:解锁AI智能体:上下文工程如何成为架构落地的“魔法钥匙”
  • JS之使用for...of赋值失败的原因分析
  • String
  • Linux /lib/modules/$(uname -r)/ 目录功能作用详解
  • 《建筑的永恒之道》第 27 章:道之核心
  • 软件工程第二次作业_个人项目
  • Linux命令大全(档案管理)
  • 小狼毫雾凇拼音安装部署
  • Chapter 3 Resize and Cropping
  • 详细介绍:java中常见的几种排序算法
  • 使用FFmpeg转换m4a
  • 提升多屏监控体验/新增辅屏预览功能/轻松实现跨屏实时监控/支持高达500路多个屏幕同时显示
  • [Java SE/文件系统/IO] 核心源码精讲:java.io.File
  • Linux 内核整体架构详解
  • atoi() - 字符串( ASCLL )转换为整数( int )
  • 02.Python:Flash初步使用
  • 解决Kubernetes集群中master节点无法与node节点通信的策略
  • 从高版本的sqlserver向低版本的sqlserver上复制表和数据的方法
  • 在Ubuntu18.04安装兼容JDK 8的Eclipse集成开发环境
  • 【php】带数组的文件列表生成,返回数组
  • 配置Nginx以支持Websocket连接的方法
  • Extundelete工具恢复数据
  • 重新理解12306:它卖的从来不是“库存”,而是“状态”
  • 基于Python+Vue开发的房产销售管理系统源码+运行步骤
  • 混合架构(SpringCloud+Dubbo)的整合方案与适用场景(一) - 教程
  • 安全技术深度探讨:从鱿鱼皮肤到AI漏洞挖掘
  • 【Bluedroid】A2DP Source 音频流暂停流程解析[3]:AVDTP 协议中 Suspend Accept 响应的处理流程与建立分析(Suspend Accept)
  • 安装WSL
  • 数据建模流程分析
  • 数学笔记