mirror of
https://github.com/3b1b/manim.git
synced 2025-09-01 00:48:45 +00:00
Use frame_rate, instead of frame_duration, and make that part of the camera rather than the scene
This commit is contained in:
parent
eca8d77f83
commit
900e6ac837
12 changed files with 66 additions and 61 deletions
|
@ -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,
|
||||
# )
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue