Python 스크립팅은 시퀀서(Sequencer) 에서 컨트롤 릭(Control Rig) 애니메이팅의 다양한 부분을 자동화하고 제어하는 데 사용할 수 있습니다. 이 문서에서는 컨트롤 릭 애니메이팅과 애니메이션 모드(Animation Mode) 및 기타 다양한 애니메이션 워크플로와 함께 Python을 사용하는 기본적인 방법을 간략하게 살펴봅니다.
전제조건
언리얼 엔진에서의 Python 스크립팅과 시퀀서에서의 스크립팅 경험이 어느 정도 있어야 합니다.
컨트롤 릭을 생성하고 사용하는 방법을 알고 있어야 합니다.
컨트롤 릭 트랙 생성
컨트롤 릭 트랙을 생성하는 것은 일반적으로 시퀀서에서 트랙을 생성하는 것과는 약간 다릅니다. 컨트롤 릭 트랙을 생성하려면 컨트롤 릭 클래스가 정의되어 있어야 합니다. 다음 명령으로 컨트롤 릭 트랙을 생성할 수 있습니다.
# 에디터 월드를 얻습니다.
world = unreal.EditorLevelLibrary.get_editor_world()
# 컨트롤 릭 에셋을 얻습니다.
rig = unreal.load_asset("/Game/Animation/ControlRig/Mannequin_ControlRig")
# 릭 클래스를 얻습니다.
rig_class = rig.get_control_rig_class()
# 레벨 시퀀스와 액터 바인딩을 사용하여 클래스에서 컨트롤 릭 트랙을 찾거나 생성할 수 있습니다.
rig_track = unreal.ControlRigSequencerLibrary.find_or_create_control_rig_track(world,level_sequence, rig_class, actor_binding)
컨트롤 애니메이팅
다음 예시들은 컨트롤을 편집하고 애니메이팅할 수 있는 다양한 방법을 설명합니다.
컨트롤 선택
다음 명령을 사용하여 컨트롤을 선택하고 컨트롤 선택을 쿼리할 수 있습니다.
# 시퀀서에서 컨트롤 릭을 얻습니다. ControlRigSequencerBindingProxy 목록을 반환합니다.
rig_proxies = unreal.ControlRigSequencerLibrary.get_control_rigs(level_sequence)
# 첫 번째 프록시를 얻습니다. Mannequin_ControlRig이라고 가정합니다.
rig_proxy = rig_proxies[0]
# ControlRigSequencerBindingProxy에서 ControlRig 오브젝트를 얻을 수 있습니다.
rig = rig_proxy.control_rig
# 지정된 컨트롤을 선택합니다.
rig.select_control("body_ctrl")
# 현재 컨트롤 선택을 얻습니다.
selected_controls = rig.current_control_selection()
print(selected_controls)
# 컨트롤 선택을 지웁니다.
rig.clear_control_selection()
컨트롤 값 얻기 및 설정하기
다음 명령을 사용하여 주어진 모든 프레임 번호의 모든 컨트롤에서 특정 값을 얻을 수 있습니다.
# 시퀀서에서 컨트롤 릭을 얻습니다. ControlRigSequencerBindingProxy 목록을 반환합니다.
rig_proxies = unreal.ControlRigSequencerLibrary.get_control_rigs(level_sequence)
# 0 프레임을 얻습니다.
frame_num = unreal.FrameNumber(0)
# 첫 번째 프록시를 얻습니다. Mannequin_ControlRig이라고 가정합니다.
rig_proxy = rig_proxies[0]
# ControlRigSequencerBindingProxy에서 ControlRig 오브젝트를 얻을 수 있습니다.
rig = rig_proxy.control_rig
# 로컬 컨트롤 값을 얻습니다. 각 컨트롤 타입에는 고유한 타입의 함수가 있습니다.
transform = unreal.ControlRigSequencerLibrary.get_local_control_rig_transform(level_sequence, rig, "body_ctrl", frame_num)
bool = unreal.ControlRigSequencerLibrary.get_local_control_rig_bool(level_sequence, rig, "twist_ctrl_vis", frame_num)
print(transform)
print(bool)
다음 명령을 사용하여 주어진 모든 프레임 번호의 모든 컨트롤에서 특정 값을 설정할 수도 있습니다.
# 시퀀서에서 컨트롤 릭을 얻습니다. ControlRigSequencerBindingProxy 목록을 반환합니다.
rig_proxies = unreal.ControlRigSequencerLibrary.get_control_rigs(level_sequence)
# 첫 번째 프록시를 얻습니다. Mannequin_ControlRig이라고 가정합니다.
rig_proxy = rig_proxies[0]
# ControlRigSequencerBindingProxy에서 ControlRig 오브젝트를 얻을 수 있습니다.
rig = rig_proxy.control_rig
# 현재 시간을 얻습니다.
current_time = unreal.LevelSequenceEditorBlueprintLibrary.get_current_time()
# 현재 시간을 FrameNumber 오브젝트로 변환합니다.
current_frame = unreal.FrameNumber(current_time)
# 컨트롤에 대한 적절한 값 오브젝트를 생성합니다.
transform_value = unreal.Transform(location=[0, 10, 20], rotation=[0,30,0], scale=[1,1,1])
bool_value = True
# 로컬 컨트롤 값을 설정합니다. 각 컨트롤 타입에는 고유한 타입의 함수가 있습니다.
# 각 타입의 함수에는 기본값이 true인 set_key 플래그도 있습니다
unreal.ControlRigSequencerLibrary.set_local_control_rig_transform(level_sequence, rig, "body_ctrl", frame_num, transform_value)
unreal.ControlRigSequencerLibrary.set_local_control_rig_bool(level_sequence, rig, "twist_ctrl_vis", frame_num, bool_value, set_key = False)
애니메이션 모드
애니메이션 모드 툴도 Python 스크립팅의 영향을 받을 수 있습니다. 다음과 같은 예시가 제공됩니다.
트윈 툴
트윈 툴에 다음 명령을 사용할 수 있습니다.
# 값을 -1 ~ 1 사이로 설정합니다.
# -1은 이전 프레임에 블렌딩됩니다.
# 1은 다음 프레임에 블렌딩됩니다.
tween_value = -1
unreal.ControlRigSequencerLibrary.tween_control_rig(level_sequence, rig, tween_value)
스냅퍼 툴
스냅퍼 툴에 다음 명령을 사용할 수 있습니다. 드라이버 오브젝트가 애니메이팅되는 경우, 드라이버 오브젝트를 활성 시퀀스에 추가해야 합니다.
# 시퀀서에서 컨트롤 릭을 얻습니다. ControlRigSequencerBindingProxy 목록을 반환합니다.
rig_proxies = unreal.ControlRigSequencerLibrary.get_control_rigs(level_sequence)
# 첫 번째 프록시를 얻습니다. Mannequin_ControlRig이라고 가정합니다.
rig_proxy = rig_proxies[0]
# ControlRigSequencerBindingProxy에서 ControlRig 오브젝트를 얻을 수 있습니다.
rig = rig_proxy.control_rig
# 액터에 추가하기 위해 에디터 액터 서브시스템을 얻습니다.
editor_actor_subsystem = unreal.get_editor_subsystem(unreal.EditorActorSubsystem)
# 에디터 월드에 큐브를 추가하고 위치를 설정합니다.
cube_mesh = unreal.load_asset("/Engine/BasicShapes/Cube")
cube_location = unreal.Vector(0, 10, 20)
cube_actor = editor_actor_subsystem.spawn_actor_from_object(cube_mesh, cube_location)
# 시작 및 끝 프레임 범위를 설정합니다.
start_frame = unreal.FrameNumber(0)
end_frame = unreal.FrameNumber(5)
# 부모 및 자손에 대한 ControlRigSnapperSelection objects 오브젝트를 생성합니다.
parent = unreal.ControlRigSnapperSelection()
children = unreal.ControlRigSnapperSelection()
# ActorForWorldTransforms 오브젝트를 생성합니다.
# 큐브 액터를 부모로 설정합니다.
parent_actor = unreal.ActorForWorldTransforms()
parent_actor.actor = cube_actor
# ControlRigForWorldTransforms 오브젝트를 생성합니다.
# 적절한 컨트롤 릭 및 왼손 컨트롤을 컨트롤로 설정합니다.
# 여기에 여러 컨트롤 이름이 있을 수 있습니다.
child_control_rig = unreal.ControlRigForWorldTransforms()
child_control_rig.control_rig = rig
child_control_rig.control_names = ["hand_l_ctrl"]
# ActorForWorldTransforms 오브젝트를 가져와 부모 ControlRigSnapperSelection으로 설정합니다.
# ControlRigForWorldTransforms 오브젝트를 가져와 자손 ControlRigSnapperSelection으로 설정합니다.
parent.actors = [parent_actor]
children.control_rigs = [child_control_rig]
# 스냅 세팅을 생성하고 설정합니다.
snap_settings = unreal.ControlRigSnapSettings()
snap_settings.keep_offset = False
snap_settings.snap_position = True
snap_settings.snap_rotation = True
snap_settings.snap_scale = False
# 그런 다음, 0~5 프레임의 큐브에 왼손 컨트롤을 스냅합니다.
unreal.ControlRigSequencerLibrary.snap_control_rig(level_sequence, start_frame, end_frame, children, parent, snap_settings)
스페이스 전환
스페이스 전환에 다음 명령과 예시를 사용할 수 있습니다.
스페이스 전환을 시작하려면, 스페이스 키프레임을 생성해야 합니다. 컨트롤의 스페이스를 기본 부모, 월드 스페이스 또는 주어진 프레임 번호의 다른 컨트롤에 설정할 수 있습니다.
# 시퀀서에서 컨트롤 릭을 얻습니다. ControlRigSequencerBindingProxy 목록을 반환합니다.
rig_proxies = unreal.ControlRigSequencerLibrary.get_control_rigs(level_sequence)
# 첫 번째 프록시를 얻습니다. Mannequin_ControlRig이라고 가정합니다.
rig_proxy = rig_proxies[0]
# ControlRigSequencerBindingProxy에서 ControlRig 오브젝트를 얻을 수 있습니다.
rig = rig_proxy.control_rig
# 왼손 컨트롤 스페이스를 0 프레임에서 월드 스페이스로 설정합니다.
control_name = "hand_l_ctrl"
space = unreal.ControlRigSequencerLibrary.get_world_space_reference_key()
time = unreal.FrameNumber(value = 0)
unreal.ControlRigSequencerLibrary.set_control_rig_space(level_sequence, rig, control_name, space, time)
# 그런 다음, 스페이스 전환을 30 프레임에서 헤드 컨트롤로 설정합니다.
space = unreal.RigElementKey(type = unreal.RigElementType.CONTROL, name = "head_ctrl")
time = unreal.FrameNumber(value = 30)
unreal.ControlRigSequencerLibrary.set_control_rig_space(level_sequence, rig, control_name, space, time)
# 마지막으로, 스페이스 전환을 60 프레임에서 기본 부모로 설정합니다.
space = unreal.ControlRigSequencerLibrary.get_world_space_reference_key()
time = unreal.FrameNumber(value = 60)
unreal.ControlRigSequencerLibrary.set_control_rig_space(level_sequence, rig, control_name, space, time)
스페이스 키프레임이 생성되면, 다음 명령을 사용하여 해당 키프레임을 원하는 프레임 번호로 이동할 수 있습니다.
# 시퀀서에서 컨트롤 릭을 얻습니다. ControlRigSequencerBindingProxy 목록을 반환합니다.
rig_proxies = unreal.ControlRigSequencerLibrary.get_control_rigs(level_sequence)
# 첫 번째 프록시를 얻습니다. Mannequin_ControlRig이라고 가정합니다.
rig_proxy = rig_proxies[0]
# ControlRigSequencerBindingProxy에서 ControlRig 오브젝트를 얻을 수 있습니다.
rig = rig_proxy.control_rig
# 스페이스 키 설정(Set Space Key) 예시에서 스페이스 키가 왼손 컨트롤의 0, 30, 60에 있다고
# 가정해 보겠습니다. 스페이스 키를 30 프레임에서 45 프레임으로 이동해보겠습니다.
control_name = "hand_l_ctrl"
old_time = unreal.FrameNumber(value = 30)
new_time = unreal.FrameNumber(value = 45)
unreal.ControlRigSequencerLibrary.move_control_rig_space(level_sequence, rig, control_name, old_time, new_time)
다음 명령을 사용하여 스페이스 키프레임을 삭제할 수 있습니다.
# 시퀀서에서 컨트롤 릭을 얻습니다. ControlRigSequencerBindingProxy 목록을 반환합니다.
rig_proxies = unreal.ControlRigSequencerLibrary.get_control_rigs(level_sequence)
# 첫 번째 프록시를 얻습니다. Mannequin_ControlRig이라고 가정합니다.
rig_proxy = rig_proxies[0]
# ControlRigSequencerBindingProxy에서 ControlRig 오브젝트를 얻을 수 있습니다.
rig = rig_proxy.control_rig
# 스페이스 키 이동(Move Space Key) 예시에서 스페이스 키가 왼손 컨트롤의 0, 45, 60에 있다고
# 가정해 보겠습니다. 스페이스 키를 45 프레임에서 제거해보겠습니다.
control_name = "hand_l_ctrl"
time = unreal.FrameNumber(value = 45)
unreal.ControlRigSequencerLibrary.delete_control_rig_space(level_sequence, rig, control_name, time)
다음 명령을 사용하여 특정 스페이스에 최종 애니메이션을 구울 수 있습니다.
# 시퀀서에서 컨트롤 릭을 얻습니다. ControlRigSequencerBindingProxy 목록을 반환합니다.
rig_proxies = unreal.ControlRigSequencerLibrary.get_control_rigs(level_sequence)
# 첫 번째 프록시를 얻습니다. Mannequin_ControlRig이라고 가정합니다.
rig_proxy = rig_proxies[0]
# ControlRigSequencerBindingProxy에서 ControlRig 오브젝트를 얻을 수 있습니다.
rig = rig_proxy.control_rig
# 선택한 릭 컨트롤을 모두 얻습니다.
control_names = rig.current_control_selection()
# 레벨 시퀀스에서 시작 및 끝 프레임을 얻고 세팅을 굽기 위해 FrameNumber 오브젝트를 생성합니다.
start_frame_num = level_sequence.get_playback_start()
end_frame_num = level_sequence.get_playback_end()
start_frame = unreal.FrameNumber(value = start_frame_num)
end_frame = unreal.FrameNumber(value = end_frame_num)
# 스페이스에 대한 굽기 세팅을 설정합니다. 기본 부모 스페이스에 구울 것입니다.
space_bake_settings = unreal.RigSpacePickerBakeSettings()
space_bake_settings.target_space = unreal.ControlRigSequencerLibrary.get_default_parent_key()
space_bake_settings.start_frame = start_frame
space_bake_settings.end_frame = end_frame
space_bake_settings.reduce_keys = False
space_bake_settings.tolerance = 0
unreal.ControlRigSequencerLibrary.bake_control_rig_space(level_sequence, rig, control_names, space_bake_settings)
애니메이션 모드 세팅
Python 스크립팅을 사용하여 애니메이션 모드 세팅을 편집할 수 있습니다. 각 프로퍼티에서는 다음과 같은 용어를 사용합니다.
이름 |
설명 |
---|---|
bDisplayHierarchy |
캐릭터에 본을 그립니다. |
bDisplayNulls |
캐릭터에 Null을 그립니다. |
bHideManipulators |
뷰포트에서 모든 컨트롤을 숨깁니다. 계층구조 표시 또는 Null 표시 가 활성화된 경우 본과 Null도 숨깁니다. |
bCoordSystemPerWidgetMode |
뷰포트에서 기즈모 모드 변경 시 좌표 공간을 복원합니다. |
bOnlySelectRigControls |
활성화하면 뷰포트에서 컨트롤 릭 컨트롤만 선택할 수 있습니다. 캐릭터를 포함한 다른 모든 오브젝트는 선택할 수 없습니다. |
bLocalTransformsInEachLocalSpace |
활성화하면 트랜스포메이션 기즈모가 로컬 좌표로 설정된 경우, 선택한 각 컨트롤을 각자의 로컬 트랜스폼 스페이스를 기준으로 변환합니다. |
GizmoScale |
기즈모 스케일을 늘이거나 줄입니다. |
다음 명령을 사용할 수 있습니다.
# 모드 세팅 클래스를 로드하고 기본 오브젝트를 얻습니다.
ControlRigSettingsClass = unreal.load_class(None, '/Script/ControlRigEditor.ControlRigEditModeSettings')
ControlRigSettings = unreal.get_default_object(ControlRigSettingsClass)
# 쿼리된 데이터를 출력합니다.
print(ControlRigSettings.get_editor_property('bDisplayHierarchy'))
print(ControlRigSettings.get_editor_property('bDisplayNulls'))
print(ControlRigSettings.get_editor_property(GizmoScale))
# 프로퍼티를 설정합니다.
ControlRigSettings.set_editor_property('bDisplayHierarchy', True)
ControlRigSettings.set_editor_property('bDisplayNulls', True)
ControlRigSettings.set_editor_property('GizmoScale', 5)
굽기 및 병합하기
컨트롤 릭에 굽습니다.
시퀀서의 액터에 이미 애니메이션 시퀀스가 있는 경우, 컨트롤 릭에 현재 애니메이션을 구워 컨트롤 릭 트랙을 생성할 수 있습니다. 다음 명령을 사용하여 그러한 작업을 수행할 수 있습니다.
# 현재 에디터 레벨을 얻습니다.
editor_system = unreal.get_editor_subsystem(unreal.UnrealEditorSubsystem)
world = editor_system.get_editor_world()
# 애니메이션 시퀀스 익스포트 옵션을 얻습니다.
anim_seq_export_options = unreal.AnimSeqExportOption()
anim_seq_export_options.export_transforms = True
anim_seq_export_options.export_curves = True
# 키 허용치 숫자 및 키 감소 스테이트를 얻습니다.
tolerance = 0.01
reduce_keys = False
# 컨트롤 릭에 굽습니다.
unreal.ControlRigSequencerLibrary.bake_to_control_rig(world, level_sequence, rig_class, anim_seq_export_options, False, tolerance, actor_binding)
애니메이션 시퀀스에 굽기
컨트롤 릭 애니메이션이 완료되면, 다음 명령을 사용하여 언리얼 엔진의 다른 영역에 사용될 애니메이션 시퀀스로 애니메이션을 내보낼 수 있습니다.
# 현재 레벨 시퀀스를 얻습니다.
level_sequence = unreal.LevelSequenceEditorBlueprintLibrary.get_current_level_sequence()
# SK Mannequin이라는 SkeletaMeshActor 바인딩을 얻습니다.
# 이는 Mannequin_ControlRig를 레벨 에디터로 드래그할 때 기본 이름입니다.
binding = level_sequence.find_binding_by_name("SK Mannequin")
# 레벨 에디터 월드를 얻습니다.
editor_subsystem = unreal.get_editor_subsystem(unreal.UnrealEditorSubsystem)
world = editor_subsystem.get_editor_world()
# 애니메이션 시퀀스 익스포트 옵션을 생성합니다.
anim_seq_export_options = unreal.AnimSeqExportOption()
anim_seq_export_options.export_transforms = True
anim_seq_export_options.export_morph_targets = True
# 에셋 툴을 얻습니다.
# 빈 AnimSequence를 생성합니다. - /Game/Test_Anim
asset_tools = unreal.AssetToolsHelpers.get_asset_tools()
anim_sequence = unreal.AssetTools.create_asset(asset_tools, asset_name = "Test_Anim", package_path = "/Game/", asset_class = unreal.AnimSequence, factory = unreal.AnimSequenceFactory())
# 생성한 AnimSequence에 굽습니다.
unreal.SequencerTools.export_anim_sequence(world, level_sequence, anim_sequence, anim_seq_export_options, binding, False)
# 링크된 애니메이션 시퀀스를 생성하려면, 마지막 아규먼트를 True로 변경하면 됩니다
unreal.SequencerTools.export_anim_sequence(world, level_sequence, anim_sequence, anim_seq_export_options, binding, True)
애니메이션 레이어 병합하기
컨트롤 릭 트랙 안에 여러 개의 섹션과 레이어를 사용하는 경우, 다음과 같은 접기 명령을 사용하여 애니메이션을 하나의 레이어로 굽고 병합할 수 있습니다.
# 시퀀서에서 컨트롤 릭을 얻습니다. ControlRigSequencerBindingProxy 목록을 반환합니다.
rig_proxies = unreal.ControlRigSequencerLibrary.get_control_rigs(level_sequence)
# 첫 번째 프록시를 얻습니다. Mannequin_ControlRig이라고 가정합니다.
rig_proxy = rig_proxies[0]
# ControlRigSequencerBindingProxy에서 MovieSceneControlRigParameterTrack 오브젝트를 얻을 수 있습니다.
# 해당 트랙을 통해 트랙의 모든 섹션을 하나의 섹션으로 접을 수 있습니다.
rig_track = rig_proxy.track
unreal.ControlRigSequencerLibrary.collapse_control_rig_anim_layers
(level_sequence, rig_track, key_reduce = False, tolerance = 0.001)