You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Manim实现循环闪烁圆点动画遇黑帧问题求助

Manim圆点闪烁动画黑帧问题修复

问题描述

我想用Manim制作一个圆点闪烁动画:圆点瞬间显示后保持可见t_on秒,随后瞬间隐藏并保持不可见t_off秒,循环至总时长t_total结束。但按以下代码生成的动画只有黑帧,没有内容。示例参数:t_on=1.5、t_off=0.5、t_total=6。

错误代码

from manim import *

class RecursiveDot(Scene):
    def construct(self):
        dot = Dot(color=BLUE, radius=0.2)

        animation = self.create_animation(dot, 6, 1.5, 0.5)

        self.play(animation)

    def create_animation(self, dot, total_duration, visible_duration, invisible_duration):
        num_cycles = int(total_duration // (visible_duration + invisible_duration))
        
        visible_animation = Create(dot, run_time=0)
        invisible_animation = Uncreate(dot, run_time=0)

        animations = []

        for _ in range(num_cycles):
            animations.append(visible_animation)
            animations.append(Wait(invisible_duration))
            animations.append(invisible_animation)
            animations.append(Wait(visible_duration))

        return AnimationGroup(*animations, run_time=total_duration)

生成命令:

manim -p -ql path_to_file.py RecursiveDot

问题原因

  1. 动画执行逻辑错误:AnimationGroup是并行执行所有传入的动画和等待动作,导致显示、隐藏、等待同时触发,画面无有效内容。
  2. 循环顺序颠倒:原代码显示圆点后等待t_off、隐藏后等待t_on,完全不符合需求逻辑。
  3. 重复使用动画实例:同一个Create/Uncreate实例被多次复用,可能引发状态冲突,无法正确触发动画。

修复方案

方案一:直接控制可见性(推荐)

通过修改圆点的visible属性实现瞬间显示/隐藏,逻辑清晰且高效:

from manim import *

class RecursiveDot(Scene):
    def construct(self):
        dot = Dot(color=BLUE, radius=0.2)
        self.add(dot)  # 将圆点添加到场景
        dot.visible = False  # 初始状态设为隐藏

        t_on = 1.5
        t_off = 0.5
        t_total = 6
        cycle_duration = t_on + t_off
        num_cycles = int(t_total // cycle_duration)

        # 执行完整循环
        for _ in range(num_cycles):
            dot.visible = True
            self.wait(t_on)
            dot.visible = False
            self.wait(t_off)
        
        # 处理总时长剩余的部分
        remaining_time = t_total % cycle_duration
        if remaining_time > 0:
            dot.visible = True
            self.wait(min(remaining_time, t_on))
            if remaining_time > t_on:
                dot.visible = False
                self.wait(remaining_time - t_on)

方案二:使用Succession串行执行动画

如果坚持用动画类实现,将AnimationGroup替换为Succession(串行执行动画序列),同时修正循环顺序:

from manim import *

class RecursiveDot(Scene):
    def construct(self):
        dot = Dot(color=BLUE, radius=0.2)
        t_on = 1.5
        t_off = 0.5
        t_total = 6
        cycle_duration = t_on + t_off
        num_cycles = int(t_total // cycle_duration)

        animations = []
        for _ in range(num_cycles):
            # 每次循环创建新的动画实例,避免状态冲突
            animations.append(Create(dot, run_time=0))
            animations.append(Wait(t_on))
            animations.append(Uncreate(dot, run_time=0))
            animations.append(Wait(t_off))
        
        # 用Succession按顺序执行所有动画
        self.play(Succession(*animations))
        
        # 处理剩余时长
        remaining_time = t_total % cycle_duration
        if remaining_time > 0:
            self.play(Create(dot, run_time=0))
            self.wait(min(remaining_time, t_on))
            if remaining_time > t_on:
                self.play(Uncreate(dot, run_time=0))
                self.wait(remaining_time - t_on)

说明

  • 方案一直接操作可见性,无需创建动画实例,性能更优,逻辑也更直观。
  • 方案二的核心是用Succession替代AnimationGroup,确保动画按顺序执行,这是解决原代码黑帧问题的关键。
  • 两种方案都补充了剩余时长的处理,保证动画严格覆盖t_total的总时长。

内容的提问来源于stack exchange,提问作者Meysam Sadeghi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 21:47:29