3Blue1Brown 动画制作教程(9)--变化多端的相机

3Blue1Brown 动画制作教程(9)--变化多端的相机

变化多端的相机


前面的文章中,场景在建立了之后,我们的视角及视野范围往往是不变的,如果需要显示一个局部细节,只能去放大场景中各种对象的尺寸,这样操作起来就显得很不灵活,所以在 manim 中包含了“camera(相机)”的概念。本文的代码参考 Alexander Vázquez 的 Github 中的项目,并对项目中代码进行了分类、简化与释义,形成本文。


相机的定位、缩放及恢复

新建一个 Python 文件,例如名字为 Camera_ex.py。在文件的开头部分写上:

from manimlib.imports import *

将所有生成动画所需的模块导入。

再添加以下代码:

class ChangePositionAndSizeCamera(MovingCameraScene):
    def construct(self):
        text=TexMobject("\\nabla\\textbf{u}").scale(3)
        square=Square()
        # Arrange the objects
        VGroup(text,square).arrange_submobjects(RIGHT,buff=3)

        self.add(text,square)
        # Save the state of camera
        self.camera.frame.save_state()
        # Animation of the camera
        self.play(
            # Set the size with the width of a object
            self.camera.frame.set_width,text.get_width()*1.2,
            # Move the camera to the object
            self.camera.frame.move_to,text
        )
        self.wait()
        # Restore the state saved
        self.play(Restore(self.camera.frame))
        self.play(
            self.camera.frame.set_height,square.get_width()*1.2,
            self.camera.frame.move_to,square
        )
        self.wait()
        self.play(Restore(self.camera.frame))
        self.wait()

该场景继承于 MovingCameraScene 类,而 MovingCameraScene 类又是继承于 Scene 基本场景类。

先新建了一个名为 text 的公式及一个名为 square 的正方形,然后通过 VGroup 将两个对象横向组成一个组合,间距为三个单位。

下面的动画展示部分,先将 text 和 square 添加到页面当中,然后通过 self.camera.frame.save_state() 储存当前的相机位置及视野(场景中的默认相机位置及视野)。

利用 self.play() 方法,先设置相机的宽度为 text 的宽度的1.2倍: self.camera.frame.set_width,text.get_width()*1.2 ,并将相机的中心移动到 text 的中心:self.camera.frame.move_to,text。

等待1秒。

利用 Restore(self.camera.frame) 方法使用刚刚储存的相机位置及视野,恢复到初始的相机的位置及视野。

利用 self.play() 方法,先设置相机的高度为 square 的宽度的1.2倍: self.camera.frame.set_height,square.get_width()*1.2 ,并将相机的中心移动到 square 的中心:self.camera.frame.move_to,square。

等待1秒。

利用 Restore(self.camera.frame) 方法使用刚刚储存的相机位置及视野,恢复到初始的相机的位置及视野。

等待1秒。


动画如下:



相机的缩放与移动

再在下面添加以下代码:

class ChangePositionAndSizeCameraInAnotherScene(GraphScene,MovingCameraScene):
    CONFIG = {
        "y_max" : 50,
        "y_min" : 0,
        "x_max" : 7,
        "x_min" : 0,
        "y_tick_frequency" : 5, 
        "x_tick_frequency" : 0.5, 
    }
    def construct(self):
        self.setup_axes(animate=False)
        graph = self.get_graph(lambda x : x**2,  
                                    color = GREEN,
                                    x_min = 0, 
                                    x_max = 7
                                    )
        dot_at_start_graph=Dot().move_to(graph.points[0])
        dot_at_end_grap=Dot().move_to(graph.points[-1])

        self.add(graph,dot_at_end_grap,dot_at_start_graph)
        self.play(
            self.camera.frame.scale,0.5,
            self.camera.frame.move_to,dot_at_start_graph
        )
        self.wait()
        self.play(
            self.camera.frame.move_to,dot_at_end_grap, run_time = 2
        )
        self.wait()

该场景继承于两个父类,一个是用于构建二维坐标系的场景类 GraphScene,另一个是前面那个例子也用到的 MovingCameraScene 类。

首先用 CONFIG{} 字典,设置了二维坐标系的一些参数。

通过 self.setup_axes(animate=False) 方法设置坐标系显示时为非动画显示。

然后定义了一个 y=x^2 的函数曲线。

通过索引找到函数曲线上的起始点终止点,并在这两个点处分别创建一个图形点。

注意 Python 中的 list 索引号的定义是:list 中的第一个元素的索引号为[0],第二个元素的索引号为 [1],最后一个元素的索引号为[-1],倒数第二个元素的索引号为[-2]。

动画部分先将二维函数图及坐标系以及两个点展现出来,然后将相机视野改为默认视野的一半,并将相机中心置于函数起始点处,并以动画形式展现这部分的变化过程。

等待1秒。

再将相机中心移动到函数终止点处,相机视野大小不变,并以动画形式展现这部分的变化过程。

等待1秒。


动画如下:


小结

利用相机可以灵活地操作场景的视野范围及位置,对于后面将要介绍的三维坐标系场景而言,还可以通过定义相机的参数改变观察视角,使得画面看起来变化莫测,局部显示效果更加流畅。


3B1B 动画制作教程持续更新中...


更多内容请关注知乎专栏:

#原创文章,知乎首发,

未经允许,不得转载#

编辑于 2020-03-26 00:53