From 900e6ac837459977d0033164fd8cf03e8ae9f609 Mon Sep 17 00:00:00 2001 From: Grant Sanderson Date: Fri, 25 Jan 2019 10:13:17 -0800 Subject: [PATCH] Use frame_rate, instead of frame_duration, and make that part of the camera rather than the scene --- active_projects/clacks/name_bump.py | 1 - manimlib/camera/camera.py | 1 + manimlib/config.py | 77 +++++++++++++++-------------- manimlib/constants.py | 9 ++-- manimlib/extract_scene.py | 1 - manimlib/scene/scene.py | 14 +++--- manimlib/scene/scene_file_writer.py | 11 +++-- manimlib/scene/scene_from_video.py | 3 +- manimlib/scene/three_d_scene.py | 4 +- manimlib/stream_starter.py | 1 - old_projects/bell.py | 4 +- stage_scenes.py | 1 - 12 files changed, 66 insertions(+), 61 deletions(-) diff --git a/active_projects/clacks/name_bump.py b/active_projects/clacks/name_bump.py index 7ef69b59..e7972b53 100644 --- a/active_projects/clacks/name_bump.py +++ b/active_projects/clacks/name_bump.py @@ -80,5 +80,4 @@ class NameBump(BlocksAndWallExample): # write_to_movie=True, # output_file_name=file_name, # camera_config=PRODUCTION_QUALITY_CAMERA_CONFIG, -# frame_duration=PRODUCTION_QUALITY_FRAME_DURATION, # ) diff --git a/manimlib/camera/camera.py b/manimlib/camera/camera.py index 6741288a..ff3500a6 100644 --- a/manimlib/camera/camera.py +++ b/manimlib/camera/camera.py @@ -30,6 +30,7 @@ class Camera(object): "background_image": None, "pixel_height": DEFAULT_PIXEL_HEIGHT, "pixel_width": DEFAULT_PIXEL_WIDTH, + "frame_duration": DEFAULT_FRAME_DURATION, # Note: frame height and width will be resized to match # the pixel aspect ratio "frame_height": FRAME_HEIGHT, diff --git a/manimlib/config.py b/manimlib/config.py index db415cef..d56b1921 100644 --- a/manimlib/config.py +++ b/manimlib/config.py @@ -181,43 +181,7 @@ def get_configuration(args): } # Camera configuration - config["camera_config"] = {} - if args.low_quality: - config["camera_config"].update(manimlib.constants.LOW_QUALITY_CAMERA_CONFIG) - config["frame_duration"] = manimlib.constants.LOW_QUALITY_FRAME_DURATION - elif args.medium_quality: - config["camera_config"].update(manimlib.constants.MEDIUM_QUALITY_CAMERA_CONFIG) - config["frame_duration"] = manimlib.constants.MEDIUM_QUALITY_FRAME_DURATION - else: - config["camera_config"].update(manimlib.constants.PRODUCTION_QUALITY_CAMERA_CONFIG) - config["frame_duration"] = manimlib.constants.PRODUCTION_QUALITY_FRAME_DURATION - - # If the resolution was passed in via -r - if args.resolution: - if "," in args.resolution: - height_str, width_str = args.resolution.split(",") - height = int(height_str) - width = int(width_str) - else: - height = int(args.resolution) - width = int(16 * height / 9) - config["camera_config"].update({ - "pixel_height": height, - "pixel_width": width, - }) - - if args.color: - try: - config["camera_config"]["background_color"] = colour.Color(args.color) - except AttributeError as err: - print("Please use a valid color") - print(err) - sys.exit(2) - - # If rendering a transparent image/move, make sure the - # scene has a background opacity of 0 - if args.transparent: - config["camera_config"]["background_opacity"] = 0 + config["camera_config"] = get_camera_configuration(args) # Arguments related to skipping stan = config["start_at_animation_number"] @@ -234,3 +198,42 @@ def get_configuration(args): config["start_at_animation_number"], ]) return config + + +def get_camera_configuration(args): + camera_config = {} + if args.low_quality: + camera_config.update(manimlib.constants.LOW_QUALITY_CAMERA_CONFIG) + elif args.medium_quality: + camera_config.update(manimlib.constants.MEDIUM_QUALITY_CAMERA_CONFIG) + else: + camera_config.update(manimlib.constants.PRODUCTION_QUALITY_CAMERA_CONFIG) + + # If the resolution was passed in via -r + if args.resolution: + if "," in args.resolution: + height_str, width_str = args.resolution.split(",") + height = int(height_str) + width = int(width_str) + else: + height = int(args.resolution) + width = int(16 * height / 9) + camera_config.update({ + "pixel_height": height, + "pixel_width": width, + }) + + if args.color: + try: + camera_config["background_color"] = colour.Color(args.color) + except AttributeError as err: + print("Please use a valid color") + print(err) + sys.exit(2) + + # If rendering a transparent image/move, make sure the + # scene has a background opacity of 0 + if args.transparent: + camera_config["background_opacity"] = 0 + + return camera_config diff --git a/manimlib/constants.py b/manimlib/constants.py index fe17b959..b34da3b5 100644 --- a/manimlib/constants.py +++ b/manimlib/constants.py @@ -82,33 +82,34 @@ NO_SCENE_MESSAGE = """ There are no scenes inside that module """ -LOW_QUALITY_FRAME_DURATION = 1. / 15 -MEDIUM_QUALITY_FRAME_DURATION = 1. / 30 -PRODUCTION_QUALITY_FRAME_DURATION = 1. / 60 - # There might be other configuration than pixel shape later... PRODUCTION_QUALITY_CAMERA_CONFIG = { "pixel_height": 1440, "pixel_width": 2560, + "frame_rate": 60, } HIGH_QUALITY_CAMERA_CONFIG = { "pixel_height": 1080, "pixel_width": 1920, + "frame_rate": 30, } MEDIUM_QUALITY_CAMERA_CONFIG = { "pixel_height": 720, "pixel_width": 1280, + "frame_rate": 30, } LOW_QUALITY_CAMERA_CONFIG = { "pixel_height": 480, "pixel_width": 854, + "frame_rate": 15, } DEFAULT_PIXEL_HEIGHT = PRODUCTION_QUALITY_CAMERA_CONFIG["pixel_height"] DEFAULT_PIXEL_WIDTH = PRODUCTION_QUALITY_CAMERA_CONFIG["pixel_width"] +DEFAULT_FRAME_DURATION = 30 DEFAULT_POINT_DENSITY_2D = 25 DEFAULT_POINT_DENSITY_1D = 250 diff --git a/manimlib/extract_scene.py b/manimlib/extract_scene.py index 94c327e6..5f59c489 100644 --- a/manimlib/extract_scene.py +++ b/manimlib/extract_scene.py @@ -123,7 +123,6 @@ def main(config): (key, config[key]) for key in [ "camera_config", - "frame_duration", "skip_animations", "file_writer_config", "start_at_animation_number", diff --git a/manimlib/scene/scene.py b/manimlib/scene/scene.py index 009bfd98..66f4dc5e 100644 --- a/manimlib/scene/scene.py +++ b/manimlib/scene/scene.py @@ -22,7 +22,6 @@ class Scene(Container): CONFIG = { "camera_class": Camera, "camera_config": {}, - "frame_duration": LOW_QUALITY_FRAME_DURATION, "file_writer_config": {}, "skip_animations": False, "always_continually_update": False, @@ -355,7 +354,7 @@ class Scene(Container): if self.skip_animations and not override_skip_animations: times = [run_time] else: - step = self.frame_duration + step = 1 / self.camera.frame_rate times = np.arange(0, run_time, step) time_progression = ProgressDisplay( times, total=n_iterations, @@ -480,7 +479,8 @@ class Scene(Container): for t in self.get_animation_time_progression(animations): for animation in animations: animation.update(t / animation.run_time) - self.continual_update(dt=self.frame_duration) + dt = 1 / self.camera.frame_rate + self.continual_update(dt) self.update_frame(moving_mobjects, static_image) self.add_frames(self.get_frame()) self.mobjects_from_last_animation = [ @@ -527,10 +527,11 @@ class Scene(Container): @handle_play_like_call def wait(self, duration=DEFAULT_WAIT_TIME, stop_condition=None): + dt = 1 / self.camera.frame_rate if self.should_continually_update(): time_progression = self.get_wait_time_progression(duration, stop_condition) for t in time_progression: - self.continual_update(dt=self.frame_duration) + self.continual_update(dt) self.update_frame() self.add_frames(self.get_frame()) if stop_condition and stop_condition(): @@ -541,7 +542,7 @@ class Scene(Container): return self else: self.update_frame() - n_frames = int(duration / self.frame_duration) + n_frames = int(duration / dt) frame = self.get_frame() self.add_frames(*[frame] * n_frames) return self @@ -560,7 +561,8 @@ class Scene(Container): return self def add_frames(self, *frames): - self.increment_time(len(frames) * self.frame_duration) + dt = 1 / self.camera.frame_rate + self.increment_time(len(frames) * dt) if self.skip_animations: return for frame in frames: diff --git a/manimlib/scene/scene_file_writer.py b/manimlib/scene/scene_file_writer.py index e19afc48..7337748e 100644 --- a/manimlib/scene/scene_file_writer.py +++ b/manimlib/scene/scene_file_writer.py @@ -84,9 +84,9 @@ class SceneFileWriter(object): def get_movie_directory(self): pixel_height = self.scene.camera.pixel_height - frame_duration = self.scene.frame_duration + frame_rate = self.scene.camera.frame_rate return "{}p{}".format( - pixel_height, int(1.0 / frame_duration) + pixel_height, frame_rate ) def get_image_directory(self): @@ -178,8 +178,9 @@ class SceneFileWriter(object): self.add_frames(*[frame] * n_frames) b = datetime.datetime.now() time_diff = (b - a).total_seconds() - if time_diff < self.frame_duration: - sleep(self.frame_duration - time_diff) + frame_duration = 1 / self.scene.camera.frame_rate + if time_diff < frame_duration: + sleep(frame_duration - time_diff) def finish(self): if self.write_to_movie: @@ -197,7 +198,7 @@ class SceneFileWriter(object): self.partial_movie_file_path = file_path self.temp_partial_movie_file_path = temp_file_path - fps = int(1 / self.scene.frame_duration) + fps = self.scene.camera.frame_rate height = self.scene.camera.get_pixel_height() width = self.scene.camera.get_pixel_width() diff --git a/manimlib/scene/scene_from_video.py b/manimlib/scene/scene_from_video.py index 72a78ec5..d7957ae1 100644 --- a/manimlib/scene/scene_from_video.py +++ b/manimlib/scene/scene_from_video.py @@ -4,6 +4,7 @@ import cv2 from manimlib.scene.scene import Scene +# TODO, is this depricated? class SceneFromVideo(Scene): def construct(self, file_name, freeze_last_frame=True, @@ -14,7 +15,7 @@ class SceneFromVideo(Scene): int(cap.get(cv2.cv.CV_CAP_PROP_FRAME_WIDTH)) ) fps = cap.get(cv2.cv.CV_CAP_PROP_FPS) - self.frame_duration = 1.0 / fps + self.camera.frame_rate = fps frame_count = int(cap.get(cv2.cv.CV_CAP_PROP_FRAME_COUNT)) if time_range is None: start_frame = 0 diff --git a/manimlib/scene/three_d_scene.py b/manimlib/scene/three_d_scene.py index 1abe82c0..e7d74e7f 100644 --- a/manimlib/scene/three_d_scene.py +++ b/manimlib/scene/three_d_scene.py @@ -1,7 +1,7 @@ from manimlib.animation.transform import ApplyMethod from manimlib.camera.three_d_camera import ThreeDCamera from manimlib.constants import DEGREES -from manimlib.constants import PRODUCTION_QUALITY_FRAME_DURATION +from manimlib.constants import PRODUCTION_QUALITY_CAMERA_CONFIG from manimlib.continual_animation.update import ContinualGrowValue from manimlib.mobject.coordinate_systems import ThreeDAxes from manimlib.mobject.geometry import Line @@ -146,7 +146,7 @@ class SpecialThreeDScene(ThreeDScene): def __init__(self, **kwargs): digest_config(self, kwargs) - if self.frame_duration == PRODUCTION_QUALITY_FRAME_DURATION: + if self.camera.get_pixel_width() == PRODUCTION_QUALITY_CAMERA_CONFIG["pixel_width"]: config = {} else: config = self.low_quality_config diff --git a/manimlib/stream_starter.py b/manimlib/stream_starter.py index f3477baa..e164aa19 100644 --- a/manimlib/stream_starter.py +++ b/manimlib/stream_starter.py @@ -31,7 +31,6 @@ def start_livestream(to_twitch=False, twitch_key=None): "end_at_animation_number": None, "skip_animations": False, "camera_config": manimlib.constants.HIGH_QUALITY_CAMERA_CONFIG, - "frame_duration": manimlib.constants.MEDIUM_QUALITY_FRAME_DURATION, "livestreaming": True, "to_twitch": to_twitch, "twitch_key": twitch_key, diff --git a/old_projects/bell.py b/old_projects/bell.py index 7ba81ba3..98139f41 100644 --- a/old_projects/bell.py +++ b/old_projects/bell.py @@ -2360,7 +2360,7 @@ class ReEmphasizeVennDiagram(VennDiagramProofByContradiction): C_freq = -0.7 self.time = 0 - dt = self.frame_duration + dt = 1 / self.camera.frame_rate def move_around(total_time): self.time @@ -2371,7 +2371,7 @@ class ReEmphasizeVennDiagram(VennDiagramProofByContradiction): new_B_to_C = rotate_vector(B_to_C, self.time*C_freq) A_group.shift(B_center + new_B_to_A - center_of_mass(A_ref)) C_group.shift(B_center + new_B_to_C - center_of_mass(C_ref)) - self.wait(self.frame_duration) + self.wait(dt) move_around(3) self.add(self.footnote) diff --git a/stage_scenes.py b/stage_scenes.py index 65e055aa..6fff1586 100644 --- a/stage_scenes.py +++ b/stage_scenes.py @@ -37,7 +37,6 @@ def stage_animations(module_name): return output_directory_kwargs = { "camera_config": PRODUCTION_QUALITY_CAMERA_CONFIG, - "frame_duration": PRODUCTION_QUALITY_FRAME_DURATION, } animation_dir = get_movie_output_directory( scene_classes[0], **output_directory_kwargs