mirror of
https://github.com/3b1b/manim.git
synced 2025-07-28 12:32:36 +08:00
Added new example scenes and cleaned up the couple of old ones
This commit is contained in:
@ -30,83 +30,133 @@ class OpeningManimExample(Scene):
|
|||||||
transform_title.to_corner(UP + LEFT)
|
transform_title.to_corner(UP + LEFT)
|
||||||
self.play(
|
self.play(
|
||||||
Transform(title, transform_title),
|
Transform(title, transform_title),
|
||||||
LaggedStart(*map(FadeOutAndShiftDown, basel)),
|
LaggedStartMap(FadeOut, basel, shift=DOWN),
|
||||||
)
|
)
|
||||||
self.wait()
|
self.wait()
|
||||||
|
|
||||||
|
fade_comment = TextMobject("""
|
||||||
|
You probably don't want to over use\\\\
|
||||||
|
Transforms, though, a simple fade often\\\\
|
||||||
|
looks nicer.
|
||||||
|
""")
|
||||||
|
fade_comment.next_to(
|
||||||
|
transform_title, DOWN,
|
||||||
|
buff=LARGE_BUFF,
|
||||||
|
aligned_edge=LEFT
|
||||||
|
)
|
||||||
|
self.play(FadeIn(fade_comment, shift=DOWN))
|
||||||
|
self.wait(3)
|
||||||
|
|
||||||
grid = NumberPlane()
|
grid = NumberPlane()
|
||||||
grid_title = TextMobject("This is a grid")
|
grid_title = TextMobject(
|
||||||
grid_title.scale(1.5)
|
"But manim is for illustrating math, not text",
|
||||||
grid_title.move_to(transform_title)
|
)
|
||||||
|
grid_title.to_edge(UP)
|
||||||
|
grid_title.add_background_rectangle()
|
||||||
|
|
||||||
self.add(grid, grid_title) # Make sure title is on top of grid
|
self.add(grid, grid_title) # Make sure title is on top of grid
|
||||||
self.play(
|
self.play(
|
||||||
FadeOut(title),
|
FadeOut(title, shift=LEFT),
|
||||||
FadeInFromDown(grid_title),
|
FadeOut(fade_comment, shift=LEFT),
|
||||||
|
FadeIn(grid_title),
|
||||||
ShowCreation(grid, run_time=3, lag_ratio=0.1),
|
ShowCreation(grid, run_time=3, lag_ratio=0.1),
|
||||||
)
|
)
|
||||||
self.wait()
|
self.wait()
|
||||||
|
|
||||||
grid_transform_title = TextMobject(
|
grid_transform_title = TextMobject(
|
||||||
"That was a non-linear function \\\\"
|
"This is a non-linear function applied to the grid"
|
||||||
"applied to the grid"
|
|
||||||
)
|
)
|
||||||
grid_transform_title.move_to(grid_title, UL)
|
grid_transform_title.set_stroke(BLACK, 5, background=True)
|
||||||
|
grid_transform_title.to_edge(UP)
|
||||||
grid.prepare_for_nonlinear_transform()
|
grid.prepare_for_nonlinear_transform()
|
||||||
self.play(
|
self.play(
|
||||||
grid.apply_function,
|
ApplyPointwiseFunction(
|
||||||
lambda p: p + np.array([
|
lambda p: p + np.array([np.sin(p[1]), np.sin(p[0]), 0]),
|
||||||
np.sin(p[1]),
|
grid,
|
||||||
np.sin(p[0]),
|
run_time=5,
|
||||||
0,
|
),
|
||||||
]),
|
FadeOut(grid_title),
|
||||||
run_time=3,
|
FadeIn(grid_transform_title),
|
||||||
)
|
)
|
||||||
self.wait()
|
self.wait()
|
||||||
self.play(
|
|
||||||
Transform(grid_title, grid_transform_title)
|
|
||||||
)
|
class WarpSquare(Scene):
|
||||||
|
def construct(self):
|
||||||
|
square = Square()
|
||||||
|
self.play(square.apply_complex_function, np.exp)
|
||||||
self.wait()
|
self.wait()
|
||||||
|
|
||||||
|
|
||||||
class SquareToCircle(Scene):
|
class SquareToCircle(Scene):
|
||||||
def construct(self):
|
def construct(self):
|
||||||
circle = Circle()
|
circle = Circle()
|
||||||
|
circle.set_fill(BLUE, opacity=0.5)
|
||||||
|
circle.set_stroke(BLUE_E, width=4)
|
||||||
square = Square()
|
square = Square()
|
||||||
square.flip(RIGHT)
|
|
||||||
square.rotate(-3 * TAU / 8)
|
|
||||||
circle.set_fill(PINK, opacity=0.5)
|
|
||||||
|
|
||||||
self.play(ShowCreation(square))
|
self.play(ShowCreation(square))
|
||||||
self.play(Transform(square, circle))
|
self.wait()
|
||||||
self.play(FadeOut(square))
|
self.play(ReplacementTransform(square, circle))
|
||||||
|
|
||||||
|
|
||||||
class WarpSquare(Scene):
|
|
||||||
def construct(self):
|
|
||||||
square = Square()
|
|
||||||
self.play(ApplyPointwiseFunction(
|
|
||||||
lambda point: complex_to_R3(np.exp(R3_to_complex(point))),
|
|
||||||
square
|
|
||||||
))
|
|
||||||
self.wait()
|
self.wait()
|
||||||
|
|
||||||
|
# This opens an iPython termnial where you can keep writing
|
||||||
|
# lines as if they were part of this construct method
|
||||||
|
self.embed()
|
||||||
|
# Try typing the following lines
|
||||||
|
# self.play(circle.stretch, 4, {"dim": 0})
|
||||||
|
# self.play(Rotate(circle, TAU / 4))
|
||||||
|
# self.play(circle.shift, 2 * RIGHT, circle.scale, 0.25)
|
||||||
|
# circle.insert_n_curves(10)
|
||||||
|
# self.play(circle.apply_complex_function, lambda z: z**2)
|
||||||
|
|
||||||
class WriteStuff(Scene):
|
|
||||||
|
class TexTransformExample(Scene):
|
||||||
def construct(self):
|
def construct(self):
|
||||||
example_text = TextMobject(
|
lines = VGroup(
|
||||||
"This is a some text",
|
# Surrounding substrings with double braces
|
||||||
tex_to_color_map={"text": YELLOW}
|
# will ensure that those parts are separated
|
||||||
|
# out in the TexMobject. For example, here the
|
||||||
|
# TexMobject will have 5 submobjects, corresponding
|
||||||
|
# to the strings [A^2, +, B^2, =, C^2]
|
||||||
|
TexMobject("{{A^2}} + {{B^2}} = {{C^2}}"),
|
||||||
|
TexMobject("{{A^2}} = {{C^2}} - {{B^2}}"),
|
||||||
|
TexMobject(
|
||||||
|
"A = \\sqrt{(C + B)(C - B)}",
|
||||||
|
substrings_to_isolate=["A", "B", "C"]
|
||||||
|
),
|
||||||
)
|
)
|
||||||
example_tex = TexMobject(
|
lines.arrange(DOWN, buff=LARGE_BUFF)
|
||||||
"\\sum_{k=1}^\\infty {1 \\over k^2} = {\\pi^2 \\over 6}",
|
for line in lines:
|
||||||
)
|
line.set_color_by_tex_to_color_map({
|
||||||
group = VGroup(example_text, example_tex)
|
"A": BLUE,
|
||||||
group.arrange(DOWN)
|
"B": TEAL,
|
||||||
group.set_width(FRAME_WIDTH - 2 * LARGE_BUFF)
|
"C": GREEN,
|
||||||
|
})
|
||||||
|
|
||||||
self.play(Write(example_text))
|
self.add(lines[0])
|
||||||
self.play(Write(example_tex))
|
|
||||||
|
# The animation TransformMatchingTex will line up parts
|
||||||
|
# of the source and target which have matching tex strings
|
||||||
|
self.play(TransformMatchingTex(
|
||||||
|
lines[0].copy(), lines[1],
|
||||||
|
run_time=2, path_arc=90 * DEGREES,
|
||||||
|
))
|
||||||
|
self.wait()
|
||||||
|
# The animation TransformMatchingShapes will line up parts
|
||||||
|
# of the source and target which have matching shapes, regardless
|
||||||
|
# of where they fall in the mobject family heirarchies.
|
||||||
|
# For example, calling TransformMatchingTex below would not
|
||||||
|
# quite look like we want, becuase lines[2] has none of its
|
||||||
|
# substringsisolated, and even if it did it would not know to
|
||||||
|
# match the symbol "C", say, from line[1] to the "C" from line[2],
|
||||||
|
# since in line[1] it is tied up with the full C^2 submobject.
|
||||||
|
# However, TransformMatchingShapes just does its best to pair
|
||||||
|
# pieces which look the same
|
||||||
|
self.play(TransformMatchingShapes(
|
||||||
|
lines[1].copy(), lines[2],
|
||||||
|
run_time=2,
|
||||||
|
))
|
||||||
self.wait()
|
self.wait()
|
||||||
|
|
||||||
|
|
||||||
@ -118,16 +168,100 @@ class UpdatersExample(Scene):
|
|||||||
num_decimal_places=3,
|
num_decimal_places=3,
|
||||||
include_sign=True,
|
include_sign=True,
|
||||||
)
|
)
|
||||||
square = Square().to_edge(UP)
|
square = Square()
|
||||||
|
square.to_edge(UP)
|
||||||
|
|
||||||
|
# This ensures that the method deicmal.next_to(square)
|
||||||
|
# is called on every frame
|
||||||
|
always(decimal.next_to, square)
|
||||||
|
# This ensures thst decimal.set_value(square.get_y()) is
|
||||||
|
# called every frame
|
||||||
|
f_always(decimal.set_value, square.get_y)
|
||||||
|
|
||||||
decimal.add_updater(lambda d: d.next_to(square, RIGHT))
|
|
||||||
decimal.add_updater(lambda d: d.set_value(square.get_center()[1]))
|
|
||||||
self.add(square, decimal)
|
self.add(square, decimal)
|
||||||
self.play(
|
self.play(
|
||||||
square.to_edge, DOWN,
|
square.to_edge, DOWN,
|
||||||
rate_func=there_and_back,
|
run_time=3,
|
||||||
run_time=5,
|
|
||||||
)
|
)
|
||||||
|
self.play(square.center)
|
||||||
self.wait()
|
self.wait()
|
||||||
|
|
||||||
|
# You can also add any function generally to a Mobject's
|
||||||
|
# list of 'updaters'.
|
||||||
|
now = self.time
|
||||||
|
square.add_updater(
|
||||||
|
lambda m: m.set_y(math.sin(self.time - now))
|
||||||
|
)
|
||||||
|
self.wait(10)
|
||||||
|
|
||||||
|
|
||||||
|
class SurfaceExample(Scene):
|
||||||
|
CONFIG = {
|
||||||
|
"camera_class": ThreeDCamera,
|
||||||
|
}
|
||||||
|
|
||||||
|
def construct(self):
|
||||||
|
torus1 = Torus(r1=1, r2=1)
|
||||||
|
torus2 = Torus(r1=3, r2=1)
|
||||||
|
sphere = Sphere(radius=3, resolution=torus1.resolution)
|
||||||
|
surfaces = [sphere, torus1, torus2]
|
||||||
|
# If you want these to be textured with pictures of, say, earth,
|
||||||
|
# find images for the texture maps you want, perhaps
|
||||||
|
# https://en.wikipedia.org/wiki/File:Blue_Marble_2002.png and
|
||||||
|
# https://commons.wikimedia.org/wiki/File:The_earth_at_night.jpg
|
||||||
|
# and make sure they are available in whatever folder manim
|
||||||
|
# looks for images, then uncomment the lines below
|
||||||
|
surfaces = [
|
||||||
|
TexturedSurface(surface, "EarthTextureMap", "NightEarthTextureMap")
|
||||||
|
for surface in [sphere, torus1, torus2]
|
||||||
|
]
|
||||||
|
|
||||||
|
for mob in surfaces:
|
||||||
|
mob.mesh = SurfaceMesh(mob)
|
||||||
|
mob.mesh.set_stroke(BLUE, 1, opacity=0.5)
|
||||||
|
|
||||||
|
# Set perspective
|
||||||
|
frame = self.camera.frame
|
||||||
|
frame.set_rotation(
|
||||||
|
theta=-30 * DEGREES,
|
||||||
|
phi=70 * DEGREES,
|
||||||
|
)
|
||||||
|
|
||||||
|
surface = surfaces[0]
|
||||||
|
|
||||||
|
self.play(
|
||||||
|
FadeIn(surface),
|
||||||
|
ShowCreation(surface.mesh, lag_ratio=0.01, run_time=3),
|
||||||
|
)
|
||||||
|
for mob in surfaces:
|
||||||
|
mob.add(mob.mesh)
|
||||||
|
surface.save_state()
|
||||||
|
self.play(Rotate(surface, PI / 2), run_time=2)
|
||||||
|
for mob in surfaces[1:]:
|
||||||
|
mob.rotate(PI / 2)
|
||||||
|
|
||||||
|
self.play(
|
||||||
|
Transform(surface, surfaces[1]),
|
||||||
|
run_time=3
|
||||||
|
)
|
||||||
|
|
||||||
|
self.play(
|
||||||
|
Transform(surface, surfaces[2]),
|
||||||
|
# Move camera frame during the transition
|
||||||
|
frame.increment_phi, -10 * DEGREES,
|
||||||
|
frame.increment_theta, -20 * DEGREES,
|
||||||
|
run_time=3
|
||||||
|
)
|
||||||
|
# Add ambient rotation
|
||||||
|
frame.add_updater(lambda m, dt: m.increment_theta(-0.1 * dt))
|
||||||
|
|
||||||
|
# Play around with where the light is
|
||||||
|
light = self.camera.light_source
|
||||||
|
self.add(light)
|
||||||
|
light.save_state()
|
||||||
|
self.play(light.move_to, 3 * IN, run_time=5)
|
||||||
|
self.play(light.shift, 10 * OUT, run_time=5)
|
||||||
|
self.wait(4)
|
||||||
|
|
||||||
|
|
||||||
# See https://github.com/3b1b/videos for many, many more
|
# See https://github.com/3b1b/videos for many, many more
|
||||||
|
Reference in New Issue
Block a user