Can't create/add keyframe on a subframe

To work around this issue I’m creating/adding the frame in an frame that is definitely not being used by anyone and then setting the time of the keyframe to the target frame and subframe. It’s weird because the “add_key()” doesn’t works but setting the time directly in the keyframe works. The following python script is enough to reproduce the issue if you have the setup I described above. Just make sure you put the correct level sequence path and binding name on the global VARs bellow.

import unreal

SEQUENCE_PATH = "/Game/Cinematics/LS_CreateKeyframeTest.LS_CreateKeyframeTest"
BINDING_NAME = "B_TestActor"
FRAME_NUMBER = 42
SUBFRAME = 0.42
TARGET_FRAME_TIME = FRAME_NUMBER + SUBFRAME

def find_binding(sequence, name):
  for binding in sequence.get_bindings():
    if binding.get_display_name() == name:
      return binding
  return None

def main():
  sequence = unreal.load_asset(SEQUENCE_PATH)
  if not sequence:
    unreal.log_error(f"LevelSequence asset not found at path: {SEQUENCE_PATH}")
    return

  binding = find_binding(sequence, BINDING_NAME)
  if not binding:
    unreal.log_error(f"Binding '{BINDING_NAME}' not found in sequence.")
    return

  transform_track = None
  for track in binding.get_tracks():
    if isinstance(track, unreal.MovieScene3DTransformTrack):
      transform_track = track
      break

  if not transform_track:
    unreal.log_error(f"Transform track not found for binding '{BINDING_NAME}'.")
    return

  for section in transform_track.get_sections():
    loc_z_channel = section.get_channel("Location.Z")
    if loc_z_channel is None:
      unreal.log_error(f" Location Z channel not found for binding '{BINDING_NAME}'.")
       
    loc_z_key = loc_z_channel.add_key(time= unreal.FrameNumber(FRAME_NUMBER), new_value= 42.0, sub_frame= SUBFRAME, time_unit= unreal.MovieSceneTimeUnit.DISPLAY_RATE, interpolation= unreal.MovieSceneKeyInterpolation.AUTO)
    current_loc_z_frametime = loc_z_key.get_time()
    current_loc_z_frame_number = current_loc_z_frametime.frame_number.value
    current_loc_z_sub_frame = current_loc_z_frametime.sub_frame
    unreal.log(f"[DEBUG] - current_loc_z_frame_number: {current_loc_z_frame_number}")
    unreal.log(f"[DEBUG] - current_loc_z_sub_frame: {current_loc_z_sub_frame}")
    loc_z_key.set_time(new_frame_number= unreal.FrameNumber(FRAME_NUMBER), sub_frame= SUBFRAME, time_unit= unreal.MovieSceneTimeUnit.DISPLAY_RATE)

    new_loc_z_frametime = loc_z_key.get_time()
    new_loc_z_frame_number = new_loc_z_frametime.frame_number.value
    new_loc_z_sub_frame = new_loc_z_frametime.sub_frame
    unreal.log(f"[DEBUG] - new_loc_z_frame_number: {new_loc_z_frame_number}")
    unreal.log(f"[DEBUG] - new_loc_z_sub_frame: {new_loc_z_sub_frame}")


if __name__ == "__main__":
  main()




Steps to Reproduce

  1. Create:
    1. Level
    2. Any actor or shape
    3. Level sequence
  2. Bind the actor to the level sequence and create a transform track (or any other desired track)
  3. Using python, try to create a keyframe on a subframe of any channel of that track.

Result: Unreal will use just the frame information and discard the subframe info.

Hey there,

This has been fixed in mainline p4 cl:49976365, and here’s the github link:

https://github.com/EpicGames/UnrealEngine/commit/71d490bce3f0b90a4cfd1dd078d33be339e44158

This is a pretty straight forward one to integrate.

Dustin

Thanks [mention removed]​ for the quick fix - this is great!

Oh that’s nice Dustin. As I do have a workaround I might just wait for it to be on a released version, any timeframe for that?

We don’t have any official timelines for 5.8, but we generally do bi-annual releases for the engine at the moment.