3b1b-manim/manimlib/animation/fading.py
2021-01-12 11:09:53 -10:00

165 lines
4.3 KiB
Python

import numpy as np
from manimlib.animation.animation import Animation
from manimlib.animation.transform import Transform
from manimlib.mobject.mobject import Group
from manimlib.constants import ORIGIN
from manimlib.utils.bezier import interpolate
from manimlib.utils.rate_functions import there_and_back
DEFAULT_FADE_LAG_RATIO = 0
class Fade(Transform):
CONFIG = {
"lag_ratio": DEFAULT_FADE_LAG_RATIO,
}
def __init__(self, mobject, shift=ORIGIN, scale=1, **kwargs):
self.shift_vect = shift
self.scale_factor = scale
super().__init__(mobject, **kwargs)
class FadeIn(Fade):
CONFIG = {
"lag_ratio": DEFAULT_FADE_LAG_RATIO,
}
def create_target(self):
return self.mobject
def create_starting_mobject(self):
start = super().create_starting_mobject()
start.set_opacity(0)
start.scale(1.0 / self.scale_factor)
start.shift(-self.shift_vect)
return start
class FadeOut(Fade):
CONFIG = {
"remover": True,
# Put it back in original state when done
"final_alpha_value": 0,
}
def create_target(self):
result = self.mobject.copy()
result.set_opacity(0)
result.shift(self.shift_vect)
result.scale(self.scale_factor)
return result
class FadeInFromPoint(FadeIn):
def __init__(self, mobject, point, **kwargs):
super().__init__(
mobject,
shift=mobject.get_center() - point,
scale=np.inf,
**kwargs,
)
class FadeOutToPoint(FadeOut):
def __init__(self, mobject, point, **kwargs):
super().__init__(
mobject,
shift=point - mobject.get_center(),
scale=0,
**kwargs,
)
class FadeTransform(Transform):
CONFIG = {
"stretch": True,
"dim_to_match": 1,
}
def __init__(self, mobject, target_mobject, **kwargs):
self.to_add_on_completion = target_mobject
mobject.save_state()
super().__init__(
Group(mobject, target_mobject.copy()),
**kwargs
)
def begin(self):
self.ending_mobject = self.mobject.copy()
Animation.begin(self)
# Both 'start' and 'end' consists of the source and target mobjects.
# At the start, the traget should be faded replacing the source,
# and at the end it should be the other way around.
start, end = self.starting_mobject, self.ending_mobject
for m0, m1 in ((start[1], start[0]), (end[0], end[1])):
self.ghost_to(m0, m1)
def ghost_to(self, source, target):
source.replace(target, stretch=self.stretch, dim_to_match=self.dim_to_match)
source.set_opacity(0)
def get_all_mobjects(self):
return [
self.mobject,
self.starting_mobject,
self.ending_mobject,
]
def get_all_families_zipped(self):
return Animation.get_all_families_zipped(self)
def clean_up_from_scene(self, scene):
Animation.clean_up_from_scene(self, scene)
scene.remove(self.mobject)
self.mobject[0].restore()
scene.add(self.to_add_on_completion)
class FadeTransformPieces(FadeTransform):
def begin(self):
self.mobject[0].align_family(self.mobject[1])
super().begin()
def ghost_to(self, source, target):
for sm0, sm1 in zip(source.get_family(), target.get_family()):
super().ghost_to(sm0, sm1)
class VFadeIn(Animation):
"""
VFadeIn and VFadeOut only work for VMobjects,
"""
CONFIG = {
"suspend_mobject_updating": False,
}
def interpolate_submobject(self, submob, start, alpha):
submob.set_stroke(
opacity=interpolate(0, start.get_stroke_opacity(), alpha)
)
submob.set_fill(
opacity=interpolate(0, start.get_fill_opacity(), alpha)
)
class VFadeOut(VFadeIn):
CONFIG = {
"remover": True,
# Put it back in original state when done
"final_alpha_value": 0,
}
def interpolate_submobject(self, submob, start, alpha):
super().interpolate_submobject(submob, start, 1 - alpha)
class VFadeInThenOut(VFadeIn):
CONFIG = {
"rate_func": there_and_back,
"remover": True,
# Put it back in original state when done
"final_alpha_value": 0.5,
}