3 from ..nvector
import NVector
4 from ..objects.shapes
import Path
6 from ..objects
import easing
7 from ..objects
import properties
10 def shake(position_prop, x_radius, y_radius, start_time, end_time, n_frames, interp=easing.Linear()):
11 if not isinstance(position_prop, list):
12 position_prop = [position_prop]
14 n_frames =
int(round(n_frames))
15 frame_time = (end_time - start_time) / n_frames
16 startpoints = list(map(
17 lambda pp: pp.get_value(start_time),
21 for i
in range(n_frames):
22 x = (random.random() * 2 - 1) * x_radius
23 y = (random.random() * 2 - 1) * y_radius
24 for pp, start
in zip(position_prop, startpoints):
27 pp.add_keyframe(start_time + i * frame_time,
NVector(px, py), interp)
29 for pp, start
in zip(position_prop, startpoints):
30 pp.add_keyframe(end_time, start, interp)
33 def rot_shake(rotation_prop, angles, start_time, end_time, n_frames):
34 frame_time = (end_time - start_time) / n_frames
35 start = rotation_prop.get_value(start_time)
37 for i
in range(0, n_frames):
38 a = angles[i % len(angles)] * math.sin(i/n_frames * math.pi)
39 rotation_prop.add_keyframe(start_time + i * frame_time, start + a)
40 rotation_prop.add_keyframe(end_time, start)
43 def spring_pull(position_prop, point, start_time, end_time, falloff=15, oscillations=7):
44 start = position_prop.get_value(start_time)
47 delta = (end_time - start_time) / oscillations
49 for i
in range(oscillations):
50 time_x = i / oscillations
51 factor = math.cos(time_x * math.pi * oscillations) * (1-time_x**(1/falloff))
52 p = point + d * factor
53 position_prop.add_keyframe(start_time + delta * i, p)
55 position_prop.add_keyframe(end_time, point)
58 def follow_path(position_prop, bezier, start_time, end_time, n_keyframes,
59 reverse=False, offset=NVector(0, 0), start_t=0, rotation_prop=
None, rotation_offset=0):
60 delta = (end_time - start_time) / (n_keyframes-1)
62 factd = 1 / (n_keyframes-1)
65 start_rot = rotation_prop.get_value(start_time)
if rotation_offset
is None else rotation_offset
67 for i
in range(n_keyframes):
68 time = start_time + i * delta
70 if fact > 1 + factd/2:
72 if time != start_time:
73 easing.Jump()(position_prop.keyframes[-1])
75 easing.Jump()(rotation_prop.keyframes[-1])
77 f = 1 - fact
if reverse
else fact
78 position_prop.add_keyframe(time, bezier.point_at(f)+offset)
81 rotation_prop.add_keyframe(time, bezier.tangent_angle_at(f) / math.pi * 180 + start_rot)
91 time_delta = (appear_end - appear_start) / n_keyframes
92 for i
in range(n_keyframes+1):
93 time = appear_start + i * time_delta
94 t2 = (time - appear_start) / (appear_end - appear_start)
98 segment = bezier.segment(t2, 1)
101 segment = bezier.segment(0, t2)
103 beziers.append(segment)
104 if len(segment.vertices) > maxp:
105 maxp = len(segment.vertices)
107 obj.shape.add_keyframe(time, segment)
109 for segment
in beziers:
110 deltap = maxp - len(segment.vertices)
112 segment.vertices += [segment.vertices[-1]] * deltap
113 segment.in_tangents += [
NVector(0, 0)] * deltap
114 segment.out_tangents += [
NVector(0, 0)] * deltap
124 time_delta = (disappear_end - disappear_start) / n_keyframes
125 for i
in range(n_keyframes+1):
126 time = disappear_start + i * time_delta
127 t1 = (time - disappear_start) / (disappear_end - disappear_start)
130 segment = bezier.segment(0, t1)
132 segment = bezier.segment(1, t1)
135 beziers.append(segment)
136 if len(segment.vertices) > maxp:
137 maxp = len(segment.vertices)
139 obj.shape.add_keyframe(time, segment)
141 for segment
in beziers:
142 deltap = maxp - len(segment.vertices)
144 segment.vertices += [segment.vertices[-1]] * deltap
145 segment.in_tangents += [
NVector(0, 0)] * deltap
146 segment.out_tangents += [
NVector(0, 0)] * deltap
151 def generate_path_segment(bezier, appear_start, appear_end, disappear_start, disappear_end, n_keyframes, reverse=False):
160 time_delta = (appear_end - appear_start) / n_keyframes
161 for i
in range(n_keyframes+1):
162 time = appear_start + i * time_delta
163 t1 = (time - disappear_start) / (disappear_end - disappear_start)
164 t2 = (time - appear_start) / (appear_end - appear_start)
166 t1 = max(0, min(1, t1))
167 t2 = max(0, min(1, t2))
173 segment = bezier.segment(t2, t1)
179 beziers.append(segment)
180 if len(segment.vertices) > maxp:
181 maxp = len(segment.vertices)
183 obj.shape.add_keyframe(time, segment)
185 for segment
in beziers:
186 deltap = maxp - len(segment.vertices)
188 segment.split_self_chunks(deltap+1)
197 def __init__(self, time_start, time_end, n_frames):
199 @param time_start When the animation shall start
200 @param time_end When the animation shall end
201 @param n_frames Number of frames in the animation
210 self.
time_deltatime_delta = (time_end - time_start) / n_frames
213 startpos = prop.get_value(self.
time_starttime_start)
214 for f
in range(self.
n_framesn_frames+1):
216 prop.add_keyframe(self.
frame_timeframe_time(f), startpos+p)
218 def _on_displace(self, startpos, f):
219 raise NotImplementedError()
222 initial = prop.get_value(self.
time_starttime_start)
224 for f
in range(self.
n_framesn_frames+1):
226 bezier.closed = initial.closed
228 for pi
in range(len(initial.vertices)):
229 startpos = initial.vertices[pi]
231 t1sp = initial.in_tangents[pi] + startpos
232 t1fin = initial.in_tangents[pi] + self.
_on_displace_on_displace(t1sp, f) - dp
233 t2sp = initial.out_tangents[pi] + startpos
234 t2fin = initial.out_tangents[pi] + self.
_on_displace_on_displace(t2sp, f) - dp
236 bezier.add_point(dp + startpos, t1fin, t2fin)
238 prop.add_keyframe(self.
frame_timeframe_time(f), bezier)
243 def _init_lerp(self, val_from, val_to, easing):
244 self.
_kf_kf = properties.OffsetKeyframe(0,
NVector(val_from), easing,
NVector(val_to))
246 def _lerp_get(self, offset):
247 return self.
_kf_kf.interpolated_value(offset / self.
n_framesn_frames)[0]
262 Displaces points as if they were following a sine wave
264 @param wavelength Distance between consecutive peaks
265 @param amplitude Distance from a peak to the original position
266 @param time_start When the animation shall start
267 @param time_end When the animation shall end
268 @param n_frames Number of keyframes to add
269 @param speed Number of peaks a point will go through in the given time
270 If negative, it will go the other way
271 @param axis Wave peak direction
273 super().
__init__(time_start, time_end, n_frames)
278 self.
axisaxis = axis / 180 * math.pi
280 def _on_displace(self, startpos, f):
282 return NVector(off * math.cos(self.
axisaxis), off * math.sin(self.
axisaxis))
297 Displaces points as if they were following a sine wave
299 @param waves List of tuples (wavelength, amplitude)
300 @param time_start When the animation shall start
301 @param time_end When the animation shall end
302 @param n_frames Number of keyframes to add
303 @param speed Number of peaks a point will go through in the given time
304 If negative, it will go the other way
305 @param axis Wave peak direction
306 @param amplitude_scale Multiplies the resulting amplitude by this factor
308 super().
__init__(time_start, time_end, n_frames)
312 self.
axisaxis = axis / 180 * math.pi
315 def _on_displace(self, startpos, f):
317 for wavelength, amplitude
in self.
waveswaves:
318 off -= math.sin(startpos[0]/wavelength*math.pi*2-f*self.
speed_fspeed_f/self.
n_framesn_frames) * amplitude
321 return NVector(off * math.cos(self.
axisaxis), off * math.sin(self.
axisaxis))
326 self.
xx = x / x.length
327 self.
yy = y / y.length
328 self.
keepkeep = keep / keep.length
332 self.
xx * self.
xx.dot(center) +
333 self.
yy * self.
yy.dot(center) +
334 self.
keepkeep * self.
keepkeep.dot(point)
338 return sum(vector.element_scaled(axis).components)
342 keep = keep_point - center
345 if abs(keep.x) > abs(keep.z):
346 y =
NVector(-keep.y, keep.x, 0)
348 y =
NVector(0, -keep.z, keep.y)
351 return cls(x, y, keep)
396 c = axis.rot_center(self.
centercenter, point)
397 rad = angle * math.pi / 180
401 axis.extract_component(delta, axis.y),
402 axis.extract_component(delta, axis.x)
405 return c + axis.x * pol_l * math.cos(dest_a) + axis.y * pol_l * math.sin(dest_a)
409 axis_x = DepthRotation.axis_x
410 axis_y = DepthRotation.axis_y
411 axis_z = DepthRotation.axis_z
413 def __init__(self, center, time_start, time_end, n_frames, axis,
414 depth=0, angle=360, anglestart=0, ease=easing.Linear()):
415 super().
__init__(time_start, time_end, n_frames)
417 if isinstance(axis, NVector):
418 axis = DepthRotationAxis.from_points(axis)
435 def _on_displace(self, startpos, f):
437 if len(startpos) < 3:
438 startpos =
NVector(*(startpos.components + [self.
depthdepth]))
439 return self.
rotationrotation.rotate3d(startpos, angle, self.
axisaxis) - startpos
445 self.
sizesize = bottomright - topleft
470 def _on_displace(self, startpos, f):
471 _, tl, tr, br, bl = self.
keyframeskeyframes[f]
472 relp = startpos - self.
toplefttopleft
473 relp.x /= self.
sizesize.x
474 relp.y /= self.
sizesize.y
476 x1 = tl.lerp(tr, relp.x)
477 x2 = bl.lerp(br, relp.x)
480 return x1.lerp(x2, relp.y) - startpos
492 Given a displacer and a function that returns a factor for a point,
493 multiplies the effect of the displacer by the factor
501 return self.
displacerdisplacer.time_start
503 def _on_displace(self, startpos, f):
504 disp = self.
displacerdisplacer._on_displace(startpos, f)
505 damp = self.
dampenerdampener(startpos)
522 time_start, time_end, n_frames,
526 @brief Uses a custom offset function, and applies a falloff to the displacement
528 @param origin Origin point for the falloff
529 @param range Radius after which the points will not move
530 @param offset_func Function returning an offset given a ratio of the time
531 @param time_start When the animation shall start
532 @param time_end When the animation shall end
533 @param n_frames Number of frames in the animation
534 @param falloff_exp Exponent for the falloff
536 super().
__init__(time_start, time_end, n_frames)
542 def _on_displace(self, startpos, f):
543 influence = 1 - min(1, (startpos - self.
originorigin).length / self.
rangerange) ** self.
falloff_expfalloff_exp
def __init__(self, x, y, keep)
def extract_component(self, vector, axis)
def from_points(cls, keep_point, center=NVector(0, 0, 0))
def rot_center(self, center, point)
def __init__(self, center, time_start, time_end, n_frames, axis, depth=0, angle=360, anglestart=0, ease=easing.Linear())
def rotate3d_z(self, point, angle)
def __init__(self, center)
def rotate3d_y(self, point, angle)
def rotate3d_x(self, point, angle)
def rotate3d(self, point, angle, axis)
Given a displacer and a function that returns a factor for a point, multiplies the effect of the disp...
def __init__(self, displacer, dampener)
def __init__(self, origin, range, offset_func, time_start, time_end, n_frames, falloff_exp=1)
Uses a custom offset function, and applies a falloff to the displacement.
def __init__(self, waves, time_start, time_end, n_frames, speed=1, axis=90, amplitude_scale=1)
Displaces points as if they were following a sine wave.
time_delta
Length of a frame.
time_start
When the animation shall start.
time_end
When the animation shall end.
def __init__(self, time_start, time_end, n_frames)
n_frames
Number of frames in the animation.
def animate_point(self, prop)
def _lerp_get(self, offset)
def _on_displace(self, startpos, f)
def _init_lerp(self, val_from, val_to, easing)
def animate_bezier(self, prop)
def __init__(self, wavelength, amplitude, time_start, time_end, n_frames, speed=1, axis=90)
Displaces points as if they were following a sine wave.
def follow_path(position_prop, bezier, start_time, end_time, n_keyframes, reverse=False, offset=NVector(0, 0), start_t=0, rotation_prop=None, rotation_offset=0)
def generate_path_disappear(bezier, disappear_start, disappear_end, n_keyframes, reverse=False)
def rot_shake(rotation_prop, angles, start_time, end_time, n_frames)
def generate_path_appear(bezier, appear_start, appear_end, n_keyframes, reverse=False)
def spring_pull(position_prop, point, start_time, end_time, falloff=15, oscillations=7)
def shake(position_prop, x_radius, y_radius, start_time, end_time, n_frames, interp=easing.Linear())
def generate_path_segment(bezier, appear_start, appear_end, disappear_start, disappear_end, n_keyframes, reverse=False)