python-3.x 无法用参数曲线填充manim中的颜色

fhg3lkii  于 2023-05-08  发布在  Python
关注(0)|答案(1)|浏览(159)

我正在创建一个rose。我能够用下面的代码完成它,但由于某种原因,我无法用颜色填充玫瑰。正如你所看到的,我使用set_fill()方法来填充蓝色。但不知何故,在我的终端没有收到填充。我无法解决这个问题。

from manim import *
import numpy as np

class Rose(Scene):
     

        def func(self, t):

            a, k = 2, 10
            x = a*np.cos(k*t)*np.cos(t)
            y = a*np.cos(k*t)*np.sin(t)
            return np.array((x, y, 0))

        def construct(self):
            func = CurvesAsSubmobjects(ParametricFunction(self.func, 
                                        t_range=np.array([0, TAU])))
            func = func.set_color(BLUE).set_stroke(width=1).set_fill(BLUE,opacity=0.5)
            self.play(Create(func.scale(1)), run_time=8)
            self.wait(1)

我得到一个输出,但玫瑰是不是充满了蓝色。谢谢你的帮助Manim版本:v0.17.3和python 3.11

l0oc07j2

l0oc07j21#

问题是CurvesAsSubmobjects()的使用。这个类将ParametricFunction()生成的连续曲线分割成一吨(实际上大约600个)小对象。
当您设置填充颜色时,您是为这些微小对象中的每一个设置,而不是为“全局”曲线设置。这些微小的物体中的每一个都非常薄,以至于它的面积为零,填充颜色无法看到。
因此,解决方案是删除CurvesAsSubmobjects()调用。你为什么把它包括进去?我的猜测是,你这样做是为了避免一个神秘的异常,否则你会得到:

TypeError: cannot pickle '_thread.lock' object

如果您尝试直接为ParametricFunction的创建设置动画,则会发生此错误,如果使用CurvesAsSubmobjects(),则此错误消失。
然而,该异常的真正原因是您传递给ParametricFunction()的函数是Scene的方法,因为您这样定义它:

class Rose(Scene):
        def func(self, t):
            a, k = 2, 10
            x = a*np.cos(k*t)*np.cos(t)
            y = a*np.cos(k*t)*np.sin(t)
            return np.array((x, y, 0))

当你打电话时:

ParametricFunction(self.func, t_range=np.array([0, TAU]))

你传递的是一个属于场景的方法。当Manim试图在内部执行对象的深度复制时(在动画期间发生),这会导致问题。问题是,由于您定义函数的方式,它还必须深度复制场景,而这无法完成,因为场景包含一个记录器。原因是非常技术性和模糊的。
但是你不需要有func()有方法的场景。它可以是一个外部函数,甚至可以是一个在construct()内部定义的内部函数(这并不意味着它是一个方法,因为它与self没有关系)。
所以你的问题的解决方案是:
1.定义func(),使其不是Scene的方法
1.不要使用CurvesAsSubmobjects()
例如:你的代码应该是:

class Test(Scene):
    def construct(self):
        def f(t):
            a, k = 2, 10
            x = a*np.cos(k*t)*np.cos(t)
            y = a*np.cos(k*t)*np.sin(t)
            return np.array((x, y, 0))
        func = ParametricFunction(f, t_range=np.array([0, TAU, 0.1]))
        func = func.set_color(BLUE).set_stroke(width=1).set_fill(BLUE,opacity=0.5)
        self.play(Create(func, run_time=8, rate_func=linear))
        self.wait()

这是可行的,但可能不是你想要的:

我认为你想使用Write()而不是Create(),因为Write()首先绘制轮廓,然后在填充中淡出:

更新

如果你从玫瑰的中心开始绘制,而不是从一个极端开始,Create()也可以很好地工作。可以通过将PI/2添加到cos()组件来实现:

class Test(Scene):
    def construct(self):
        def f(t):
            a, k = 2, 10
            x = a*np.cos(k*t+PI/2)*np.cos(t)
            y = a*np.cos(k*t+PI/2)*np.sin(t)
            return np.array((x, y, 0))
        func = ParametricFunction(f, t_range=np.array([0, TAU, 0.1]))
        func = func.set_color(BLUE).set_stroke(width=1).set_fill(BLUE, opacity=0.5)
        self.play(Create(func, run_time=8, rate_func=linear))
        self.wait()

结果:

相关问题