manim 中文教程

网友投稿 1488 2022-11-06

manim 中文教程

manim 中文教程

manim基础教程1. 文件的执行1.1 保存为视频并立即播放1.2 保留帧1.3 视频尺寸1.4 视频通道1.5 保留进度显示条1.6 从某一个动画状态(animation)开始存为视频 2. 显示操作2.1 基本步骤(以TextMobject为例)2.5 位置相关的函数2.5.1toedge()和tocorner()2.5.2 moveto()2.5.3 nextto()2.5.4 shift()2.5.5 rotate()2.5.6 flip() 2.6 播放动画2.6.1 play()2.6.1.1 显示动画函数SomePlayMethods2.6.1.2 runtime 2.6.2 add()2.6.3 wait()2.6.4 remove() 2.7 设置颜色2.8 缩放大小2.9 并行动画 3. text数组4. 基础动画类 Scene5. 二维坐标类 GraphScene5.1 setupaxes()5.2 getgraph()5.3 coordstopoint()5.4 pointtocoords()5.5 getgraphlabel()5.6 getverticallinetograph()5.7 getverticallinestograph()5.8 改变坐标标签的颜色 6. 文本类 TextMobject7. LaTeX文本类 TexMobject8. 二维图形类8.1 点Dot8.2 圆形Circle8.3 环Annulus8.4 长方形Rectangle8.5 方形Square8.6 椭圆Ellipse8.7 弧Arc8.8 线Line 9. 三维图形类9.1 球 Sphere9.2 立方 Cube9.3 棱柱Prism9.4 参数曲面 ParametricSurface9.5 参数曲线 ParametricFunction 10. 群组类VGroup10.1 arrange() 11. 相机参数11.1 setcameraorientation11.2 movecamera11.3 settodefaultangledcameraorientation11.4 addfixedinframemobjects 12. 坐标系类12.1 坐标系抽象类 CoordinateSystem12.2 二维坐标类 Axes12.3 三维坐标系类 ThreeDAxes12.4 NumberPlane12.5 ComplexPlane(NumberPlane) 附录A:常见的常数1. 颜色2. 方向3. 角度

manim基础教程

注意:

1. 文件的执行

命令行执行:python -m manim \path\to\yourfile.py [className] [-params]

usage: manim.py [-h] [-p] [-w] [-s] [-l] [-m] [--high_quality] [-g] [-i] [-f] [-t] [-q] [-a] [-o FILE_NAME] [-n START_AT_ANIMATION_NUMBER] [-r RESOLUTION] [-c COLOR] [--sound] [--leave_progress_bars] [--media_dir MEDIA_DIR] [--video_dir VIDEO_DIR | --video_output_dir VIDEO_OUTPUT_DIR] [--tex_dir TEX_DIR] [--livestream] [--to-twitch] [--with-key TWITCH_KEY] [file] [scene_names [scene_names ...]]

positional arguments: file path to file holding the python code for the scene scene_names Name of the Scene class you want to see

optional arguments: -h, --help show this help message and exit -p, --preview Automatically open the saved file once its done -w, --write_to_movie Render the scene as a movie file -s, --save_last_frame Save the last frame -l, --low_quality Render at a low quality (for faster rendering) -m, --medium_quality Render at a medium quality --high_quality Render at a high quality -g, --save_pngs Save each frame as a png -i, --save_as_gif Save the video as gif -f, --show_file_in_finder Show the output file in finder -t, --transparent Render to a movie file with an alpha channel -q, --quiet -a, --write_all Write all the scenes from a file -o FILE_NAME, --file_name FILE_NAME Specify the name of the output file, ifit should be different from the scene class name -n START_AT_ANIMATION_NUMBER, --start_at_animation_number START_AT_ANIMATION_NUMBER Start rendering not from the first animation, butfrom another, specified by its index. If you passin two comma separated values, e.g. "3,6", it will end the rendering at the second value -r RESOLUTION, --resolution RESOLUTION Resolution, passed as "height,width" -c COLOR, --color COLOR Background color --sound Play a success/failure sound --leave_progress_bars Leave progress bars displayed in terminal --media_dir MEDIA_DIR directory to write media --video_dir VIDEO_DIR directory to write file tree for video --video_output_dir VIDEO_OUTPUT_DIR directory to write video --tex_dir TEX_DIR directory to write tex --livestream Run in streaming mode --to-twitch Stream to twitch --with-key TWITCH_KEY Stream key for twitch

1.1 保存为视频并立即播放

参数-p

如果有多个绘图类会出现列表让你选择

也可以直接指定类名(示例为Example类)生成对应的类名的视频

fps = 15,宽854,高480:python -m manim \path\to\yourfile.py Example -pl fps = 30,宽1280,高720:python -m manim \path\to\yourfile.py Example -pm fps = 60,宽2560,高1440:python -m manim \path\to\yourfile.py Example -p

1.2 保留帧

-s保留最后一帧

当有多个类的时候会出现选择项让你选择保留哪几个绘图类的最后一帧

保留最后一帧并立即查看: python -m manim \path\to\yourfile.py Example -ps 保留全部绘图类为视频:python -m manim \path\to\yourfile.py Example -alpython -m manim \path\to\yourfile.py Example -ampython -m manim \path\to\yourfile.py Example -a 保留全部绘图类最后一帧:python -m manim \path\to\yourfile.py Example -as

1.3 视频尺寸

-r HEIGHT WIDTH

高度500 宽度600python -m manim \path\to\yourfile.py Example -plr 500 600 默认为16/9因此默认可以仅设置高度不需要设置宽度 高度为500的视频:python -m manim \path\to\yourfile.py Example -plr 500

1.4 视频通道

-t, --transparent alpha通道,扩展名为mov

1.5 保留进度显示条

--leave_progress_bars:

python -m manim \path\to\yourfile.py Example -pl --leave_progress_barsMedia will be written to ./media\. You can change this behavior with the --media_dir flag.Animation 0: WriteTextMobject, etc.: 100%|##############################################################################################| 15/15 [00:00<00:00, 32.48it/s] File ready at \path\to\video.mp4Played 2 animations

1.6 从某一个动画状态(animation)开始存为视频

-n START_AT_ANIMATION_NUMBER, --start_at_animation_number START_AT_ANIMATION_NUMBER

不是从第一个动画开始渲染,而是从索引指定的另一个动画开始渲染。 如果您传入两个逗号分隔值,例如 “3,6”,它将以第二个值渲染

class ShowGraph(Scene): def construct(self): print("dot = Dot()") dot = Dot() self.wait(2) print("dot.to_edge(UL)") dot.to_edge(UL) self.play(FadeIn(dot)) self.wait(2) print("text = TextMobject(\"text\")") text = TextMobject("text") self.wait(2) print("text.to_corner(UP)") text.to_corner(UP) self.play(Write(text)) self.wait(2)

不加起始渲染运行如下:

PS E:\programing-engineering\manim-tutorial\manim> python -m manim .\1_text_format.py ShowGraph -pl --leave_progress_bars Media will be written to ./media\. You can change this behavior with the --media_dir flag.dot = Dot()dot.to_edge(UL)Animation 1: FadeInDot: 100%|###########################################################################################################| 15/15 [00:00<00:00, 64.27it/s] text = TextMobject("text")text.to_corner(UP)Animation 4: WriteTextMobject: 100%|####################################################################################################| 15/15 [00:00<00:00, 39.79it/s] File ready at E:\programing-engineering\manim-tutorial\manim\media\videos\1_text_format\480p15\ShowGraph.mp4Played 6 animations

增加起始渲染:

从刚才的没有渲染的输出可以看出animation 1是dot.to_edge(UL)后的FadeInDot动画,所以如果-n 2则从animation 2开始,所以开始dot就已经显示在屏幕上面了

PS E:\programing-engineering\manim-tutorial\manim> python -m manim .\1_text_format.py ShowGraph -pl -n 2 --leave_progress_barsMedia will be written to ./media\. You can change this behavior with the --media_dir flag.dot = Dot()dot.to_edge(UL)Animation 1: FadeInDot: 100%|###########################################################################################################| 15/15 [00:00<00:00, 84.02it/s] text = TextMobject("text")text.to_corner(UP)Animation 4: WriteTextMobject: 100%|####################################################################################################| 15/15 [00:00<00:00, 58.52it/s] File ready at E:\programing-engineering\manim-tutorial\manim\media\videos\1_text_format\480p15\ShowGraph.mp4Played 6 animations

其他的参数不一一介绍,自行查看英文说明

1.7 默认显示进度条

默认设置在manimlib/config.py,manimlib/extract_secne.py与manimlib/scene.py里进行定义,可以修改该文件进行修改默认配置,注意因为修改源码所以要小心

例如:在上面的三个文件里:

将里面所有的“--leave_progress_bars”和“leave_progress_bars”修改为“--remove_progress_bars”与“remove__progress_bars”,同时将

此处的action改成不显示

这样如果加上--remove_progress_bars就不会显示进度条了,而默认是显示进度条的

1.8 改变视频存放位置

改变manimlib/constants.py中的:

if not os.path.isdir(MEDIA_DIR): MEDIA_DIR = "./media"

改./media为你想要存放的位置

1.9 存为gif

You can use python -m manim animation.py name_scene -im to render gif medium quality, or python -m manim animation.py name_scene -gm to render all frames as images, the images are saved in a folder

2. 显示操作

2.1 基本步骤(以TextMobject为例)

from manimlib.imports import *class WriteText(Scene): def construct(self): text = TextMobject("A Text") text.to_edge(UP) text.move_to(1*UP+0.1*RIGHT) //以play为例 self.play(SomeWriteMethod(text),run_time = seconds) self.wait(seconds) self.remove(text)

2.5 位置相关的函数

2.5.1to_edge()和to_corner()

someObject.to_edge(DIRECTION的线性组合,buff = number)

someObject.to_corner(DIRECTION的四个组合方向,buff = number)

to_edge参数可以是任意方向(方向有哪些见附录中方向常数列表)以及它们的线性组合,如0.1*RIGHT+0.2*UP,buff 两者的边缘的距离

to_corner仅接受组合方向UR,UL,DR,DL

如果没有to_edge和to_center默认为中间(ORIGIN)someObject.to_edge(UP+RIGHT)完全等效于someObject.to_corner(UR),其余四个方向同理

2.5.2 move_to()

someObject.move_to(DIRECTION的线性组合 or numpy的向量)

在当前位置移动到对应的位置

参数可以是UP,DOWN,LEFT,RIGHT等的倍数,可以非整数,单位宽度大概是4倍默认字体的行高,下面只要跟这八个个固定值有关的均是如此

someObject.move_to(UP+2*RIGHT)

参数也可以是numpy向量:

vec = np.array([1,2,0])someObject.move_to(vec)

因为图案的位置向量可以由get_center得到,所以可以如下操作:

someObject.move_to(someObject2.get_center()+2*RIGHT)

参数还可以是另外一个图案,表示的位置是该图案的几何中心:

someObject.move_to(someObject2)

2.5.3 next_to()

someObject1.next_to(someObject2,DIRECTION,buff=number)

someObject1对于someObject2的相对位置

与move_to的区别在于,next_to表示的是边界的距离,而不是中心距离

如:text1.next_to(text2,LEFT,buff=2) :

2.5.4 shift()

someObject.shift(DIRECTION*number):

自己垂直方向平移

2.5.5 rotate()

someObject.rotate(PI*number或者number,point):

逆时针旋转

如果相对图案为空,则自旋

如:

class RotateObject(Scene): def construct(self): textM = TextMobject("Text") textC = TextMobject("Reference text") textM.shift(UP) textM.rotate(PI/4) self.play(Write(textM),Write(textC)) self.wait(2)

否则相对 相对图案旋转:

class RotateObject(Scene): def construct(self): textM = TextMobject("Text") textC = TextMobject("Reference text") textM.rotate(PI/4,textC) self.play(Write(textM),Write(textC)) self.wait(2)

2.5.6 flip()

someObject.flip(DIRECTION):

按照矢量量方向翻转180度,遵循右手定则。

如text.flip(UP):

2.6 播放动画

2.6.1 play()

动画效果,可以是多个text,这个函数是多线程的,所以不会阻塞就会进入下一行操作

(如果下一个操作是remove掉text而没有使用wait函数进行等待,最终效果会变成立即销毁text即没有显示text,下面的add也同理)

**play(SomePlayMethod(someObject),run_time = seconds):**播放某种动画方法 如果希望并行同时播放多个动画,仅仅是python语法问题,给出如下例子模板:class concurrent(Scene): def construct(self): dot1 = Dot() dot2 = Dot() dot2.shift(UP) dot3 = Dot() dot3.shift(DOWN) # 单个动画的演示 self.play(Write(dot1)) # 多个动画演示 self.play(*[ Transform(i.copy(),j) for i,j in zip([dot1,dot1],[dot2,dot3]) ])# 故意使用i,j是为了显示zip的使用 self.wait() play(someObjectX.functionX,functionParamX, ​ someObjectX.functionX,functionParamX, …… run_time=seconds):同时改变某种或多种属性class ChangeColorAndSizeAnimation(Scene): def construct(self): text = TextMobject("Text") text.scale(2) text.shift(LEFT*2) self.play(Write(text)) self.wait() self.play( text.shift, RIGHT*2, text.scale, 2, text.set_color, RED, run_time=2, ) self.wait()

2.6.1.1 显示动画函数SomePlayMethods

动画函数,主要包含下列几个:

2.6.1.2 run_time

动画从开始到结束所用的时间,决定了动画的快慢(动画write的快慢是固定的不由runtime决定,但是到达了runtime又没有后面的wait,write会被截断),而非动画播放完了继续等待到run_time指定的时间,注意如果runtime太短可能导致动画write

2.6.1.3 rate_func

直译为速度函数,即内定的动画函数

分为三个值:there_and_back来回,linear一去不复返,smooth平滑(速度先为0,然后加快,到了中间减速最后到达终点为0)

例:

self.play( triangle.shift,RIGHT*2, rate_func=smooth, # Change this with: linear,smooth run_time=5 )

2.6.2 add()

add(someObject1,someObject2,…)

无动画添加文字,可以是多个text

2.6.3 wait()

wait(int seconds):

等待动画停留时间,如果没有参数则默认等待到将动画播放完为止

2.6.4 remove()

remove(someObject1,someObject2,…):

移除text,可以是多个text,注意FadeOut类的动画虽然自带消失效果但是该变量还是会停留在内存中

2.7 设置颜色

someObject.set_color(COLOR)

COLOR有哪些见附录的颜色一栏,COLOR本质上是一个字符串所以可以自定义字符串传入:

someObject.set_color(string)

如:

someObject.set_color("#0000FF")

2.8 缩放大小

someObject.scale(number)

class TextArray(Scene): def construct(self): dot1 = Dot() dot1.scale(3) dot1.shift(UP) dot2 = Dot() self.add(dot1,dot2) self.wait(3)

2.9 同步播放动画

TODO:暂时没有时间理解源码

让某一个物体(mobject)跟随另一个物体的移动而并行移动(使用其他移动方式,路径)

manimlib\mobject\mobject.py

add_updater(update_function, index=None, call_updater=True)update_function:更新函数,函数传入一个object对象,函数内部有一系列对该对象和已知的对象进行的一系列操作,可以是lambda表达式 例子:让一个点在“label”文字右边,随着文字的移动,始终保持在其右侧

# author:TBclass AddUpdater1(Scene): def construct(self): dot = Dot() text = TextMobject("Label")\ .next_to(dot,RIGHT,buff=SMALL_BUFF) self.add(dot,text) # Update function 更新函数 def update_text(obj): obj.next_to(dot,RIGHT,buff=SMALL_BUFF) # Add update function to the objects # 把更新函数加给对象 text.add_updater(update_text) # 如果想简洁,lambda表达式如下: # text.add_updater(lambda m: m.next_to(dot,RIGHT,buff=SMALL_BUFF)) # 此时下面的remove_updater(update_text)不能继续使用,需要改为clear_updaters # Add the object again 重新加入text # 注意这个步骤不能少,否则看不到!!! # 即使之前加入过,现在还是要重新加入 self.add(text) self.play(dot.shift,UP*2) # Remove update function text.remove_updater(update_text) self.wait()

**remove_updater(update_function)**取消并行播放函数 **clear_updaters(recursive=True)**取消所有的并行播放函数 UpdateFromFunc(Animation) 见2.6.1.1,注意这个函数仅在play函数中生效,play结束后就不会继续同步

更多例子(有时间再补充):TB的更新函数页面

3. text数组

在2中所有的显示方法几乎都可以对数组成立,

如文字串:

class TextArray(Scene): def construct(self): text = TextMobject("A","B","C","D","E","F") text[0].set_color(RED) text[1].set_color(ORANGE) text[2].set_color(YELLOW) text[3].set_color(GREEN) text[4].set_color(BLUE) #Hexadecimal color self.play(Write(text)) self.wait(2)

还可以拼接为LaTeX串(此处不能用TextMobject代替,否则报错):

class TexArray(Scene): def construct(self): text = TexMobject("A","{B","\\over","C}","D","E") text[0].set_color(RED) text[1].set_color(ORANGE) text[2].set_color(YELLOW) text[3].set_color(GREEN) text[4].set_color(BLUE) text[5].set_color(BLUE) self.play(Write(text)) self.wait(2)

对于数组可以直接如同对单个object操作,如:

text.shift(UP)

注意:

text = TextMobject(string)是一维数组

当text = TextMobject(string1,string2,….)中所有的string均为字母的时候,text为二维数组但是每一个子数组大小仅为1

如果有任意一个string是多个字母则text是二维数组

4. 基础动画类 Scene

所有的动画均是scene类的子类产生的,因此scene的功能比较少,主要是对一些基础的属性进行配置

\manimlib\scene\scene.py

变量的值得初始定义见下:

# \manimlib\scene\scene.pyCONFIG = { "camera_class": Camera, "camera_config": {}, "file_writer_config": {}, "skip_animations": False, "always_update_mobjects": False, "random_seed": 0, "start_at_animation_number": None, "end_at_animation_number": None, "leave_progress_bars": False, }

其中camera_config是对视频的处理,由camera类完成:

\manimlib\camera\camera.py

# \manimlib\camera\camera.pyCONFIG = {# 背景颜色 "background_image": None,# 视频的高宽与帧率 "pixel_height": DEFAULT_PIXEL_HEIGHT, "pixel_width": DEFAULT_PIXEL_WIDTH, "frame_rate": DEFAULT_FRAME_RATE,# Note: frame height and width will be resized to match# the pixel aspect ratio# FRAME_HEIGHT = 8.0# FRAME_WIDTH = FRAME_HEIGHT * DEFAULT_PIXEL_WIDTH / DEFAULT_PIXEL_HEIGHT "frame_height": FRAME_HEIGHT, "frame_width": FRAME_WIDTH,# 默认方向 "frame_center": ORIGIN,# 背景颜色 "background_color": BLACK, "background_opacity": 1,# Points in vectorized mobjects with norm greater# than this value will be rescaled. "max_allowable_norm": FRAME_WIDTH, "image_mode": "RGBA", "n_channels": 4, "pixel_array_dtype": 'uint8',# z_buff_func is only used if the flag above is set to True.# round z coordinate to nearest hundredth when comparring "z_buff_func": lambda m: np.round(m.get_center()[2], 2), "cairo_line_width_multiple": 0.01, }

所有的动画都是继承自Scene,所以动画的某些特定的属性可以通过CONFIG修改:

例子:

插入背景图片

class TextLike1DArrays(Scene): CONFIG={ "camera_config": { "background_image": r"1.png", }, } def construct(self): self.add(TextMobject("Text").set_color(RED)) self.wait()

5. 二维坐标类 GraphScene

\manimlib\scene\graph_scene.py

继承自Scene类,用来绘制坐标

属性如下:

CONFIG = { "x_min": -1, "x_max": 10, "x_axis_width": 9, "x_tick_frequency": 1, "x_leftmost_tick": None, # Change if different from x_min "x_labeled_nums": None, "x_axis_label": "$x$", "y_min": -1, "y_max": 10, "y_axis_height": 6, "y_tick_frequency": 1, "y_bottom_tick": None, # Change if different from y_min "y_labeled_nums": None, "y_axis_label": "$y$", "axes_color": GREY, "graph_origin": 2.5 * DOWN + 4 * LEFT, "exclude_zero_label": True, "default_graph_colors": [BLUE, GREEN, YELLOW], "default_derivative_color": GREEN, "default_input_color": YELLOW, "default_riemann_start_color": BLUE, "default_riemann_end_color": GREEN, "area_opacity": 0.8, "num_rects": 50, }

一般流程是:

class Graph2D(GraphScene): def x_2(self, x): return x**2 def construct(self): self.setup_axes(animate=True) graph = self.get_graph(self.x_2,color = GREEN,x_min = 2,x_max = 4) self.play(ShowCreation(graph),run_time = 2) self.wait()

5.1 setup_axes()

setup_axes(animate=Bool):

默认没有动画效果,setup_axes(animate=True)则会显示动画

5.2 get_graph()

get_graph(func, color=None,x_min=None,x_max=None, **kwargs)

得到坐标系的句柄,并设置值

5.3 coords_to_point()

coords_to_point(x, y)

坐标变成对应的帧中的点

5.4 point_to_coords()

point_to_coords(point)

帧中的点转换为坐标,返回x,y组成的元组

5.5 get_graph_label()

get_graph_label(graph,label="f(x)", x_val=None,direction=RIGHT, buff=MED_SMALL_BUFF, color=None)

graph:从graph中获得坐标标签

label默认为“f(x)”,可以改成自己想要的函数

x_val:x的取值范围

buff:距离边界的距离

color:颜色

5.6 get_vertical_line_to_graph()

get_vertical_line_to_graph(x, graph,line_class=Line,**line_kwargs)

得到竖直线,起点为(x,0)终点为(x,f(x))

返回line_class类型的图像

5.7 get_vertical_lines_to_graph()

get_vertical_lines_to_graph( graph,x_min=None,x_max=None, num_lines=20, **kwargs)

同时得到画多条竖直线

返回line_class类型的VGroup

5.8 改变坐标标签的颜色

https://github.com/Elteoremadebeethoven/AnimationsWithManim/blob/master/English/6a_plots_2D/change_label_colors.md#change-labels-colors-in-graphsceneChange labels colors in GraphSceneAdd this to the CONFIG dictionary:在CONFIG中加入: "x_label_color":RED, "y_label_color":BLUEIn the setup_axes method change the lines:在源码的setup_axes中的两句: x_label = TextMobject(self.x_axis_label) # and y_label = TextMobject(self.y_axis_label)with改为 x_label = TextMobject(self.x_axis_label,color=self.x_label_color) # and y_label = TextMobject(self.x_axis_label,color=self.y_label_color)

效果:

6. 文本类 TextMobject

7. LaTeX文本类 TexMobject

\manimlib\mobject\svg\tex_mobject.py

显示为LaTeX格式(在想要LaTeX字符串按照数组显示时必须使用这个实现)

CONFIG = { "template_tex_file_body": TEMPLATE_TEX_FILE_BODY, # 笔画宽度 "stroke_width": 0, # 填充不透明度 "fill_opacity": 1.0, # 笔画的描边宽度 "background_stroke_width": 1, # 笔画的描边颜色 "background_stroke_color": BLACK, "should_center": True, "height": None, "organize_left_to_right": False, "alignment": "", }

例:

class Formula(Scene): def construct(self): formula = TexMobject("This is a sentence") self.play(Write(formula)) self.wait(3)

8. 二维图形类

\manimlib\mobject\geometry.py

TODO:待完善

8.1 点Dot

CONFIG = { "radius": DEFAULT_DOT_RADIUS, "stroke_width": 0, "fill_opacity": 1.0, "color": WHITE }

8.2 圆形Circle

继承自Arc

CONFIG = { "color": RED, "close_new_points": True, "anchors_span_full_range": False }

8.3 环Annulus

继承自圆形

CONFIG = { "inner_radius": 1, "outer_radius": 2, "fill_opacity": 1, "stroke_width": 0, "color": WHITE, "mark_paths_closed": False, }

8.4 长方形Rectangle

CONFIG = { "color": WHITE, "height": 2.0, "width": 4.0, "mark_paths_closed": True, "close_new_points": True, }

8.5 方形Square

继承自长方形

CONFIG = { # 边长 "side_length": 2.0, }

8.6 椭圆Ellipse

继承自圆形

CONFIG = { "width": 2, "height": 1 }

8.7 弧Arc

CONFIG = { "radius": 1.0, "num_components": 9, "anchors_span_full_range": True, "arc_center": ORIGIN, }

8.8 线Line

Line(start=LEFT, end=RIGHT, **kwargs)

start,end:起点终点,形式是np向量

kwargs为配置信息,继承自VMobject

CONFIG = { "fill_color": None, "fill_opacity": 0.0, "stroke_color": None, "stroke_opacity": 1.0, "stroke_width": DEFAULT_STROKE_WIDTH, # The purpose of background stroke is to have # something that won't overlap the fill, e.g. # For text against some textured background "background_stroke_color": BLACK, "background_stroke_opacity": 1.0, "background_stroke_width": 0, # When a color c is set, there will be a second color # computed based on interpolating c to WHITE by with # sheen_factor, and the display will gradient to this # secondary color in the direction of sheen_direction. "sheen_factor": 0.0, "sheen_direction": UL, # Indicates that it will not be displayed, but # that it should count in parent mobject's path "close_new_points": False, "pre_function_handle_to_anchor_scale_factor": 0.01, "make_smooth_after_applying_functions": False, "background_image_file": None, "shade_in_3d": False, # This is within a pixel # TODO, do we care about accounting for # varying zoom levels? "tolerance_for_point_equality": 1e-6, "n_points_per_cubic_curve": 4, }

9. 三维图形类

\manimlib\mobject\three_dimensions.py

9.1 球 Sphere

继承自ParametricSurface,实现通过绘制三维多边形曲面实现的,具体看源码

CONFIG = { "resolution": (12, 24), "radius": 1, "u_min": 0.001, "u_max": PI - 0.001, "v_min": 0, "v_max": TAU, }

9.2 立方 Cube

CONFIG = { "fill_opacity": 0.75, "fill_color": BLUE, "stroke_width": 0, "side_length": 2, }

9.3 棱柱Prism

继承自cube

CONFIG = { "dimensions": [3, 2, 1] }

9.4 参数曲面 ParametricSurface

参数方程表达的曲面

ParametricSurface(func, **kwargs)

CONFIG = { "u_min": 0, "u_max": 1, "v_min": 0, "v_max": 1, "resolution": 32, "surface_piece_config": {}, "fill_color": BLUE_D, "fill_opacity": 1.0, "checkerboard_colors": [BLUE_D, BLUE_E], "stroke_color": LIGHT_GREY, "stroke_width": 0.5, "should_make_jagged": False, "pre_function_handle_to_anchor_scale_factor": 0.00001, }

func:自定义的方程,此方程传入两个参数,返回三维向量,每一个分量均是传入两个自变量的表达式

如:

def func(x, y): return np.array([x**2,y+2,x**2 - y**2])

绘制三维曲面的例子:

class SurfacesAnimation(ThreeDScene): def construct(self): axes = ThreeDAxes() cylinder = ParametricSurface( lambda u, v: np.array([ np.cos(TAU * v), np.sin(TAU * v), 2 * (1 - u) ]), resolution=(6, 32)).fade(0.5) #Resolution of the surfaces paraboloid = ParametricSurface( lambda u, v: np.array([ np.cos(v)*u, np.sin(v)*u, u**2 ]),v_max=TAU, checkerboard_colors=[PURPLE_D, PURPLE_E], resolution=(10, 32)).scale(2) para_hyp = ParametricSurface( lambda u, v: np.array([ u, v, u**2-v**2 ]),v_min=-2,v_max=2,u_min=-2,u_max=2,checkerboard_colors=[BLUE_D, BLUE_E], resolution=(15, 32)).scale(1) cone = ParametricSurface( lambda u, v: np.array([ u*np.cos(v), u*np.sin(v), u ]),v_min=0,v_max=TAU,u_min=-2,u_max=2,checkerboard_colors=[GREEN_D, GREEN_E], resolution=(15, 32)).scale(1) hip_one_side = ParametricSurface( lambda u, v: np.array([ np.cosh(u)*np.cos(v), np.cosh(u)*np.sin(v), np.sinh(u) ]),v_min=0,v_max=TAU,u_min=-2,u_max=2,checkerboard_colors=[YELLOW_D, YELLOW_E], resolution=(15, 32)) ellipsoid=ParametricSurface( lambda u, v: np.array([ 1*np.cos(u)*np.cos(v), 2*np.cos(u)*np.sin(v), 0.5*np.sin(u) ]),v_min=0,v_max=TAU,u_min=-PI/2,u_max=PI/2,checkerboard_colors=[TEAL_D, TEAL_E], resolution=(15, 32)).scale(2) sphere = ParametricSurface( lambda u, v: np.array([ 1.5*np.cos(u)*np.cos(v), 1.5*np.cos(u)*np.sin(v), 1.5*np.sin(u) ]),v_min=0,v_max=TAU,u_min=-PI/2,u_max=PI/2,checkerboard_colors=[RED_D, RED_E], resolution=(15, 32)).scale(2) self.set_camera_orientation(phi=75 * DEGREES) self.begin_ambient_camera_rotation(rate=0.2) self.add(axes) self.play(Write(sphere)) self.wait() self.play(ReplacementTransform(sphere,ellipsoid)) self.wait() self.play(ReplacementTransform(ellipsoid,cone)) self.wait() self.play(ReplacementTransform(cone,hip_one_side)) self.wait() self.play(ReplacementTransform(hip_one_side,para_hyp)) self.wait() self.play(ReplacementTransform(para_hyp,paraboloid)) self.wait() self.play(ReplacementTransform(paraboloid,cylinder)) self.wait() self.play(FadeOut(cylinder))

9.5 参数曲线 ParametricFunction

ParametricSurface(func, **kwargs)

func:自定义的方程,此方程传入一个参数,返回三维向量,每一个分量均是传入自变量的表达式

CONFIG = { "t_min": 0, "t_max": 1, "step_size": 0.01, # Use "auto" (lowercase) for automatic step size "dt": 1e-8, # TODO, be smarter about figuring these out? "discontinuities": [], }

例:

class ParametricCurve2(ThreeDScene): def construct(self): curve1=ParametricFunction( lambda u : np.array([ 1.2*np.cos(u), 1.2*np.sin(u), u/2 ]),color=RED,t_min=-TAU,t_max=TAU, ) curve2=ParametricFunction( lambda u : np.array([ 1.2*np.cos(u), 1.2*np.sin(u), u ]),color=RED,t_min=-TAU,t_max=TAU, ) curve1.set_shade_in_3d(True) curve2.set_shade_in_3d(True) axes = ThreeDAxes() self.add(axes) self.set_camera_orientation(phi=80 * DEGREES,theta=-60*DEGREES) self.begin_ambient_camera_rotation(rate=0.1) self.play(ShowCreation(curve1)) self.wait() self.play(Transform(curve1,curve2),rate_func=there_and_back,run_time=3) self.wait()

10. 群组类VGroup

可以将多个图像合并为一个组进行批量同步操作(自我理解为Vector Group的缩写)

someObjectGroup = VGroup(someObject1,someObject2,…)

10.1 arrange()

someObjectGroup.arrange(DIRECTION,aligned_edge = DIRECTION,buff=number)

**DIRECTION:**以someObject1,someObject2,…顺序按照此方向排列

**aligned_edge:**对齐

**buff:**成员之间的距离

例:

class ArrangeObjects(Scene): def construct(self): text1 = TextMobject("text1") text2 = TextMobject("text2 text2") text3 = TextMobject("text3 text3 text3") textgroup = VGroup(text1,text2,text3) textgroup.arrange( UP, aligned_edge = LEFT, buff=0.4 ) self.add(textgroup) self.wait()

动画效果:

因为arrange第一个参数不在config里面,需要单独放在外面

self.play( text_group.arrange, UP, {"aligned_edge":RIGHT,"buff":2} )

11. 相机参数

相机是针对3D动画类(ThreeDScene)的方法

\manimlib\scene\three_d_scene.py

将视频的视窗看做相机,就可以通过调整相机的远近,角度来观察三维物体,这就是相机类的作用

11.1 set_camera_orientation

threeDScene.set_camera_orientation(phi=degrees1,theta=degrees2,gamma=degrees3,distance=number)

设置相机的角度

11.2 move_camera

threeDScene.move_camera(phi=None,theta=None, distance=None, gamma=None, frame_center=None,added_anims=[],**kwargs)

例子:

class MoveCamera2(ThreeDScene): def construct(self): axes = ThreeDAxes() circle=Circle() self.set_camera_orientation(phi=80 * DEGREES) self.play(ShowCreation(circle),ShowCreation(axes)) #Start move camera self.begin_ambient_camera_rotation(rate=0.1) self.wait(5) #Stop move camera self.stop_ambient_camera_rotation() #Return the position of the camera self.move_camera(phi=80*DEGREES,theta=-PI/2) self.wait()

11.3 set_to_default_angled_camera_orientation

还原为默认角度

11.4 add_fixed_in_frame_mobjects

加入固定在屏幕的图像,此图像不随相机变化而变化

*add_fixed_in_frame_mobjects(mobjects)

例:

class Text3D3(ThreeDScene): def construct(self): axes = ThreeDAxes() self.set_camera_orientation(phi=75 * DEGREES,theta=-45*DEGREES) text3d=TextMobject("This is a 3D text") self.add_fixed_in_frame_mobjects(text3d) #<----- Add this text3d.to_corner(UL) self.add(axes) self.begin_ambient_camera_rotation() self.play(Write(text3d)) sphere = ParametricSurface( lambda u, v: np.array([ 1.5*np.cos(u)*np.cos(v), 1.5*np.cos(u)*np.sin(v), 1.5*np.sin(u) ]),v_min=0,v_max=TAU,u_min=-PI/2,u_max=PI/2,checkerboard_colors=[RED_D, RED_E], resolution=(15, 32)).scale(2) self.play(LaggedStart(ShowCreation,sphere)) self.wait(2)

12. 坐标系类

12.0 数轴类 NumberLine

继承于Line,属性如下:

CONFIG = { "color": LIGHT_GREY, # X的范围 "x_min": -FRAME_X_RADIUS, "x_max": FRAME_X_RADIUS, # 单元格的大小,默认和单位长度一致 "unit_size": 1, # 是否包含刻度tick "include_ticks": True, # tick的尺寸,大小为:2个单位*tick_size "tick_size": 0.1, # tick的分布密度 "tick_frequency": 1, # Defaults to value near x_min s.t. 0 is a tick # TODO, rename this "leftmost_tick": None, # Change name # 最长的tick,作者原意应该是作为数轴标识的tick,一般为中间的tick即原点,会画长一点 "numbers_with_elongated_ticks": [0], # 标上数字 "include_numbers": False, # 显示的数字格式 "numbers_to_show": None, "longer_tick_multiple": 2, # 中间的数字 "number_at_center": 0, "number_scale_val": 0.75, "label_direction": DOWN, "line_to_number_buff": MED_SMALL_BUFF, # 包含箭头 "include_tip": False, # tip:箭头,下面两个是其尺寸设置 "tip_width": 0.25, "tip_height": 0.25, "decimal_number_config": { "num_decimal_places": 0, }, # 从数字标记中去掉0这个标记 "exclude_zero_from_default_numbers": False, }

注意其中x_min,x_max均为帧的左右范围即每帧的最左边和最右边

本质上来说,数轴是一条线(Line),每一个间隔(tick)均为小的线(Line)

整个构建流程是,先画出横线作为坐标轴,然后从左到右画出一个个小竖线,最后增加数字,箭头等小部件

12.1 坐标系抽象类 CoordinateSystem

CONFIG = { "dimension": 2, "x_min": -FRAME_X_RADIUS, "x_max": FRAME_X_RADIUS, "y_min": -FRAME_Y_RADIUS, "y_max": FRAME_Y_RADIUS, }

主要的几个抽象方法:

coords指的是坐标轴中的点的值,point指没有坐标轴时真实的坐标,在创建坐标轴时候中心设置在ORIGIN,坐标大小没有缩放的时候两者是一样的

coords_to_point(*coords);c2p(*coords):将坐标系中的点的坐标值转换为屏幕上的点 point_to_coords(point);p2c(point):coords_to_point逆方法 get_axes():得到CoordinateSystem对象,一般为包含x,y,z坐标的数组 get_axis(index):得到index对应的坐标,xyz坐标对应的index分别为1,2,3 get_x_axis();get_y_axis();get_z_axis() get_axis_label一类:给对应的坐标(轴)添加标签,显示标签,并返回标签对象 get_axis_label(label_tex, axis, edge, direction, buff=MED_SMALL_BUFF): get_axis_labels(x_label_tex="x", y_label_tex="y"): get_x_axis_label(label_tex, edge=RIGHT, direction=DL, **kwargs): get_y_axis_label(label_tex, edge=UP, direction=DR, **kwargs): label_tex:坐标标签,使用latex字符串(TexMobject) axis:想获取的坐标标签的对应的坐标对象 edge:四个边缘位置 direction:在坐标轴的相对位置 **kwargs:其他在config内的配置,如颜色等,自行修改

get_graph(function, **kwargs):给定方程,绘制图像并返回

get_parametric_curve(function, **kwargs):绘制给定参数曲线方程并返回

input_to_graph_point(x, graph):暂时没搞清楚啥玩意

12.2 二维坐标类 Axes

继承CoordinateSystem

实质是创造两个NumberLine数轴,然后将其中一个按照中心旋转90度,作为Y轴,然后对X,Y轴进行其他的属性进行调整,所以配置里面有"number_line_config"

Axes(**kwargs)

CONFIG = { # 数轴的配置 "number_line_config": { "color": LIGHT_GREY, "include_tip": True, "exclude_zero_from_default_numbers": True, }, # 横坐标轴和数轴的默认配置一样不需要修改 "x_axis_config": {}, "y_axis_config": { # 默认将“y”这个标签放在纵坐标轴的左侧 "label_direction": LEFT, }, # 原点默认和帧图的中心点一致 "center_point": ORIGIN, }

实现了:

coords_to_point(*coords);c2p(*coords):将坐标系中的点的坐标值转换为屏幕(帧图)上的点 分析一下源码:

def coords_to_point(self, *coords): # 将坐标轴中的原点0换算为对应的帧图中的坐标 origin = self.x_axis.number_to_point(0) # 将帧图坐标转换为向量 result = np.array(origin) # result = 原点对应的帧图的坐标+coord相对帧图中原点的坐标 = coord在帧图中的实际坐标 for axis, coord in zip(self.get_axes(), coords): result += (axis.number_to_point(coord) - origin) return result

point_to_coords(point);p2c(point)

增加了方法:

get_coordinate_labels(x_vals=None, y_vals=None):传入x,y标签的latex字符串,得到对应的x,y坐标轴的标签的对象

add_coordinates(x_vals=None, y_vals=None):和get_coordinate_labels相似,但是将其加入了自己的成员变量并返回了自己

12.3 三维坐标系类 ThreeDAxes

继承自Axes

ThreeDAxes(**kwargs)

CONFIG = { "dimension": 3, "x_min": -5.5, "x_max": 5.5, "y_min": -5.5, "y_max": 5.5, "z_axis_config": {}, "z_min": -3.5, "z_max": 3.5, "z_normal": DOWN, "num_axis_pieces": 20, "light_source": 9 * DOWN + 7 * LEFT + 10 * OUT, }

12.4 NumberPlane

12.5 ComplexPlane

复数坐标系,继承于NumberPlane

# author:TBclass ComplexPlaneScene(Scene): def construct(self): # See manimlib/mobject/number_line.py and coordinate_systems.py cp = ComplexPlane( y_axis_config={"decimal_number_config":{"unit": "i"}}, number_line_config={"include_numbers":True} ) x_axis = cp[-2] y_axis = cp[-1] x_axis.set_color(RED) y_axis.set_color(PURPLE) x_labels = x_axis[1] x_labels.set_color(ORANGE) y_labels = y_axis[1] y_labels.set_color(YELLOW) for y in y_labels: y.rotate(-PI/2) x_label = TexMobject("x") x_label.move_to(cp.c2p(6.8,x_label.get_height())) y_label = TexMobject("y") y_label.move_to(cp.c2p(-y_label.get_width(),3.8)) self.add(cp,x_label,y_label) self.wait()

附录A:常见的常数

\manimlib\constants.py

1. 颜色

见constants.py中COLOR_MAP中的列表

2. 方向

ORIGIN = np.array((0., 0., 0.))UP = np.array((0., 1., 0.))DOWN = np.array((0., -1., 0.))RIGHT = np.array((1., 0., 0.))LEFT = np.array((-1., 0., 0.))IN = np.array((0., 0., -1.))OUT = np.array((0., 0., 1.))X_AXIS = np.array((1., 0., 0.))Y_AXIS = np.array((0., 1., 0.))Z_AXIS = np.array((0., 0., 1.))# Useful abbreviations for diagonalsUL = UP + LEFTUR = UP + RIGHTDL = DOWN + LEFTDR = DOWN + RIGHTTOP = FRAME_Y_RADIUS * UPBOTTOM = FRAME_Y_RADIUS * DOWNLEFT_SIDE = FRAME_X_RADIUS * LEFTRIGHT_SIDE = FRAME_X_RADIUS * RIGHT

3. 角度

PI = np.piTAU = 2 * PIDEGREES = TAU / 360

4. 距离

SMALL_BUFF = 0.1MED_SMALL_BUFF = 0.25MED_LARGE_BUFF = 0.5LARGE_BUFF = 1DEFAULT_MOBJECT_TO_EDGE_BUFFER = MED_LARGE_BUFFDEFAULT_MOBJECT_TO_MOBJECT_BUFFER = MED_SMALL_BUFF

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Git-it- Git 教程
下一篇:2022年6月30日——Java案例(6)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~