59 lines
2.8 KiB
Python
59 lines
2.8 KiB
Python
"""Transfer horizontal root motion to Sequencer actor keys without changing source clips."""
|
|
import math
|
|
import hashlib
|
|
|
|
import unreal
|
|
|
|
from .paths import GENERATED
|
|
|
|
|
|
def prepare(clip, child, scene_name):
|
|
component = child.skeletal_mesh_component
|
|
bone = component.get_bone_name(0)
|
|
count = int(clip.get_editor_property("number_of_sampled_keys"))
|
|
duration = clip.get_play_length()
|
|
if count < 2 or duration <= 0:
|
|
raise ValueError("keep_end_position wymaga animacji z co najmniej dwiema probkami.")
|
|
poses = [unreal.AnimationLibrary.get_bone_pose_for_time(
|
|
clip, bone, duration * index / (count - 1), False) for index in range(count)]
|
|
first = poses[0].translation
|
|
# Extract only horizontal travel. Keep vertical motion (jumps/bobbing),
|
|
# every root rotation and scale, and all other bone tracks unchanged.
|
|
positions = [unreal.Vector(first.x, first.y, pose.translation.z) for pose in poses]
|
|
folder = f"{GENERATED}/{scene_name}/RootMotion"
|
|
identity = hashlib.sha1(clip.get_path_name().encode("utf-8")).hexdigest()[:8]
|
|
name = clip.get_name() + "_" + identity + "_InPlace"
|
|
path = folder + "/" + name
|
|
if unreal.EditorAssetLibrary.does_asset_exist(path):
|
|
# This path contains only our generated derivative for this scene.
|
|
if not unreal.EditorAssetLibrary.delete_asset(path):
|
|
raise RuntimeError("Nie mozna odswiezyc wygenerowanego klipu " + path)
|
|
copy = unreal.AssetToolsHelpers.get_asset_tools().duplicate_asset(name, folder, clip)
|
|
if copy is None:
|
|
raise RuntimeError("Nie mozna utworzyc kopii animacji dla keep_end_position.")
|
|
controller = copy.get_editor_property("controller")
|
|
if not controller.set_bone_track_keys(bone, positions, [pose.rotation for pose in poses],
|
|
[pose.scale3d for pose in poses], should_transact=False):
|
|
raise RuntimeError("Nie mozna przeniesc ruchu kosci glownej do Transform.")
|
|
unreal.EditorAssetLibrary.save_loaded_asset(copy)
|
|
return copy, poses, duration
|
|
|
|
|
|
def displacement(poses, duration, elapsed, reverse=False):
|
|
"""Interpolate horizontal root travel, accumulating complete playback loops."""
|
|
elapsed = max(0.0, elapsed)
|
|
loops = math.floor(elapsed / duration)
|
|
time = elapsed - loops * duration
|
|
if reverse:
|
|
time = duration - time
|
|
index = min(time / duration * (len(poses) - 1), len(poses) - 1)
|
|
lower = int(index)
|
|
upper = min(lower + 1, len(poses) - 1)
|
|
alpha = index - lower
|
|
a, b = poses[lower].translation, poses[upper].translation
|
|
start, end = poses[0].translation, poses[-1].translation
|
|
if reverse:
|
|
start, end = end, start
|
|
return unreal.Vector(a.x + (b.x - a.x) * alpha - start.x + loops * (end.x - start.x),
|
|
a.y + (b.y - a.y) * alpha - start.y + loops * (end.y - start.y), 0)
|