I am trying to create a tool to be able to transfer Control Rig animation/keys from a source Level Sequence to another Level Sequence without having to open the source Level Sequence. An Animation Library/Transfer tool of sorts.
It needs to be able to get the channel names and keys to be able to match and add to another Control rig. Does not have to be the same one as long as the channel names align.
Expectation:
Using `unreal.load_asset(source_LS_game_path)` to get the channel and key data without opening the source Level Sequence in the Sequencer.
Issue:
Control Rig Channels are not being returned thus am unable to get the key data.
It looks like the rigs construction event is run after the PY function has complete.
Tried:
unreal.load_asset()
Adding the source Level Sequence as a subsequence in the current Level Sequence that is open in the Sequencer. Then trying to get the channels/keys. (One PY call)
Tried focusing into the added subsequence. `unreal.LevelSequenceEditorBlueprintLibrary.focus_level_sequence()`
`unreal.LevelSequenceEditorBlueprintLibrary.refresh_current_level_sequence()` on both test 1 and 2.
`unreal.ControlRig ~ request_construction()` on both test 1 and 2.
Workaround:
Open the Level Sequence in unreal before running the Tool.
Defeats the point if you want to access/transfer channel and key data from multiple Level Sequences to one Level Sequence.
Have the Python tool run in two separate session/run cycles.
User presses button one to load the source Level Sequence it as a subsequence
User presses button two to copy and paste keys from the channels then delete the subsequence.
Export a dictionary section, channel and key data. This would require us to store all key information
A source Level Sequence with a Blueprint containing a Control Rig using spawned controls and keys set in the Sequencer.
A fresh Unreal Engine session. You cannot of already opened the source Level Sequence in your Unreal Engine session.
Code Example:
import unreal
unreal.load_asset('/Game/path_to_source_level_sequence')
for binding in source_sequence.get_bindings():
print(binding.get_name())
for track in binding.get_tracks():
print(' - ' + track.get_name())
if isinstance(track, unreal.MovieSceneControlRigParameterTrack):
for section in track.get_sections(): # Works as expected
print(' - ' + section.get_name())
for channel in section.get_all_channels(): # Empty list
print(' - ' + channel.get_name())
Found a solution. It does require you to load the source Level Sequence as a Sub Sequence into your current Level Sequence.
import unreal
source_sequence = unreal.load_asset('/Game/path_to_source_level_sequence')
target_sequence = unreal.LevelSequenceEditorBlueprintLibrary.get_focused_level_sequence()
# Add the Level Sequence as a Sub Sequence in your current Level Sequence
cinematic_shot_track = target_sequence.add_track(
unreal.MovieSceneSubTrack
)
subsequence_section = cinematic_shot_track.add_section()
subsequence_section.set_sequence(source_sequence)
subsequence_section.set_range(source_sequence.get_playback_start(), source_sequence.get_playback_end())
# Make sure that your Sequencer is at the correct frame to load the Sub Level Sequence
# Then revert back the the original frame for your transfer
current_time = unreal.LevelSequenceEditorBlueprintLibrary.get_current_time()
unreal.LevelSequenceEditorBlueprintLibrary.set_current_time(source_sequence.get_playback_start())
unreal.LevelSequenceEditorBlueprintLibrary.force_update() # Available since 5.5
unreal.LevelSequenceEditorBlueprintLibrary.set_current_time(current_time)
for binding in source_sequence.get_bindings():
print(binding.get_name())
for track in binding.get_tracks():
print(' - ' + track.get_name())
if isinstance(track, unreal.MovieSceneControlRigParameterTrack):
for section in track.get_sections(): # Works as expected
print(' - ' + section.get_name())
for channel in section.get_all_channels(): # Empty list
print(' - ' + channel.get_name())