Use frame_rate, instead of frame_duration, and make that part of the camera rather than the scene

This commit is contained in:
Grant Sanderson 2019-01-25 10:13:17 -08:00
parent eca8d77f83
commit 900e6ac837
12 changed files with 66 additions and 61 deletions

View file

@ -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,
# )

View file

@ -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,

View file

@ -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

View file

@ -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

View file

@ -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",

View file

@ -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:

View file

@ -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()

View file

@ -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

View file

@ -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

View file

@ -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,

View file

@ -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)

View file

@ -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