Manim实现线条发光效果
<p>在动画制作中,发光效果是一种非常吸引眼球的视觉元素,它可以为简单的线条增添动态和活力。</p><p>今天,我们将通过<code>Manim</code>框架来实现一个线条的发光效果,并逐步解析代码,让你轻松掌握这个技巧。</p>
<h1 id="准备工作">准备工作</h1>
<p>首先确保安装<code>Manim</code>社区版(<code>ManimCE</code>):</p>
<pre><code class="language-bash">pip install manim
</code></pre>
<h1 id="实现的思路">实现的思路</h1>
<p>要让线条发光,我们需要在基础线条的周围添加一层层的<strong>“发光层”</strong>,并通过动态调整这些发光层的透明度和宽度,来模拟发光的效果。</p>
<p><strong>主要思路和步骤</strong>如下:</p>
<ol>
<li><strong>创建基础线条</strong>:首先绘制一条普通的线条作为发光的基础。</li>
<li><strong>添加发光层</strong>:在基础线条的周围添加多层线条,这些线条将作为发光效果的载体。</li>
<li><strong>动态调整发光层属性</strong>:通过正弦波函数动态调整发光层的透明度和宽度,使其产生闪烁的发光效果。</li>
</ol>
<h1 id="实现的过程">实现的过程</h1>
<p>按照实现的思路,下面逐步来实现:</p>
<h2 id="创建基础线条">创建基础线条</h2>
<pre><code class="language-python">class PulsingGlowLine(Scene):
def construct(self):
# 创建基础直线
line = Line(LEFT, RIGHT, color=BLUE, stroke_width=2).scale(3)
line.set_stroke(width=2)
# 第一阶段:绘制基础直线
self.play(Create(line))
self.wait(0.5)
</code></pre>
<p>其中代码主要含义:</p>
<ul>
<li><code>Line(LEFT, RIGHT, color=BLUE, stroke_width=2)</code>:创建了一条从左到右的蓝色线条,宽度为2。</li>
<li><code>.scale(3)</code>:将线条放大3倍,使其更明显。</li>
<li><code>self.play(Create(line))</code>:使用Create动画将线条绘制到场景中。</li>
<li><code>self.wait(0.5)</code>:暂停0.5秒,让用户有时间看清基础线条。</li>
</ul>
<h2 id="添加发光层">添加发光层</h2>
<pre><code class="language-python"> # 创建发光效果组
glow_group = VGroup()
colors = # 发光颜色序列
num_layers = 12# 发光层数量
# 创建多层发光效果
for i in range(num_layers):
glow = line.copy()
phase = i / num_layers# 相位控制
# 设置发光层属性
glow.set_stroke(
width=5 * (1 - phase) + 2,# 宽度递减
color=colors,
opacity=0,# 初始完全透明
)
glow_group.add(glow)
</code></pre>
<p>其中代码主要含义:</p>
<ul>
<li><code>VGroup()</code>:是一个组合对象,用于管理多个图形对象。</li>
<li><code>colors</code>:是一个颜色列表,用于为发光层指定不同的颜色。</li>
<li><code>num_layers</code>:定义了发光层的数量。</li>
<li>在循环中:通过<code>line.copy()</code>复制基础线条,并调整其宽度、颜色和透明度。</li>
<li><code>width=5 * (1 - phase) + 2</code>:使发光层的宽度从外到内逐渐减小。</li>
<li><code>opacity=0</code>:将发光层的初始透明度设置为完全透明,后续通过动态调整透明度来实现发光效果。</li>
</ul>
<h2 id="动态调整发光层属性">动态调整发光层属性</h2>
<pre><code class="language-python"> # 将发光层放在基础线下方
glow_group.set_z_index(line.z_index - 1)
self.add(glow_group, line)
self.wait()
# 定义更新函数实现脉冲效果
def update_glow(group, dt):
# 使用正弦波生成动态参数
t = self.time * 2# 控制脉冲速度
for i, glow in enumerate(group):
phase = i * 0.15# 相位偏移量
intensity = (np.sin(t + phase) + 1) / 2# 0-1之间波动
# 动态调整属性
glow.set_stroke(
opacity=intensity * 0.5,# 透明度波动
width=5 * intensity + 2,# 宽度波动
)
# 添加持续更新器
glow_group.add_updater(update_glow)
self.wait(6)# 展示6秒动态效果
</code></pre>
<p>其中代码主要含义:</p>
<ul>
<li><code>glow_group.set_z_index(line.z_index - 1)</code>:将发光层放在基础线条的下方,避免遮挡基础线条。</li>
<li><code>update_glow</code>:是一个更新函数,用于动态调整发光层的属性。</li>
<li><code>self.time</code>:是<code>ManimCE</code>内置的时间变量,表示动画播放的时间。</li>
<li><code>np.sin(t + phase)</code>:生成一个在<code>-1</code>到<code>1</code>之间波动的值,通过<code>(np.sin(t + phase) + 1) / 2</code>将其转换为<code>0</code>到<code>1</code>之间的值,作为发光强度<code>intensity</code>。</li>
<li><code>glow.set_stroke(opacity=intensity * 0.5, width=5 * intensity + 2)</code>:动态调整发光层的透明度和宽度,使其产生闪烁的效果。</li>
<li><code>glow_group.add_updater(update_glow)</code>:将更新函数绑定到发光层组,使其在动画播放过程中持续更新。</li>
<li><code>self.wait(6)</code>:让动画展示6秒的发光效果。</li>
</ul>
<h2 id="结束动画">结束动画</h2>
<pre><code class="language-python"> # 移除更新器并保持最终状态
glow_group.remove_updater(update_glow)
self.remove(glow_group)
self.wait()
</code></pre>
<p>代码主要含义:</p>
<ul>
<li><code>glow_group.remove_updater(update_glow)</code>:移除更新函数,停止发光效果的动态变化。</li>
<li><code>self.remove(glow_group)</code>:将发光层组从场景中移除。</li>
<li><code>self.wait()</code>:暂停动画,等待用户手动停止。</li>
</ul>
<p>整个代码运行效果如下:</p>
<p><img src="https://img2024.cnblogs.com/blog/83005/202505/83005-20250517094507080-1134114373.gif" alt="" loading="lazy"></p>
<h1 id="总结">总结</h1>
<p>通过这个文章,我们可以了解到:</p>
<ol>
<li>发光效果 = 多层半透明描边 + 动态属性变化</li>
<li><code>add_updater</code>实现持续动画</li>
<li>三角函数创造平滑波动</li>
<li>相位差产生波浪效果</li>
</ol>
<p>现在尝试修改参数创建你自己的特效吧!</p>
<p>比如,修改发光的颜色,发光的脉冲频率等等。</p><br><br>
来源:https://www.cnblogs.com/wang_yb/p/18880993
頁:
[1]