34 lines
1.4 KiB
Python
34 lines
1.4 KiB
Python
"""Animation metadata usable in normal Python and VS Code without Unreal."""
|
|
from enum import Enum
|
|
import math
|
|
|
|
|
|
class AnimationClip(Enum):
|
|
"""A named clip with its exported duration. Subclasses list concrete clips."""
|
|
|
|
def __init__(self, key: str, seconds: float):
|
|
self._key = key
|
|
self._seconds = seconds
|
|
|
|
@property
|
|
def key(self) -> str:
|
|
"""Clip name used by shot.animation(), derived from the FBX filename."""
|
|
return self._key
|
|
|
|
@property
|
|
def seconds(self) -> float:
|
|
"""Duration of one playback at speed=1, exported from Unreal."""
|
|
return self._seconds
|
|
|
|
def frames(self, fps: int = 24, speed: float = 1.0) -> int:
|
|
"""Frames needed for one playback at this sequence FPS and speed."""
|
|
if type(fps) is not int or fps < 1:
|
|
raise ValueError("fps musi byc dodatnia liczba calkowita.")
|
|
if isinstance(speed, bool) or not isinstance(speed, (int, float)) or not math.isfinite(speed) or speed <= 0:
|
|
raise ValueError("speed musi byc dodatnia liczba.")
|
|
value = self.seconds * fps / speed
|
|
# Unreal stores durations as float32; avoid adding a whole extra frame
|
|
# for values such as 3.200000047683716 seconds at 30 FPS.
|
|
nearest = round(value)
|
|
return max(1, nearest if math.isclose(value, nearest, rel_tol=0, abs_tol=0.0001) else math.ceil(value))
|