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

Manim中ReplacementTransform使用疑问:蓝色矩形提前显示

问题

我正在尝试用Manim复刻谷歌Logo,目前遇到的问题是蓝色矩形在ReplacementTransform变换前就已显示。我对ReplacementTransform的理解是,目标对象在变换前不会出现,而是随着动画推进逐步显现,但我的场景中蓝色矩形却提前出现了。请问我的理解是否正确,还是用法有误?

代码示例
from manim import *


class Props:
    blue = "#4285F4"
    red = "#DB4437"
    yellow = "#F4B400"
    green = "#0F9D58"

    dot_radius = 0.5

    arc_inner_radius = 1
    arc_outer_radius = 1.5
    arc_angle = PI / 2

    blue_start_angle = -PI / 4
    red_start_angle = -7 * PI / 4
    yellow_start_angle = -5 * PI / 4
    green_start_angle = -3 * PI / 4


class GoogleLogo(Scene):
    def create_dot(self, color, radius, **kwargs):
        return Dot(color=color, radius=radius, **kwargs)

    def arrange_dots(self, blue, red, yellow, green):
        blue.move_to((-3, 0, 0))
        red.move_to((-1, 0, 0))
        yellow.move_to((1, 0, 0))
        green.move_to((3, 0, 0))

    def annulus_sector(
        self,
        color,
        start_angle,
        angle=PI / 2,
        inner_radius=Props.arc_inner_radius,
        outer_radius=Props.arc_outer_radius,
    ):
        return AnnularSector(
            inner_radius=inner_radius,
            outer_radius=outer_radius,
            color=color,
            fill_opacity=1.0,
            start_angle=start_angle,
            angle=angle,
            stroke_width=0,
        )

    def construct(self):
        blue, red, green, yellow = [
            self.create_dot(c, Props.dot_radius)
            for c in (Props.blue, Props.red, Props.green, Props.yellow)
        ]

        self.arrange_dots(blue, red, yellow, green)

        dots = VGroup(blue, red, yellow, green)

        bounce_animation = [
            AnimationGroup(
                x.animate(rate_func=there_and_back).shift(UP * 0.5),
                x.animate(rate_func=there_and_back).shift(DOWN * 0.5),
            )
            for x in dots
        ]

        for _ in range(1):
            self.play(LaggedStart(*bounce_animation, lag_ratio=0.1))

        # transform dots to letter G
        blue_annulus, red_annulus, yellow_annulus, green_annulus = [
            self.annulus_sector(c, a, ang)
            for c, a, ang in zip(
                [Props.blue, Props.red, Props.yellow, Props.green],
                [
                    Props.blue_start_angle,
                    Props.red_start_angle,
                    Props.yellow_start_angle,
                    Props.green_start_angle,
                ],
                [PI / 4] + [PI / 2] * 3,
            )
        ]
        dots_minus_blue = VGroup(red, yellow, green)
        sectors_minus_blue = VGroup(red_annulus, yellow_annulus, green_annulus)

        transformations = [
            ReplacementTransform(dot, sect, path_func=utils.paths.path_along_arc(-PI))
            for dot, sect in zip(dots_minus_blue, sectors_minus_blue)
        ]

        blue_slab = Rectangle(height=0.5, width=1.5, color=Props.blue, fill_opacity=1)
        blue_slab.next_to(blue_annulus, UP, aligned_edge=UR, buff=0)
        blue_slab.set_stroke(width=0)
        blue_slab.shift(UP * 0.1)
        blue_annulus.set_stroke(width=0)

        dot_to_slab = ReplacementTransform(blue, blue_slab)
        slab_to_annulus = ReplacementTransform(blue_slab.copy(), blue_annulus)

        self.play(
            LaggedStart(
                *transformations,
                Succession(dot_to_slab, slab_to_annulus),
                lag_ratio=0.9
            )
        )

        self.wait(3)
解答

你的理解完全正确:ReplacementTransform的目标对象本应在动画开始前隐藏,随动画进程逐步替换源对象。问题出在两个地方:

  1. 目标对象初始可见:Manim中所有创建的Mobject默认都是可见状态,你创建blue_slab后没有手动隐藏,导致它提前出现在场景中。
  2. 不必要的对象复制:你用blue_slab.copy()做第二次变换,复制出的对象同样默认可见,会和原矩形重叠,进一步加剧提前显示的问题。

修正步骤

  • 创建blue_slab和blue_annulus后,立即设置它们为隐藏状态:set_opacity(0)
  • 第二次变换直接使用原blue_slab,不需要复制,ReplacementTransform会自动处理对象的过渡

修改后的关键代码片段:

blue_slab = Rectangle(height=0.5, width=1.5, color=Props.blue, fill_opacity=1)
blue_slab.next_to(blue_annulus, UP, aligned_edge=UR, buff=0)
blue_slab.set_stroke(width=0)
blue_slab.shift(UP * 0.1)
blue_slab.set_opacity(0)  # 初始隐藏蓝色矩形
blue_annulus.set_stroke(width=0)
blue_annulus.set_opacity(0)  # 初始隐藏蓝色扇形

dot_to_slab = ReplacementTransform(blue, blue_slab)
slab_to_annulus = ReplacementTransform(blue_slab, blue_annulus)  # 移除copy()

ReplacementTransform会在动画启动时自动恢复目标对象的不透明度,完成从源到目标的平滑过渡,这样就不会出现提前显示的问题了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 18:42:03