Skip to content

Commit 294efcd

Browse files
Fixed render flow issues with introducer animations (#2594)
* only let introducer add mobject if not yet present * fix check for empty moving_mobjects list * added two tests * added control data * black * fixed usage of Mock in some tests * check family members instead of mobject list * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * moved moving_mobjects / static_mobjects assignment to begin_animations * restored correct render flow, made sure static_image is created properly * fixed some tests * make sure scene_finished handles frame update correctly * improve / fix test_vector_scene * black Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 9bae654 commit 294efcd

File tree

10 files changed

+47
-19
lines changed

10 files changed

+47
-19
lines changed

manim/animation/animation.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,10 @@ def _setup_scene(self, scene: Scene) -> None:
233233
"""
234234
if scene is None:
235235
return
236-
if self.is_introducer():
236+
if (
237+
self.is_introducer()
238+
and self.mobject not in scene.get_mobject_family_members()
239+
):
237240
scene.add(self.mobject)
238241

239242
def create_starting_mobject(self) -> Mobject:

manim/renderer/cairo_renderer.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,13 +86,14 @@ def play(self, scene, *args, **kwargs):
8686
{"h": str(self.animations_hashes[:5])},
8787
)
8888

89+
self.file_writer.begin_animation(not self.skip_animations)
90+
scene.begin_animations()
91+
8992
# Save a static image, to avoid rendering non moving objects.
9093
self.static_image = self.save_static_frame_data(scene, scene.static_mobjects)
9194

92-
self.file_writer.begin_animation(not self.skip_animations)
93-
scene.begin_animations()
9495
if scene.is_current_animation_frozen_frame():
95-
self.update_frame(scene)
96+
self.update_frame(scene, mobjects=scene.moving_mobjects)
9697
# self.duration stands for the total run time of all the animations.
9798
# In this case, as there is only a wait, it will be the length of the wait.
9899
self.freeze_current_frame(scene.duration)
@@ -218,8 +219,8 @@ def save_static_frame_data(
218219
typing.Iterable[Mobject]
219220
the static image computed.
220221
"""
222+
self.static_image = None
221223
if not static_mobjects:
222-
self.static_image = None
223224
return None
224225
self.update_frame(scene, mobjects=static_mobjects)
225226
self.static_image = self.get_frame()
@@ -258,8 +259,10 @@ def scene_finished(self, scene):
258259
config.save_last_frame = True
259260
config.write_to_movie = False
260261
else:
262+
self.static_image = None
261263
self.update_frame(scene)
262264

263265
if config["save_last_frame"]:
266+
self.static_image = None
264267
self.update_frame(scene)
265268
self.file_writer.save_final_image(self.camera.get_image())

manim/scene/scene.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -451,7 +451,7 @@ def add(self, *mobjects):
451451
mobjects = [*mobjects, *self.foreground_mobjects]
452452
self.restructure_mobjects(to_remove=mobjects)
453453
self.mobjects += mobjects
454-
if self.moving_mobjects is not None:
454+
if self.moving_mobjects:
455455
self.restructure_mobjects(
456456
to_remove=mobjects,
457457
mobject_list_name="moving_mobjects",
@@ -1074,13 +1074,6 @@ def compile_animation_data(self, *animations: Animation, **play_kwargs):
10741074
# Static image logic when the wait is static is done by the renderer, not here.
10751075
self.animations[0].is_static_wait = True
10761076
return None
1077-
elif config.renderer != "opengl":
1078-
# Paint all non-moving objects onto the screen, so they don't
1079-
# have to be rendered every frame
1080-
(
1081-
self.moving_mobjects,
1082-
self.static_mobjects,
1083-
) = self.get_moving_and_static_mobjects(self.animations)
10841077
self.duration = self.get_run_time(self.animations)
10851078
return self
10861079

@@ -1090,6 +1083,14 @@ def begin_animations(self) -> None:
10901083
animation._setup_scene(self)
10911084
animation.begin()
10921085

1086+
if config.renderer != "opengl":
1087+
# Paint all non-moving objects onto the screen, so they don't
1088+
# have to be rendered every frame
1089+
(
1090+
self.moving_mobjects,
1091+
self.static_mobjects,
1092+
) = self.get_moving_and_static_mobjects(self.animations)
1093+
10931094
def is_current_animation_frozen_frame(self) -> bool:
10941095
"""Returns whether the current animation produces a static frame (generally a Wait)."""
10951096
return (

tests/opengl/test_composition_opengl.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from __future__ import annotations
22

3-
from unittest.mock import Mock
3+
from unittest.mock import MagicMock
44

55
from manim.animation.animation import Animation, Wait
66
from manim.animation.composition import AnimationGroup, Succession
@@ -18,7 +18,7 @@ def test_succession_timing(using_opengl_renderer):
1818
animation_4s = FadeOut(line, shift=DOWN, run_time=4.0)
1919
succession = Succession(animation_1s, animation_4s)
2020
assert succession.get_run_time() == 5.0
21-
succession._setup_scene(Mock())
21+
succession._setup_scene(MagicMock())
2222
succession.begin()
2323
assert succession.active_index == 0
2424
# The first animation takes 20% of the total run time.
@@ -50,7 +50,7 @@ def test_succession_in_succession_timing(using_opengl_renderer):
5050
)
5151
assert nested_succession.get_run_time() == 5.0
5252
assert succession.get_run_time() == 10.0
53-
succession._setup_scene(Mock())
53+
succession._setup_scene(MagicMock())
5454
succession.begin()
5555
succession.interpolate(0.1)
5656
assert succession.active_index == 0

tests/test_composition.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from __future__ import annotations
22

3-
from unittest.mock import Mock
3+
from unittest.mock import MagicMock
44

55
import pytest
66

@@ -22,7 +22,7 @@ def test_succession_timing():
2222
animation_4s = FadeOut(line, shift=DOWN, run_time=4.0)
2323
succession = Succession(animation_1s, animation_4s)
2424
assert succession.get_run_time() == 5.0
25-
succession._setup_scene(Mock())
25+
succession._setup_scene(MagicMock())
2626
succession.begin()
2727
assert succession.active_index == 0
2828
# The first animation takes 20% of the total run time.
@@ -54,7 +54,7 @@ def test_succession_in_succession_timing():
5454
)
5555
assert nested_succession.get_run_time() == 5.0
5656
assert succession.get_run_time() == 10.0
57-
succession._setup_scene(Mock())
57+
succession._setup_scene(MagicMock())
5858
succession.begin()
5959
succession.interpolate(0.1)
6060
assert succession.active_index == 0
9.09 KB
Binary file not shown.
31.2 KB
Binary file not shown.
29.6 KB
Binary file not shown.

tests/test_graphical_units/test_creation.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,23 @@ def test_SpinInFromNothing(scene):
6767
def test_ShrinkToCenter(scene):
6868
square = Square()
6969
scene.play(ShrinkToCenter(square))
70+
71+
72+
@frames_comparison(last_frame=False)
73+
def test_bring_to_back_introducer(scene):
74+
a = Square(color=RED, fill_opacity=1)
75+
b = Square(color=BLUE, fill_opacity=1).shift(RIGHT)
76+
scene.add(a)
77+
scene.bring_to_back(b)
78+
scene.play(FadeIn(b))
79+
scene.wait()
80+
81+
82+
@frames_comparison(last_frame=False)
83+
def test_z_index_introducer(scene):
84+
a = Circle().set_fill(color=RED, opacity=1.0)
85+
scene.add(a)
86+
b = Circle(arc_center=(0.5, 0.5, 0.0), color=GREEN, fill_opacity=1)
87+
b.set_z_index(-1)
88+
scene.play(Create(b))
89+
scene.wait()

tests/test_graphical_units/test_vector_scene.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,4 @@ def test_vector_to_coords(scene):
1313
basis = scene.get_basis_vectors()
1414
scene.add(basis)
1515
scene.vector_to_coords(vector=vector)
16+
scene.wait()

0 commit comments

Comments
 (0)