mirror of
https://github.com/3b1b/manim.git
synced 2025-08-05 16:49:03 +00:00
Merge branch 'lighthouse-grant' into lighthouse2
This commit is contained in:
commit
3944c8a2d8
11 changed files with 4711 additions and 100 deletions
|
@ -426,7 +426,6 @@ class IntroScene(PiCreatureScene):
|
|||
|
||||
self.ellipsis = TexMobject("\cdots")
|
||||
self.ellipsis.scale(0.4)
|
||||
|
||||
for i in range(5, max_n1):
|
||||
|
||||
if i == 5:
|
||||
|
@ -441,7 +440,6 @@ class IntroScene(PiCreatureScene):
|
|||
GrowFromPoint(self.rects[i], self.euler_sum[10].get_center(),
|
||||
run_time = 0.5)
|
||||
)
|
||||
|
||||
for i in range(max_n1, max_n2):
|
||||
self.play(
|
||||
GrowFromPoint(self.rects[i], self.euler_sum[10].get_center(),
|
||||
|
@ -929,15 +927,11 @@ class SingleLighthouseScene(PiCreatureScene):
|
|||
|
||||
|
||||
class MorphIntoSunScene(PiCreatureScene):
|
||||
|
||||
def construct(self):
|
||||
|
||||
self.setup_elements()
|
||||
self.morph_lighthouse_into_sun()
|
||||
|
||||
|
||||
def setup_elements(self):
|
||||
|
||||
self.remove(self.get_primary_pi_creature())
|
||||
|
||||
SCREEN_SIZE = 3.0
|
||||
|
@ -988,10 +982,8 @@ class MorphIntoSunScene(PiCreatureScene):
|
|||
|
||||
self.add_foreground_mobject(self.light_source.shadow)
|
||||
self.add_foreground_mobject(morty)
|
||||
|
||||
self.light_source.dim_ambient
|
||||
self.add(self.light_source.spotlight)
|
||||
|
||||
self.screen_tracker = ScreenTracker(self.light_source)
|
||||
self.add(self.screen_tracker)
|
||||
|
||||
|
@ -4351,10 +4343,6 @@ class ArcHighlightOverlayScene(Scene):
|
|||
)
|
||||
|
||||
|
||||
flash_arcs(3)
|
||||
|
||||
|
||||
|
||||
|
||||
class ThumbnailScene(Scene):
|
||||
|
||||
|
@ -4545,14 +4533,4 @@ class RightAnglesOverlay(Scene):
|
|||
|
||||
self.play(FadeOut(lines))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
flash_arcs(3)
|
||||
|
|
4651
active_projects/basel2.py
Normal file
4651
active_projects/basel2.py
Normal file
File diff suppressed because it is too large
Load diff
|
@ -101,9 +101,15 @@ class Swap(CyclicReplace):
|
|||
pass #Renaming, more understandable for two entries
|
||||
|
||||
class GrowFromPoint(Transform):
|
||||
CONFIG = {
|
||||
"point_color" : None,
|
||||
}
|
||||
def __init__(self, mobject, point, **kwargs):
|
||||
digest_config(self, kwargs)
|
||||
target = mobject.copy()
|
||||
point_mob = Point(point)
|
||||
if self.point_color:
|
||||
point_mob.highlight(self.point_color)
|
||||
mobject.replace(point_mob)
|
||||
mobject.highlight(point_mob.get_color())
|
||||
Transform.__init__(self, mobject, target, **kwargs)
|
||||
|
|
|
@ -18,7 +18,6 @@ from camera import Camera
|
|||
HELP_MESSAGE = """
|
||||
Usage:
|
||||
python extract_scene.py <module> [<scene name>]
|
||||
|
||||
-p preview in low quality
|
||||
-s show and save picture of last frame
|
||||
-w write result to file [this is default if nothing else is stated]
|
||||
|
@ -35,7 +34,6 @@ SCENE_NOT_FOUND_MESSAGE = """
|
|||
CHOOSE_NUMBER_MESSAGE = """
|
||||
Choose number corresponding to desired scene/arguments.
|
||||
(Use comma separated list for multiple entries)
|
||||
|
||||
Choice(s): """
|
||||
INVALID_NUMBER_MESSAGE = "Fine then, if you don't want to give a valid number I'll just quit"
|
||||
|
||||
|
@ -95,6 +93,7 @@ def get_configuration():
|
|||
"save_pngs" : args.save_pngs,
|
||||
#If -t is passed in (for transparent), this will be RGBA
|
||||
"saved_image_mode": "RGBA" if args.transparent else "RGB",
|
||||
"movie_file_extension" : ".mov" if args.transparent else ".mp4",
|
||||
"quiet" : args.quiet or args.write_all,
|
||||
"ignore_waits" : args.preview,
|
||||
"write_all" : args.write_all,
|
||||
|
@ -237,6 +236,7 @@ def main():
|
|||
"write_to_movie",
|
||||
"output_directory",
|
||||
"save_pngs",
|
||||
"movie_file_extension",
|
||||
"start_at_animation_number",
|
||||
"end_at_animation_number",
|
||||
]
|
||||
|
@ -260,4 +260,4 @@ def main():
|
|||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
main()
|
|
@ -693,6 +693,7 @@ class DictAsObject(object):
|
|||
def __init__(self, dict):
|
||||
self.__dict__ = dict
|
||||
|
||||
# Just to have a less heavyweight name for this extremely common operation
|
||||
#
|
||||
# We may wish to have more fine-grained control over division by zero behavior
|
||||
# in the future (separate specifiable values for 0/0 and x/0 with x != 0),
|
||||
|
@ -707,7 +708,6 @@ def fdiv(a, b, zero_over_zero_value = None):
|
|||
|
||||
return np.true_divide(a, b, out = out, where = where)
|
||||
|
||||
|
||||
def add_extension_if_not_present(file_name, extension):
|
||||
# This could conceivably be smarter about handling existing differing extensions
|
||||
if(file_name[-len(extension):] != extension):
|
||||
|
|
|
@ -389,6 +389,9 @@ class Mobject(Container):
|
|||
def stretch_to_fit_height(self, height, **kwargs):
|
||||
return self.rescale_to_fit(height, 1, stretch = True, **kwargs)
|
||||
|
||||
def stretch_to_fit_depth(self, depth, **kwargs):
|
||||
return self.rescale_to_fit(depth, 1, stretch = True, **kwargs)
|
||||
|
||||
def scale_to_fit_width(self, width, **kwargs):
|
||||
return self.rescale_to_fit(width, 0, stretch = False, **kwargs)
|
||||
|
||||
|
|
|
@ -37,9 +37,9 @@ class SVGMobject(VMobject):
|
|||
if self.file_name is None:
|
||||
raise Exception("Must specify file for SVGMobject")
|
||||
possible_paths = [
|
||||
self.file_name,
|
||||
os.path.join(SVG_IMAGE_DIR, self.file_name),
|
||||
os.path.join(SVG_IMAGE_DIR, self.file_name + ".svg"),
|
||||
self.file_name,
|
||||
]
|
||||
for path in possible_paths:
|
||||
if os.path.exists(path):
|
||||
|
|
|
@ -82,7 +82,7 @@ class Scene(Container):
|
|||
def setup(self):
|
||||
"""
|
||||
This is meant to be implement by any scenes which
|
||||
are commonly subclassed, and have some common setup
|
||||
are comonly subclassed, and have some common setup
|
||||
involved before the construct method is called.
|
||||
"""
|
||||
pass
|
||||
|
@ -366,7 +366,6 @@ class Scene(Container):
|
|||
Each arg can either be an animation, or a mobject method
|
||||
followed by that methods arguments (and potentially follow
|
||||
by a dict of kwargs for that method).
|
||||
|
||||
This animation list is built by going through the args list,
|
||||
and each animation is simply added, but when a mobject method
|
||||
s hit, a MoveToTarget animation is built using the args that
|
||||
|
@ -387,7 +386,7 @@ class Scene(Container):
|
|||
animations.pop()
|
||||
#method should already have target then.
|
||||
else:
|
||||
mobject.target = mobject.deepcopy()
|
||||
mobject.generate_target()
|
||||
#
|
||||
if len(state["method_args"]) > 0 and isinstance(state["method_args"][-1], dict):
|
||||
method_kwargs = state["method_args"].pop()
|
||||
|
@ -578,17 +577,12 @@ class Scene(Container):
|
|||
FFMPEG_BIN,
|
||||
'-y', # overwrite output file if it exists
|
||||
'-f', 'rawvideo',
|
||||
'-vcodec','rawvideo',
|
||||
'-s', '%dx%d'%(width, height), # size of one frame
|
||||
'-pix_fmt', 'rgba',
|
||||
'-r', str(fps), # frames per second
|
||||
'-i', '-', # The imput comes from a pipe
|
||||
'-an', # Tells FFMPEG not to expect any audio
|
||||
'-vcodec', 'mpeg',
|
||||
'-c:v', 'libx264',
|
||||
'-pix_fmt', 'yuv420p',
|
||||
'-loglevel', 'error',
|
||||
temp_file_path,
|
||||
]
|
||||
if self.movie_file_extension == ".mov":
|
||||
# This is if the background of the exported video
|
||||
|
@ -624,4 +618,3 @@ class EndSceneEarlyException(Exception):
|
|||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -123,8 +123,11 @@ class PatreonEndScreen(PatreonThanks):
|
|||
"n_patron_columns" : 3,
|
||||
"max_patron_width" : 3,
|
||||
"run_time" : 20,
|
||||
"randomize_order" : True,
|
||||
}
|
||||
def construct(self):
|
||||
if self.randomize_order:
|
||||
random.shuffle(self.specific_patrons)
|
||||
self.add_title()
|
||||
self.scroll_through_patrons()
|
||||
|
||||
|
@ -141,7 +144,6 @@ class PatreonEndScreen(PatreonThanks):
|
|||
pi.next_to(title, vect, buff = MED_LARGE_BUFF)
|
||||
self.add_foreground_mobjects(title, randy, morty)
|
||||
|
||||
|
||||
def scroll_through_patrons(self):
|
||||
logo_box = Square(side_length = 2.5)
|
||||
logo_box.to_corner(DOWN+LEFT, buff = MED_LARGE_BUFF)
|
||||
|
@ -176,7 +178,7 @@ class PatreonEndScreen(PatreonThanks):
|
|||
aligned_edge = UP,
|
||||
)
|
||||
columns.scale_to_fit_width(total_width - 1)
|
||||
columns.next_to(black_rect, DOWN, LARGE_BUFF)
|
||||
columns.next_to(black_rect, DOWN, 3*LARGE_BUFF)
|
||||
columns.to_edge(RIGHT)
|
||||
|
||||
self.play(
|
||||
|
|
|
@ -128,7 +128,6 @@ class LightSource(VMobject):
|
|||
self.camera_mob = new_cam_mob
|
||||
self.spotlight.camera_mob = new_cam_mob
|
||||
|
||||
|
||||
def set_screen(self, new_screen):
|
||||
if self.has_screen():
|
||||
self.spotlight.screen = new_screen
|
||||
|
@ -160,9 +159,6 @@ class LightSource(VMobject):
|
|||
# in any case
|
||||
self.screen = new_screen
|
||||
|
||||
|
||||
|
||||
|
||||
def move_source_to(self,point):
|
||||
apoint = np.array(point)
|
||||
v = apoint - self.get_source_point()
|
||||
|
@ -195,14 +191,13 @@ class LightSource(VMobject):
|
|||
self.spotlight.update_sectors()
|
||||
self.update_shadow()
|
||||
|
||||
|
||||
def update_lighthouse(self):
|
||||
new_lh = Lighthouse()
|
||||
new_lh.move_to(ORIGIN)
|
||||
new_lh.apply_matrix(self.rotation_matrix())
|
||||
new_lh.shift(self.get_source_point())
|
||||
self.lighthouse.submobjects = new_lh.submobjects
|
||||
|
||||
self.lighthouse.move_to(self.get_source_point())
|
||||
# new_lh = Lighthouse()
|
||||
# new_lh.move_to(ORIGIN)
|
||||
# new_lh.apply_matrix(self.rotation_matrix())
|
||||
# new_lh.shift(self.get_source_point())
|
||||
# self.lighthouse.submobjects = new_lh.submobjects
|
||||
|
||||
def update_ambient(self):
|
||||
new_ambient_light = AmbientLight(
|
||||
|
@ -217,12 +212,9 @@ class LightSource(VMobject):
|
|||
new_ambient_light.move_source_to(self.get_source_point())
|
||||
self.ambient_light.submobjects = new_ambient_light.submobjects
|
||||
|
||||
|
||||
|
||||
def get_source_point(self):
|
||||
return self.source_point.get_location()
|
||||
|
||||
|
||||
def rotation_matrix(self):
|
||||
|
||||
if self.camera_mob == None:
|
||||
|
@ -247,9 +239,7 @@ class LightSource(VMobject):
|
|||
R = np.dot(R2, R1)
|
||||
return R
|
||||
|
||||
|
||||
def update_shadow(self):
|
||||
|
||||
point = self.get_source_point()
|
||||
projected_screen_points = []
|
||||
if not self.has_screen():
|
||||
|
@ -319,7 +309,6 @@ class LightSource(VMobject):
|
|||
self.shadow.mark_paths_closed = True
|
||||
|
||||
|
||||
|
||||
class SwitchOn(LaggedStart):
|
||||
CONFIG = {
|
||||
"lag_ratio": 0.2,
|
||||
|
@ -329,9 +318,9 @@ class SwitchOn(LaggedStart):
|
|||
def __init__(self, light, **kwargs):
|
||||
if (not isinstance(light,AmbientLight) and not isinstance(light,Spotlight)):
|
||||
raise Exception("Only AmbientLights and Spotlights can be switched on")
|
||||
LaggedStart.__init__(self,
|
||||
FadeIn, light, **kwargs)
|
||||
|
||||
LaggedStart.__init__(
|
||||
self, FadeIn, light, **kwargs
|
||||
)
|
||||
|
||||
class SwitchOff(LaggedStart):
|
||||
CONFIG = {
|
||||
|
@ -347,9 +336,6 @@ class SwitchOff(LaggedStart):
|
|||
FadeOut, light, **kwargs)
|
||||
light.submobjects = light.submobjects[::-1]
|
||||
|
||||
|
||||
|
||||
|
||||
class Lighthouse(SVGMobject):
|
||||
CONFIG = {
|
||||
"file_name" : "lighthouse",
|
||||
|
@ -361,7 +347,6 @@ class Lighthouse(SVGMobject):
|
|||
def move_to(self,point):
|
||||
self.next_to(point, DOWN, buff = 0)
|
||||
|
||||
|
||||
class AmbientLight(VMobject):
|
||||
|
||||
# Parameters are:
|
||||
|
@ -377,8 +362,8 @@ class AmbientLight(VMobject):
|
|||
"opacity_function" : lambda r : 1.0/(r+1.0)**2,
|
||||
"color" : LIGHT_COLOR,
|
||||
"max_opacity" : 1.0,
|
||||
"num_levels" : 10,
|
||||
"radius" : 10.0
|
||||
"num_levels" : NUM_LEVELS,
|
||||
"radius" : 5.0
|
||||
}
|
||||
|
||||
def generate_points(self):
|
||||
|
@ -438,21 +423,7 @@ class AmbientLight(VMobject):
|
|||
submob.set_fill(opacity = new_submob_alpha)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class Spotlight(VMobject):
|
||||
|
||||
CONFIG = {
|
||||
"source_point": VectorizedPoint(location = ORIGIN, stroke_width = 0, fill_opacity = 0),
|
||||
"opacity_function" : lambda r : 1.0/(r/2+1.0)**2,
|
||||
|
@ -481,13 +452,10 @@ class Spotlight(VMobject):
|
|||
w = project_along_vector(point,v)
|
||||
return w
|
||||
|
||||
|
||||
def get_source_point(self):
|
||||
return self.source_point.get_location()
|
||||
|
||||
|
||||
def generate_points(self):
|
||||
|
||||
self.submobjects = []
|
||||
|
||||
self.add(self.source_point)
|
||||
|
@ -503,13 +471,7 @@ class Spotlight(VMobject):
|
|||
new_sector = self.new_sector(r,dr,lower_angle,upper_angle)
|
||||
self.add(new_sector)
|
||||
|
||||
|
||||
def new_sector(self,r,dr,lower_angle,upper_angle):
|
||||
# Note: I'm not looking _too_ closely at the implementation
|
||||
# of these updates based on viewing angles and such. It seems to
|
||||
# behave as intended, but let me know if you'd like more thorough
|
||||
# scrutiny
|
||||
|
||||
alpha = self.max_opacity * self.opacity_function(r)
|
||||
annular_sector = AnnularSector(
|
||||
inner_radius = r,
|
||||
|
@ -545,7 +507,6 @@ class Spotlight(VMobject):
|
|||
else:
|
||||
return -absolute_angle
|
||||
|
||||
|
||||
def viewing_angles(self,screen):
|
||||
|
||||
screen_points = screen.get_anchors()
|
||||
|
@ -572,7 +533,6 @@ class Spotlight(VMobject):
|
|||
|
||||
return lower_ray, upper_ray
|
||||
|
||||
|
||||
def opening_angle(self):
|
||||
l,u = self.viewing_angles(self.screen)
|
||||
return u - l
|
||||
|
@ -592,21 +552,20 @@ class Spotlight(VMobject):
|
|||
self.update_sectors()
|
||||
return self
|
||||
|
||||
|
||||
def update_sectors(self):
|
||||
if self.screen == None:
|
||||
return
|
||||
for submob in self.submobject_family():
|
||||
for submob in self.submobjects:
|
||||
if type(submob) == AnnularSector:
|
||||
lower_angle, upper_angle = self.viewing_angles(self.screen)
|
||||
#dr = submob.outer_radius - submob.inner_radius
|
||||
dr = self.radius / self.num_levels
|
||||
new_submob = self.new_sector(submob.inner_radius,dr,lower_angle,upper_angle)
|
||||
submob.points = new_submob.points
|
||||
submob.set_fill(opacity = 10 * self.opacity_function(submob.outer_radius))
|
||||
|
||||
|
||||
|
||||
new_submob = self.new_sector(
|
||||
submob.inner_radius, dr, lower_angle, upper_angle
|
||||
)
|
||||
# submob.points = new_submob.points
|
||||
# submob.set_fill(opacity = 10 * self.opacity_function(submob.outer_radius))
|
||||
Transform(submob, new_submob).update(1)
|
||||
|
||||
def dimming(self,new_alpha):
|
||||
old_alpha = self.max_opacity
|
||||
|
@ -640,7 +599,27 @@ class Spotlight(VMobject):
|
|||
|
||||
|
||||
class ScreenTracker(ContinualAnimation):
|
||||
def __init__(self, light_source, **kwargs):
|
||||
self.light_source = light_source
|
||||
dummy_mob = Mobject()
|
||||
ContinualAnimation.__init__(self, dummy_mob, **kwargs)
|
||||
|
||||
def update_mobject(self, dt):
|
||||
self.mobject.update()
|
||||
self.light_source.update()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -144,7 +144,6 @@ class ContinualChangingDecimal(ContinualAnimation):
|
|||
|
||||
def update_mobject(self, dt):
|
||||
self.anim.update(self.internal_time)
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue