베리언트 매니저 개요를 읽어봤다면 '베리언트 매니저(Variant Manager)'에 포함된 베리언트 및 베리언트 세트에 대한 정보에 액세스하고 베리언트를 동적으로 전환하기 위해 '베리언트 매니저'가 런타임에서 사용할 수 있는 블루프린트 API를 제공한다는 것을 알고 있을 것입니다. 하지만 '베리언트 매니저'는 에디터에서 실행되는 스크립트에 대해서만 사용 가능한 별도의 API도 노출합니다. 이 에디터 전용 API를 사용하여 새로운 레벨 베리언트 세트(Level Variant Sets) 에셋 및 액터를 생성하고 씬 베리언트를 통해 이를 프로그래밍 방식으로 구성할 수 있습니다.
이는 다른 애플리케이션에서 이미 작성한 베리언트 또는 세팅을 반영하기 위해 언리얼 엔진 프로젝트에서 씬 베리언트를 자동으로 구성해야 하는 경우 특히 유용합니다. 이러한 씬 베리언트에 대한 데이터를 언리얼 에디터 스크립팅 시스템이 읽을 수 있는 포맷으로 익스포트할 수 있는 경우, 이 페이지에 설명된 방식을 사용하여 동일한 씬 베리언트를 언리얼 엔진에서 구성할 수 있습니다. 이렇게 하면 '베리언트 매니저' UI에서 동일한 베리언트를 수동으로 리빌딩하는 데 드는 시간과 노력을 절약할 수 있습니다. 또한 오류가 줄어들고 반복 사용할 수 있게 됩니다.
'베리언트 매니저'의 구성을 스크립트로 작성하는 데는 블루프린트 또는 Python을 사용할 수 있습니다.
씬 베리언트를 구성하는 데 있어 가장 중요한 노드는 블루프린트 팔레트의 베리언트 매니저 카테고리에 있습니다. 이 카테고리에 있는 노드를 사용하면 새로운 레벨 베리언트 세트 에셋을 생성하고, 해당 에셋에 베리언트 세트와 베리언트를 추가하고, 액터를 베리언트에 바인딩하고, 해당 액터를 위한 프로퍼티 값을 캡처할 수 있습니다.
현재는 베리언트 활성화 시 함수 호출하기에서 설명되어 있는 것과 같이 함수 호출자(Function Caller) 를 사용하여 바인딩된 액터를 구성하는 데 에디터 스크립팅 API를 사용할 수 없습니다. 스크립팅 API는 바인딩된 액터에 프로퍼티 값을 캡처하고 설정하는 데만 사용할 수 있습니다.
아래 표에는 가장 많이 사용되는 노드가 설명되어 있습니다.
![]() |
Create Level Variant Sets Asset | '콘텐츠 브라우저'에서 이름과 경로가 지정된 새로운 빈 레벨 베리언트 세트 에셋을 생성합니다. /Game/ 으로 시작해야 합니다. |
![]() |
Add Variant Set | 지정된 베리언트를 지정된 베리언트 세트의 자손으로 추가합니다. 이는 '베리언트 매니저' UI에서 + 베리언트 세트(+ Variant Set) 버튼을 클릭하는 것과 같습니다. 새로운 베리언트 세트를 처음부터 새로 생성하는 방법에 대한 지침은 아래 팁을 참고하세요. |
![]() |
Add Actor Binding | 지정된 베리언트에 지정된 액터를 추가합니다. 이는 월드 아웃라이너(World Outliner) 에서 액터를 드래그하여 '베리언트 매니저' UI에서 베리언트에 드롭하는 것과 같습니다. |
![]() |
Get Capturable Properties | '베리언트 매니저'가 지정된 액터에 대해 제어할 수 있는 모든 프로퍼티의 이름을 반환합니다. Capture Property 노드를 호출할 때 이러한 값 중에서 어떤 값이든 사용할 수 있습니다. |
![]() |
Capture Property | 지정된 베리언트에서 액터에 지정한 프로퍼티 값을 저장합니다. |
![]() |
Add Variant | 지정된 베리언트 세트의 자손으로 지정된 베리언트를 추가합니다. |
레벨 베리언트 세트 에셋에 추가하기 위해 새 베리언트 세트를 생성해야 하거나, 베리언트 세트에 추가하기 위해 새 베리언트를 생성해야 하는 경우 Construct Object from Class 노드를 사용할 수 있습니다. 첫 번째 입력에서, 생성해야 하는 클래스에 따라 VariantSet 또는 Variant 클래스를 지정합니다. 두 번째 Outer 입력에서, 구성하려는 레벨 베리언트 세트 에셋을 항상 사용합니다. 마지막으로, 출력 값을 Add 노드에 전달합니다. 예를 들어 이 스니펫은 새 베리언트 세트를 생성하여 이를 에셋에 추가한 다음 새 베리언트를 생성하고 이를 해당 베리언트 세트에 추가합니다.
블루프린트 예시
에디터 유틸리티 위젯의 다음 그래프는 '베리언트 매니저'를 프로그래밍 방식으로 구성하는 방법을 보여줍니다. 먼저, 작업할 새 액터를 생성합니다. 그런 다음 새 레벨 베리언트 세트 에셋을 생성하고 새 베리언트 세트로 이를 구성합니다. 마지막으로, 해당 베리언트 세트에 베리언트 두 개를 추가합니다. 하나는 액터가 표시되는 곳이고, 다른 하나는 액터가 숨겨지는 곳입니다.
이 예시를 실행한 후에는 레벨의 원점에 새 큐브가 생성된 것을 확인할 수 있습니다. 또한 베리언트를 전환하여 큐브를 표시하거나 숨길 수 있는 새 레벨 베리언트 세트 에셋이 생성됩니다.
씬 베리언트를 구성하는 데 있어 가장 중요한 클래스는 unreal.VariantManagerLibrary
입니다. 이 클래스를 사용하면 새로운 레벨 베리언트 세트 에셋을 생성하고, 해당 에셋에 베리언트 세트와 베리언트를 추가하고, 액터를 베리언트에 바인딩하고, 해당 액터에 대한 프로퍼티 값을 캡처할 수 있습니다.
현재는 베리언트 활성화 시 함수 호출하기에서 설명되어 있는 것과 같이 함수 호출자(Function Caller) 를 사용하여 바인딩된 액터를 구성하는 데 에디터 스크립팅 API를 사용할 수 없습니다. 스크립팅 API는 바인딩된 액터에 프로퍼티 값을 캡처하고 설정하는 데만 사용할 수 있습니다.
아래 표에는 가장 많이 사용되는 함수가 설명되어 있습니다. 이러한 함수와 함께 VariantManagerLibrary
에서 제공하는 기타 함수에 대한 자세한 내용은 Python API 레퍼런스를 참고하세요.
|
|
|
|
|
|
Python 예시
다음 예시는 새로운 레벨 베리언트 세트 에셋을 처음부터 새로 구성하는 방법을 보여줍니다.
이 예시에서는 먼저 큐브와 구체로 이루어진 씬을 구성한 다음 '베리언트 매니저'를 구성하여 이러한 액터의 위치와 비저빌리티를 변경합니다.
import math
import unreal
# 스크립트의 이 섹션은 10개의 부모 액터가 있는 기본적인 시작 씬을 구성합니다.
# 각 부모 액터는 씬 계층구조에서 구체와 큐브가 각각 1개인 총 2개의 자손 액터를 가지고 있습니다.
sphere_mesh = unreal.EditorAssetLibrary.load_asset('/Engine/BasicShapes/Sphere')
cube_mesh = unreal.EditorAssetLibrary.load_asset('/Engine/BasicShapes/Cube')
parent_actors = []
sphere_actors = []
cube_actors = []
for i in range(0,10):
parent_actor = unreal.EditorLevelLibrary.spawn_actor_from_class(unreal.StaticMeshActor, unreal.Vector(0, 0, 0), unreal.Rotator(0, 0, 0))
parent_actor.root_component.set_editor_property("mobility", unreal.ComponentMobility.MOVABLE)
parent_actor.set_actor_label("actor_" + str(i).zfill(3))
sphere_actor = unreal.EditorLevelLibrary.spawn_actor_from_class(unreal.StaticMeshActor, unreal.Vector(0, 0, 0), unreal.Rotator(0, 0, 0))
sphere_actor.static_mesh_component.set_static_mesh(sphere_mesh)
sphere_actor.root_component.set_editor_property("mobility", unreal.ComponentMobility.MOVABLE)
sphere_actor.attach_to_actor(parent_actor, unreal.Name(), unreal.AttachmentRule.KEEP_WORLD, unreal.AttachmentRule.KEEP_WORLD, unreal.AttachmentRule.KEEP_WORLD, False)
sphere_actor.set_actor_label("sphere_" + str(i).zfill(3))
cube_actor = unreal.EditorLevelLibrary.spawn_actor_from_class(unreal.StaticMeshActor, unreal.Vector(0, 0, 0), unreal.Rotator(0, 0, 0))
cube_actor.static_mesh_component.set_static_mesh(cube_mesh)
cube_actor.root_component.set_editor_property("mobility", unreal.ComponentMobility.MOVABLE)
cube_actor.attach_to_component(parent_actor.root_component, unreal.Name(), unreal.AttachmentRule.KEEP_WORLD, unreal.AttachmentRule.KEEP_WORLD, unreal.AttachmentRule.KEEP_WORLD, False)
cube_actor.set_actor_label("cube_" + str(i).zfill(3))
parent_actors.append(parent_actor)
sphere_actors.append(sphere_actor)
cube_actors.append(cube_actor)
# '콘텐츠 브라우저(Content Browser)'에서 이름과 경로가 지정된 레벨 베리언트 세트 에셋을 생성합니다.
# 경로는 항상 /Game/으로 시작해야 합니다.
lvs = unreal.VariantManagerLibrary.create_level_variant_sets_asset('ProceduralVariants', '/Game')
# 새로운 베리언트 세트를 생성하여 위치 베리언트를 관리합니다.
position_variant_set = unreal.VariantSet()
position_variant_set.set_display_text('Position')
# 레벨 베리언트 세트 에셋에 빈 베리언트 세트를 추가합니다.
unreal.VariantManagerLibrary.add_variant_set(lvs, position_variant_set)
# 이 섹션은 부모 액터를 일렬로 위치시키는 새로운 베리언트를 구성합니다.
# 먼저, 베리언트를 생성합니다.
position_variant_0 = unreal.Variant()
position_variant_0.set_display_text('Line')
# 각 부모 액터의 경우...
for i, actor in enumerate(parent_actors):
# 액터를 X 축을 따라 일렬로 위치시킵니다.
actor.set_actor_location_and_rotation(unreal.Vector(i*200, 0, 0), unreal.Rotator(0, 0, 0), False, True)
# 액터를 베리언트에 바인딩합니다.
unreal.VariantManagerLibrary.add_actor_binding(position_variant_0, actor)
# 액터의 스태틱 메시 컴포넌트의 상대적 위치 및 회전 프로퍼티를 캡처하여 현재 값에 저장합니다.
unreal.VariantManagerLibrary.capture_property(position_variant_0, actor, 'Static Mesh Component / Relative Location')
unreal.VariantManagerLibrary.capture_property(position_variant_0, actor, 'Static Mesh Component / Relative Rotation')
# 이제 베리언트가 구성되었으므로 이를 베리언트 세트에 추가합니다.
unreal.VariantManagerLibrary.add_variant(position_variant_set, position_variant_0)
# 이 섹션에서는 동일한 프로세스를 따라 두 번째 베리언트를 구성하지만,
# 이번에는 부모 액터를 일렬이 아닌 원형으로 배치합니다.
position_variant_1 = unreal.Variant()
position_variant_1.set_display_text('Circle')
for i, actor in enumerate(parent_actors):
actor.set_actor_location_and_rotation(unreal.Vector(1000*math.cos(i*360.0/(len(parent_actors)-1)), 1000*math.sin(i*360.0/(len(parent_actors)-1)), 0), unreal.Rotator(0, 0, 0), False, True)
unreal.VariantManagerLibrary.add_actor_binding(position_variant_1, actor)
unreal.VariantManagerLibrary.capture_property(position_variant_1, actor, 'Static Mesh Component / Relative Location')
unreal.VariantManagerLibrary.capture_property(position_variant_1, actor, 'Static Mesh Component / Relative Rotation')
unreal.VariantManagerLibrary.add_variant(position_variant_set, position_variant_1)
# 다양한 모양을 가진 여러 액터를 표시하고 숨기는 것을 관리하기 위해 새로운 베리언트 세트를 생성합니다.
shape_variant_set = unreal.VariantSet()
shape_variant_set.set_display_text('Shape')
unreal.VariantManagerLibrary.add_variant_set(lvs, shape_variant_set)
# 두 개의 베리언트를 생성합니다. 하나는 구체를 표시하고 큐브를 숨기며,
#다른 하나는 큐브를 표시하고 구체를 숨깁니다.
shape_variant_0 = unreal.Variant()
shape_variant_0.set_display_text('Sphere')
shape_variant_1 = unreal.Variant()
shape_variant_1.set_display_text('Cube')
# 각 구체 액터를 두 개의 베리언트에 바인딩하여 액터의 스태틱 메시 컴포넌트의 시각적 프로퍼티를 캡처합니다.
for i, actor in enumerate(sphere_actors):
actor.root_component.set_visibility(True)
unreal.VariantManagerLibrary.add_actor_binding(shape_variant_0, actor)
unreal.VariantManagerLibrary.capture_property(shape_variant_0, actor, 'Static Mesh Component / Visible')
actor.root_component.set_visibility(False)
unreal.VariantManagerLibrary.add_actor_binding(shape_variant_1, actor)
unreal.VariantManagerLibrary.capture_property(shape_variant_1, actor, 'Static Mesh Component / Visible')
# 각 구체 액터를 두 개의 베리언트에 바인딩하여 액터의 스태틱 메시 컴포넌트의 시각적 프로퍼티를 캡처합니다.
# 하지만 위 구체 액터에서 반대 비저빌리티 값을 저장합니다.
for i, actor in enumerate(cube_actors):
actor.root_component.set_visibility(False)
unreal.VariantManagerLibrary.add_actor_binding(shape_variant_0, actor)
unreal.VariantManagerLibrary.capture_property(shape_variant_0, actor, 'Static Mesh Component / Visible')
actor.root_component.set_visibility(True)
unreal.VariantManagerLibrary.add_actor_binding(shape_variant_1, actor)
unreal.VariantManagerLibrary.capture_property(shape_variant_1, actor, 'Static Mesh Component / Visible')
# 마지막으로, 베리언트 세트에 두 개의 베리언트를 추가합니다.
unreal.VariantManagerLibrary.add_variant(shape_variant_set, shape_variant_0)
unreal.VariantManagerLibrary.add_variant(shape_variant_set, shape_variant_1)
# 런타임에 블루프린트에서 사용할 수 있도록 현재 레벨에 레벨 베리언트 세트 에셋을 추가합니다.
lvs_actor = unreal.VariantManagerLibrary.create_level_variant_sets_actor(lvs)
결과는 다음과 같습니다. 각각 두 개의 베리언트가 있는 두 개의 베리언트 세트입니다.
-
첫 번째 베리언트 세트는 3D 공간에 있는 액터의 위치를 전환하여 액터를 일렬 또는 원형으로 정렬합니다.
-
두 번째 베리언트 세트는 큐브 메시와 구체 메시 간에 액터를 교체합니다.