컨트롤 릭에서 Python 스크립팅을 사용하여 워크플로를 자동화하고 리깅 프로세스를 위한 툴을 생성합니다. 또한 컨트롤 릭 Python 로그(Control Rig Python Log) 를 사용하여 명령을 리버스 엔지니어링하고 스크립트를 복사하여 다른 프로젝트에 공유할 수 있습니다.
이 문서는 컨트롤 릭에서의 Python 스크립팅에 대한 개요, 컨트롤 릭 Python 로그와 몇 가지 스크립팅 예시를 제공합니다.
전제조건
컨트롤 릭 에셋을 연 상태여야 합니다.
언리얼 엔진에서의 Python 스크립팅 경험이 필요합니다.
스크립팅 개요
Python은 주로 컨트롤 릭에서 사용되어 릭 그래프와 인터랙션하며, 다음과 같은 여러 가지 모듈로 구성됩니다.
모듈 이름 |
설명 |
---|---|
ControlRig |
릭을 위한 런타임을 포함합니다. |
ControlRigDeveloper |
릭을 변경하는 모든 기능을 포함합니다. |
ControlRigEditor |
프론트 엔드 및 유저 인터페이스 로직을 포함합니다. |
컨트롤 릭 그래프는 모델-뷰-컨트롤러(Model-View-Controller) 디자인 패턴을 사용하여 구현되었습니다. 모델은 다음 용어를 사용한 그래프 그 자체입니다.
컨트롤 릭 Python 용어 |
설명 |
---|---|
RigUnit |
릭의 함수를 정의하는 C++ 구조체입니다(예: FRigUnit_GetBoneTransform). |
핀(Pin) |
함수의 단일 입력 또는 출력입니다. |
링크(Link) |
두 핀 사이의 연결입니다. |
노드(Node) |
RigUnit의 시각적 표현입니다. |
그래프(Graph) |
릭 내에서 모든 노드와 링크를 포함하는 방향 그래프입니다. |
PinPath |
그래프 내 핀의 주소를 설명하는 스트링입니다(예: NodeA.Translation.X). |
컨트롤러(Controller) |
그래프 내에서 변경을 하는 데 사용되는 오브젝트입니다. |
RigElementKey |
본, 컨트롤, Null, 커브 중에서 선택합니다. |
본(Bone) |
디포메이션에 사용되는 스켈레톤의 릭 엘리먼트입니다. |
컨트롤(Control) |
인터랙션에 사용되는 릭 엘리먼트입니다. |
Null |
중간 트랜스폼에 사용되는 릭 엘리먼트입니다. |
커브(Curve) |
float 채널을 저장하는 데 사용되는 릭 엘리먼트입니다. |
셰이프(Shape) |
뷰포트 내 컨트롤의 시각적 표현입니다. |
계층구조(Hierarchy) |
릭 내의 모든 본, 컨트롤, Null, 커브를 저장하는 컨테이너입니다. |
HierarchyController |
HierarchyController는 컨트롤러와 유사하며 계층구조를 변경하는 데 사용됩니다. |
컴파일러(Compiler) |
컨트롤 릭 그래프를 고성능 런타임으로 변환하는 오브젝트입니다. |
VM |
릭 실행에 사용되는 가상 머신 런타임입니다. |
상수(Constant) |
런타임 시 변하지 않는 값입니다. |
파라미터(Parameter) |
릭의 입력 또는 출력으로 사용될 수 있는 값입니다. |
변수(Variable) |
런타임에서 변경될 수 있는 값으로 릭 실행 이후로 계속 유지됩니다. |
ControlRigBlueprint |
그래프, 컨트롤러, 컴파일러, VM을 포함하는 에셋입니다. |
팩토리(Factory) |
새 오브젝트 생성 및 임포트를 담당하는 오브젝트입니다. 언리얼 에디터 전체에 에셋을 생성하는 데 사용됩니다. |
Python은 Python 에디터 스크립트 플러그인(Python Editor Script Plugin) 으로 활성화되며, 이 플러그인은 언리얼 엔진에서 기본적으로 활성화됩니다. 또한 이 플러그인은 컨트롤 릭 플러그인(Control Rig Plugin) 이 활성화되면 종속성으로 인해 자동으로 활성화됩니다.
컨트롤 릭에 액세스하기
스크립팅의 첫 단계는 인터랙션할 메인 오브젝트에 액세스하는 것입니다. 이 경우는 ControlRigBlueprint 오브젝트에 액세스합니다. 액세스하는 방법에는 몇 가지가 있지만 첫 명령은 보통 컨트롤 릭을 변경하기 위해 ControlRigDeveloper 모듈을 로드하는 것입니다.
unreal.load_module('ControlRigDeveloper')
기존 릭에 액세스하려면 다음 예시 명령으로 에셋을 로드합니다.
rig = unreal.load_object(name = '/Game/ControlRig/Samples/Mannequin_ControlRig', outer = None)
다음을 사용하여 현재 열려 있는 컨트롤 릭 에셋을 로드할 수도 있습니다.
rigs = unreal.ControlRigBlueprint.get_currently_open_rig_blueprints()
새 컨트롤 릭 에셋은 다음과 같이 생성합니다.
factory = unreal.ControlRigBlueprintFactory()
rig = factory.create_new_control_rig_asset(desired_package_path = '/Game/TestRig')
마지막으로 다음 예시 코드를 사용하여 스켈레톤 또는 스켈레탈 메시를 기준으로 컨트롤 릭 에셋을 생성할 수 있습니다.
# 스켈레탈 메시 로드하기
mesh = unreal.load_object(name = '/Game/Mannequin/Character/Mesh/SK_Mannequin.SK_Mannequin', outer = None)
# 메시를 위한 컨트롤 릭 생성하기
factory = unreal.ControlRigBlueprintFactory
rig = factory.create_control_rig_from_skeletal_mesh_or_skeleton(selected_object = mesh)
Python 로그
Python 로그(Python Log) 는 컨트롤 릭 에디터 안에서 수행한 모든 액션의 텍스트 로그를 제공합니다. 여기에는 뷰포트, 계층구조, 그래프 내의 액션도 포함됩니다. 이 로그를 사용하여 Python 스크립트에서 사용할 명령을 참조하세요.
로그에 액세스하려면 메인 컨트롤 릭 메뉴에서 창(Window) > 메시지 로그(Message Log) 를 클릭한 다음 메시지 로그 사이드바에서 컨트롤 릭 Python 로그(Control Rig Python Log) 를 선택합니다.
이제 릭 그래프에서 액션을 수행하고 로그에 기록할 수 있습니다.
명령을 저장해서 공유하거나 다른 곳에서 사용하려면 로그에서 라인을 선택하고 Ctrl + C 를 눌러 복사한 후 다른 텍스트 에디터에 붙여넣으면 됩니다. Shift 키를 누른 채로 여러 라인을 선택할 수도 있습니다.
명령을 출력 로그(Output Log) 에 붙여넣고 실행하는 테스트를 수행하면 로그 유형이 Python으로 설정됐는지 확인할 수 있습니다 이 예시에서는 새 컨트롤이 생성되었습니다.
Python 컨텍스트
Python 컨텍스트는 Python 명령 실행 시 어떤 컨트롤 릭 에셋이 영향을 받을지 컨텍스트화하는 데 사용됩니다. 기본적으로 컨트롤 릭을 볼 때는 컨텍스트가 설정되어 있지 않습니다. 클래스 세팅(Class Settings) 디테일 패널에서 Python 컨텍스트 실행(Run Python Context) 을 클릭하여 현재 컨트롤 릭의 컨텍스트를 설정할 수 있습니다.
이렇게 하면 현재 컨트롤 릭 에셋을 Python 컨텍스트에 바인드하는 일련의 명령이 실행됩니다. 그러면 Python 로그에서 복사한 명령을 이 컨트롤 릭 에셋 안에 붙여넣고 실행할 수 있습니다.
blueprint.get_controller_by_name('').set_node_selection([])
import unreal
blueprint = unreal.load_object(name = '/Game/ShowAndTell202009/Pretzel/Mannequin_FBIK_CtrlRig', outer = None)
library = blueprint.get_local_function_library()
library_controller = blueprint.get_controller(library)
hierarchy = blueprint.hierarchy
hierarchy_controller = hierarchy.get_controller()
Python 스크립트 복사하기
컨트롤 릭의 노드, 릭 엘리먼트, 프로퍼티 전체를 클립보드에 복사할 수 있습니다. 그런 다음 이를 외부 스크립트 에디터에 붙여넣거나 출력 로그에 붙여넣고 다른 컨트롤 릭에서 실행할 수 있습니다. Python 스크립트 복사는 여러 릭 간의 로직 공유, 디버깅, 비교에 유용합니다. 개별 명령을 복사하는 것과 마찬가지로 전체 릭을 복사하는 것 또한 컨트롤 릭에서 Python 명령을 리버스 엔지니어링하는 데 도움이 됩니다.
컨트롤 릭을 복사하려면 클래스 세팅 디테일 패널에서 Python 스크립트 복사 를 클릭합니다.
Python 스크립트 예시
노드 추가하기
노드는 RigUnit 구조체의 시각적 표현이므로 그래프에 노드를 추가하려면 유닛에 액세스해야 합니다.
unreal.load_module('ControlRigDeveloper')
# 사용 가능한 모든 유닛의 배열 가져오기
units = unreal.ControlRigBlueprint.get_available_rig_units()
# 이 유닛에 대한 디테일 출력하기
for unit in units:
print(unit.get_path_name())
print(unreal.EditorAssetLibrary.get_metadata_tag(unit, 'Keywords'))
다음으로 컨트롤러에 액세스해야 합니다. 컨트롤러는 그래프를 변경하는 데 사용되는 중심적인 오브젝트입니다.
controller = rig.get_controller()
그래프에 노드를 추가하려면 add_struct_node
, add_comment_node
, add_parameter_node
또는 add_variable_node
함수를 사용할 수 있습니다. 아래 예시는 가장 일반적인 유형인 구조체 노드에 집중합니다. 구조체 노드는 RigUnit의 시각적 표현이므로 그래프의 노드 대부분은 구조체 노드입니다.
# 유닛 구하기 - 경로 또는 유사 방식으로도 구할 수도 있음
unit = unreal.RigUnit_MathFloatAdd.static_struct()
# 그래프에 유닛 구조체, 메서드(항상 Excute임), 2D 위치가 제공되는 경우 그래프에 노드를 추가하기
node = controller.add_unit_node(script_struct = unit, method_name = "Execute", position = unreal.Vector2D(0, 0))
계층구조 편집하기
그래프 편집뿐 아니라 계층구조도 Python 코드로 편집할 수 있습니다. 컨트롤 릭 계층구조의 각 릭 엘리먼트는 RigElementKey 를 사용하여 식별하며, 여기에는 엘리먼트의 이름과 유형이 포함됩니다. 계층구조 내의 엘리먼트를 생성하거나 엘리먼트와 인터랙션할 때 이 키를 사용해야 합니다.
컨트롤 릭 엘리먼트는 구조체입니다. 즉, 전체 값을 사용하여 복사됩니다. 그 결과 엘리먼트를 변경하면 계층구조에서 이를 다시 설정해야 할 수도 있습니다.
계층구조(Hierarchy) 는 엘리먼트를 쿼리하고, 글로벌/로컬 트랜스폼을 구하거나 설정하고, 엘리먼트를 초기 값으로 리셋하는 데 사용됩니다.
HierarchyController 는 엘리먼트를 추가, 제거, 편집하는 데 사용됩니다. 필요한 경우 이를 사용하여 엘리먼트의 이름을 변경하거나 부모를 다시 지정할 수도 있습니다.
현재 계층구조 검사를 수행하기 위해 다음 Python 코드를 사용할 수 있습니다.
# 계층구조 오브젝트에 액세스하기
hierarchy = rig.hierarchy
# 모든 엘리먼트 키를 구하여 출력하기
elements = hierarchy.get_all_keys()
for element in elements:
print(element)
릭 엘리먼트(예: 본)를 생성하기 위해 다음 코드를 사용할 수 있습니다.
# 계층구조 컨트롤러 오브젝트에 액세스하기
hierarchy_ctrlr = rig.get_hierarchy_controller()
# 새 본 추가하기
new_bone_key = hierarchy_ctrlr.add_bone(name = "MyBone", parent = unreal.RigElementKey(), transform = unreal.Transform())
# Z에서 10유닛 떨어져 있는 부모에 새 자손 본 추가하기
child_transform = unreal.Transform(location = [0, 0, 10])
new_child_bone_key = hierarchy_ctrlr.add_bone(name = "ChildBone", parent = new_bone_key, transform = child_transform)
변수 및 에셋 조작하기
게터 및 세터 노드가 있는 컨트롤 릭 변수를 생성하기 위해 다음 코드를 사용할 수 있습니다.
rig.add_member_variable("MyVariable", "Transform", is_public = True, is_read_only = False, default_value ="")
# 변수 게터 노드 생성하기
controller.add_variable_node_from_object_path(MyVariable, 'FTransform', '/Script/CoreUObject.Transform', is_getter = True, default_value = '', position = unreal.Vector2D(), node_name = 'MyVariable_Getter')
# 변수 세터 노드 생성하기
controller.add_variable_node_from_object_path(MyVariable, 'FTransform', '/Script/CoreUObject.Transform', is_getter = False, default_value = '', position = unreal.Vector2D(), node_name = 'MyVariable_Setter')
프리뷰 메시도 다음 코드를 사용하여 변경할 수 있습니다.
# 스켈레탈 메시 로드하기
mesh = unreal.load_object(name = '/Game/Mannequin/Character/Mesh/SK_Mannequin.SK_Mannequin', outer = None)
# 새(빈) 에셋 생성하기
factory = unreal.ControlRigBlueprintFactory()
rig = factory.create_new_control_rig_asset(desired_package_path = '/Game/TestRig')
# 프리뷰 메시 설정하기
rig.set_preview_mesh(preview_mesh = mesh)
컨트롤 릭은 컨텍스트에 따라 다음 코드를 사용하여 컴파일할 수 있습니다.
# VM 강제 리컴파일하기
rig.recompile_vm()
# 보류 중인 변경 사항이 있는 경우 VM 컴파일하기
rig.recompile_vm_if_required()
# 자동 컴파일이 활성화되어 있고 에디터가 열려 있으면 컴파일 요청하기
rig.request_auto_vm_recompilation()
# 컨트롤 릭에 init 패스 실행 요청하기(모든 유닛 초기화)
rig.request_control_rig_init()
# 컨트롤 릭에 전체 블루프린트 컴파일 실행 요청하기
unreal.BlueprintEditorLibrary.compile_blueprint(rig)
에디터 스타트업
에디터 스타트업 시 Python 스크립트를 로드할 수 있습니다. 이는 커스텀 툴과 내장 Python 함수를 로드하는 데 유용합니다. 프로젝트 디렉터리의 다음 폴더 경로에서 이 스크립트 및 샘플 스크립팅 함수를 찾을 수 있습니다.
Engine\Plugins\Animation\ControlRig\Content\Python
이 폴더 안에 있는 init_unreal.py 스크립트에는 다음 코드가 포함되어 있습니다.
import RigHierarchy.add_controls_for_selected
import RigHierarchy.add_null_above_selected
import RigHierarchy.align_items
RigHierarchy.add_controls_for_selected.run()
RigHierarchy.add_null_above_selected.run()
RigHierarchy.align_items.run()
이 코드는 추가 기능을 활성화하는 샘플 스크립트를 로드합니다.
예를 들어 add_controls_for_selected 는 선택된 본에서 컨트롤을 생성하는 함수와 함께 추가 규칙을 활성화합니다. 이러한 규칙은 Engine\Plugins\Animation\ControlRig\Content\Python\RigHierarchy\add_controls_for_selected.py에 위치한 커스텀 Python 스크립트에 의해 결정됩니다.