씬 그래프 엔티티의 트랜스폼은 엔티티의 이동(translation)(위치), 회전(rotation)(방향), 스케일(scale)(크기)을 정의합니다. 씬 그래프 엔티티를 변환하려면 엔티티에 transform_component가 있어야 합니다. transform_component에는 UEFN 또는 Verse 코드를 통해 조작할 수 있는 다음과 같은 두 개의 필드가 있습니다.
원점(Origin): LocalTransform이 계산되는 선택 사항 원점입니다.
LocalTransform: 엔티티의 부모를 기준으로 하거나 선택 사항 원점 필드가 설정된 경우 원점을 기준으로 한
(/Verse.org/SpatialMath:)transform입니다.
엔티티의 원점은 엔티티 transform_component의 LocalTransform이 계산될 때 기준이 되는 엔티티입니다. 이는 transform_component의 원점 필드가 설정된 경우 원점 필드의 값이고, 원점 필드가 설정되지 않은 경우에는 씬 그래프 계층구조에서 엔티티의 부모입니다.
트랜스폼과 transform_component를 구분하는 것이 중요합니다. 트랜스폼은 /Verse.org/SpatialMath 모듈에 정의된 복합 데이터 타입으로, 다음 수치를 왼쪽-위쪽-앞쪽(LUF) 좌표계에 저장합니다.
이동(
vector3): 오브젝트의 위치입니다.회전(
rotation): 오브젝트의 방향입니다.스케일(
vector3): 오브젝트의 크기입니다.
transform_component는 /Verse.org/SceneGraph 모듈에 정의된 Verse 클래스로, 씬 그래프 엔티티의 LocalTransform을 저장하고, 선택 사항으로 대체 원점도 저장합니다. transform_component는 시뮬레이션에서 그 위치를 정의하는 트랜스폼을 위해 엔티티에 제공되는 컨테이너라고 생각할 수 있습니다.
Verse 트랜스폼
씬 그래프에서는 /Verse.org/SpatialMath 모듈 트랜스폼이 사용되고, Verse 모듈 트랜스폼에서는 오른손 LUF 좌표계가 사용됩니다. Verse 트랜스폼을 생성하려면 클래스 아키타입 및 rotations를 생성하는 기본 메서드를 사용하면 됩니다.
# Transform specifying all fields
MyTransform:transform = transform:
Translation := vector3{Left := 2.0, Up := -4.0, Forward := 8.0}
Rotation := MakeRotationFromEulerDegrees(-90.0, 180.0, 0.0)
Scale := vector3{Left := 2.0, Up := 4.0, Forward := 2.0}
# Transform specifying only Translation
MyOtherTransform:transform = transform:
Translation := vector3{Up := 512.0}
UEFN의 좌표계에 대한 자세한 내용은 왼쪽-위쪽-앞쪽 좌표계 페이지를 참고하세요. 페이지에는 /UnrealEngine.com/Temporary/SpatialMath 모듈의 XYZ 트랜스폼과 Verse 모듈 트랜스폼 간의 변환에 대한 정보도 포함되어 있습니다.
transform_component로 엔티티 생성하기
UEFN 아웃라이너 또는 Verse를 사용하여 엔티티를 생성할 수 있습니다.
UEFN의 경우
액터 배치(Place Actors) 메뉴를 통해 프로젝트에 씬 그래프 엔티티를 빠르게 추가할 수 있습니다.
액터 배치 메뉴를 통해 프로젝트에 씬 그래프 엔티티를 추가하면 기본적으로 엔티티에 transform_component가 포함되어 있습니다.
원하는 경우 아웃라이너 패널에서 최근에 배치된 엔티티로 이동한 후 transform_component를 찾아 컴포넌트 제거(Remove Component)를 선택하여 transform_component를 제거할 수 있습니다.
아래 이미지에서 해당 엔티티에 더 이상 transform_component가 없는 것을 확인할 수 있습니다.
Verse의 경우
다음과 같이 Verse 코드로 클래스 아키타입을 사용해 씬 그래프 엔티티를 생성할 수 있습니다.
MyEntity:entity = entity{}이 경우엔 엔티티에 transform_component가 없으므로, transform_component를 엔티티에 추가해야 합니다. 트랜스폼 작업에 선호되는 메서드는 SetLocalTransform과 SetGlobalTransform입니다. 이러한 함수는 transform_component 생성, 값 설정, 엔티티에 트랜스폼 컴포넌트 추가를 모두 동시에 처리합니다.
MyEntity:entity = entity{}
# Add entity to simulation entity so MyEntity begins simulating when play begins
if (SimEntity := Entity.GetSimulationEntity[]):
SimEntity.AddEntities(array{MyEntity})
# Identity transform
IdentityTransform:transform = transform:
Translation := vector3{Left := 0.0, Up := 0.0, Forward := 0.0}
Rotation := MakeRotationFromEulerDegrees(0.0, 0.0, 0.0)
또는 AddComponents를 사용하여 컴포넌트를 직접 추가할 수도 있습니다.
# Add entity to simulation entity so MyEntity begins simulating when play begins
if (SimEntity := Entity.GetSimulationEntity[]):
SimEntity.AddEntities(array{MyEntity})
# Use AddComponents
MyEntity.AddComponents(array{ transform_component{ Entity := MyEntity }})
# Same as above, but more readable if adding multiple components at once
MyEntity.AddComponents of array:
transform_component{Entity := MyEntity}Verse 코드로 씬 그래프 엔티티에 transform_component를 추가하는 다른 메서드는 Verse에서 transform_component 작업하기 섹션에 설명되어 있습니다.
엔티티의 트랜스폼이 계산되는 방식
transform_component를 사용하여 씬 그래프 엔티티에서 수행할 가장 중요한 작업은 엔티티의 트랜스폼을 가져오거나 설정하는 것입니다.
아래에서 살펴볼 두 가지 트랜스폼 타입은 로컬 트랜스폼과 글로벌 트랜스폼입니다. 엔티티의 트랜스폼을 효과적으로 조작하기 위해서는 이 두 트랜스폼이 어떻게 계산되는지 이해하는 것이 중요합니다.
로컬 트랜스폼은 엔티티의 원점을 기준으로 하는 트랜스폼입니다. 모든 씬 그래프 엔티티의 로컬 트랜스폼은 씬 그래프 엔티티의 transform_component에 있는 LocalTransform 필드의 값입니다.
글로벌 트랜스폼은 글로벌 스페이스의 LUF 좌표계 원점을 기준으로 하는 트랜스폼입니다. 씬 그래프 엔티티의 글로벌 트랜스폼은 엔티티의 LocalTransform을 다음과 같은 항목과 조합하여 계산합니다.
엔티티의 transform_component에서 원점 필드가 설정되어 있지 않은 경우 엔티티 부모의 글로벌 트랜스폼
엔티티의 transform_component에서 원점 필드가 설정된 경우 엔티티 원점의 글로벌 트랜스폼
아래에서는 이동을 추가하여 최종 트랜스폼을 계산할 수 있도록 회전과 스케일 조절 없이 이동만 사용하는 예시를 살펴봅니다. 이 예시에서는 회전과 스케일이 모든 트랜스폼에서 각각 동일 상태를 유지하는 것으로 가정하기 때문에, 엔티티의 트랜스폼을 엔티티의 트랜스폼 이동 벡터로 나타내는 데 약식 표현이 사용됩니다.
다음과 같이 구성된 세 개의 씬 그래프 엔티티를 가정해 보겠습니다.
BaseEntity: LUF 좌표계에서의 LocalTransform(0.0, 0.0, 0.0).
A: LocalTransform(750.0, 100.0, 0.0)
B: LocalTransform(-250.0, 100.0, 0.0)
아래 이미지는 씬에 있는 세 개의 엔티티를 보여줍니다. 여기서 BaseEntity에는 mesh_component가 없으며, A는 큐브이고 B는 원뿔입니다.
예를 들어 엔티티 B의 로컬 트랜스폼과 글로벌 트랜스폼을 결정하려 한다고 가정해 보겠습니다. 로컬 트랜스폼은 빠르게 알 수 있습니다. 아래 표시된 것처럼 엔티티 B transform_component의 LocalTransform 필드 값이 이에 해당합니다.
엔티티 B의 로컬 트랜스폼은 (-250.0, 100.0, 0.0)입니다.
엔티티 B의 글로벌 트랜스폼을 계산하려면, 엔티티 B의 계층구조를 시뮬레이션 엔티티까지 추적하여 시뮬레이션 엔티티부터 시작해 엔티티 B까지 내려가면서 트랜스폼을 조합해야 합니다. 시뮬레이션 엔티티는 여기에 속하는 다른 모든 시뮬레이션 엔티티가 자손이 되는 현재 시뮬레이션의 루트입니다.
엔티티 B의 글로벌 트랜스폼을 계산하는 단계는 다음과 같습니다.
시뮬레이션 엔티티는 현재 시뮬레이션의 루트입니다.
시뮬레이션 엔티티 글로벌 트랜스폼: (0.0, 0.0, 0.0).
BaseEntity는 시뮬레이션 엔티티의 자손입니다. 이미지 1.0에서와 같이 BaseEntity의 로컬 트랜스폼은 (0.0, 0.0, 0.0)입니다. 시뮬레이션 엔티티의 글로벌 트랜스폼과 BaseEntity의 로컬 트랜스폼을 조합하면 다음과 같은 값이 나옵니다.
BaseEntity 글로벌 트랜스폼: (0.0, 0.0, 0.0) + (0.0, 0.0, 0.0) = (0.0, 0.0, 0.0).
엔티티 A는 BaseEntity의 자손입니다. 이미지 1.1에서와 같이 엔티티 A의 로컬 트랜스폼은 (750.0, 100.0, 0.0)입니다. BaseEntity의 글로벌 트랜스폼과 엔티티 A의 위치 트랜스폼을 조합하면 다음과 같은 값이 나옵니다.
엔티티 A 글로벌 트랜스폼: (0.0, 0.0, 0.0) + (750.0, 100.0, 0.0) = (750.0, 100.0, 0.0).
엔티티 B는 엔티티 A의 자손입니다. 이미지 1.2에서와 같이 엔티티 B의 로컬 트랜스폼은 (-250.0, 100.0, 0.0)입니다. A의 글로벌 트랜스폼과 엔티티 B의 위치 트랜스폼을 조합하면 다음과 같은 값이 나옵니다.
엔티티 B 글로벌 트랜스폼: (750.0, 100.0, 0.0) + (-250.0, 100.0, 0.0) = (500.0, 200.0, 0.0).
따라서 LUF 좌표계에서 엔티티 B의 글로벌 트랜스폼은 (500.0, 200.0, 0.0)이 됩니다.
에디터에서 transform_component 작업하기
LocalTransform과 원점을 사용하여 엔티티의 트랜스폼을 조작할 수 있습니다.
로컬 트랜스폼
엔티티의 transform_component에 있는 LocalTransform 필드는 원점을 기준으로 한 엔티티의 (/Verse.org/SpatialMath:)transform입니다. 원점 필드가 명시적으로 설정되어 있지 않으면 엔티티의 원점은 씬 그래프 계층구조에서 해당 부모의 기본값으로 지정됩니다. LocalTransform 필드는 UEFN에 표시되는 편집 가능한 필드로, 여기에서 엔티티를 바로 편집할 수 있습니다.
이동: 해당 부모 또는 직접 정의된 원점을 기준으로 한 위치입니다.
엔티티의 이동을 변경하여 레벨에서 엔티티를 움직일 수 있습니다.
회전: 해당 부모 또는 직접 정의된 원점을 기준으로 한 방향입니다.
엔티티의 회전을 변경하여 엔티티의 피벗 포인트를 중심으로 엔티티를 회전할 수 있습니다.
스케일: 해당 부모 또는 직접 정의된 원점을 기준으로 한 크기입니다.
엔티티의 스케일을 변경하여 엔티티를 더 크거나 작게 만들 수 있습니다.
원점
엔티티 transform_component의 원점은 LocalTransform 계산의 기준이 되는 오브젝트입니다. transform_component의 이 필드는 선택 사항입니다. 기본적으로 transform_component의 LocalTransform은 엔티티 원점에 기반한 엔티티의 트랜스폼으로, 소유 엔티티의 부모 엔티티를 기준으로 계산됩니다. 원하는 경우 엔티티의 transform_component에 있는 원점 필드를 설정하여 엔티티의 부모가 아닌 오브젝트를 기준으로 LocalTransform을 계산할 수 있습니다.
예를 들어 엔티티의 원점을 완전히 다른 엔티티로 설정할 수 있습니다. Verse origin 인터페이스를 구현하는 클래스로 이 필드를 설정할 수 있습니다. 특히 원점 필드를 다른 씬 그래프 엔티티로 설정하려면 entity_origin 클래스를 선택한 후 새 원점으로 설정할 엔티티를 선택합니다.
transform_component의 원점과 LUF 좌표계의 원점을 구분하는 것이 중요합니다. LUF 좌표계의 원점은 이동이 (0.0, 0.0, 0.0)인 월드 스페이스 내의 지점입니다.
엔티티의 transform_component 원점은 엔티티의 transform_component LocalTransform의 이동이 (0.0, 0.0, 0.0)인 경우 엔티티가 위치하는 지점입니다.
아래에서는 원점 필드와 LocalTransform이 실제로 어떻게 동작하는지에 대한 예시를 살펴봅니다. BaseEntity가 월드 스페이스의 원점에 위치하고, mesh_component 큐브로 표현되는 자손 엔티티 A와 mesh_component 원뿔로 표현되는 자손 엔티티 B가 있다고 가정해 보겠습니다.
위의 이미지에서와 같이 transform_component에서 원점 필드가 설정되어 있지 않고 LocalTransform이 월드 스페이스의 원점으로 설정되어 있으므로, BaseEntity는 월드 스페이스의 원점에 위치합니다.
아래 이미지에서는 엔티티 A의 원점 필드도 설정되어 있지 않으므로, LocalTransform이 해당 부모인 BaseEntity의 transform_component를 기준으로 계산되어 있는 것을 알 수 있습니다.
BaseEntity가 월드 스페이스의 원점에 위치해 있고 엔티티 A의 LocalTransform 이동이 vector3{Left := 750.0, Up := 100.0, Forward := 0.0}으로 설정되어 있으므로, 엔티티 A는 vector3{Left := 750.0, Up := 100.0, Forward := 0.0}에 위치합니다. BaseEntity에 있는 LocalTransform의 회전과 스케일은 각각 동일 상태를 유지하므로, 엔티티 A의 회전과 스케일은 변경되지 않습니다.
아래 이미지에서 BaseEntity의 자손이기도 한 엔티티 B에서 transform_component의 원점 필드가 엔티티 A로 설정된 것을 볼 수 있습니다.
그 결과 엔티티 B의 transform_component에 있는 LocalTransform 필드는 엔티티 A의 계산된 트랜스폼을 기준으로 합니다. 엔티티 B의 LocalTransform은 vector3{Left := -250.0, Up := 100.0, Forward := 0.0}으로 설정되어 있고 엔티티 A의 LocalTransform은 vector3{Left := 750.0, Up := 100.0, Forward := 0.0}으로 설정되어 있어, 엔티티 B의 글로벌 트랜스폼은 vector3{Left := 500.0, Up := 200.0, Forward := 0.0}이 됩니다.
엔티티 A의 transform_component에서 LocalTransform 필드의 회전 컴포넌트를 앞쪽 축에서 -90.0도로 변경하면 엔티티 B도 앞쪽 축에서 -90.0도 회전합니다. 이는 자손의 회전 역시 부모로부터 상속되기 때문입니다.
Verse에서 transform_component 작업하기
GetComponent를 사용하여 엔티티에 transform_component가 있는지 확인할 수 있습니다.
MyEntityNoTransform:entity = entity{}
if (SimEntity := Entity.GetSimulationEntity[]):
SimEntity.AddEntities(array{MyEntityNoTransform})
MyEntityWithTransform:entity = entity{}
MyEntityWithTransform.AddComponents of array:
transform_component{Entity := MyEntityWithTransform}
if (SimEntity := Entity.GetSimulationEntity[]):
GetComponent를 사용하여 transform_component를 가져와 transform_component로 직접 작업하는 대신, 엔티티 익스텐션 메서드를 통해 transform_component 작업을 하는 것이 좋습니다.
트랜스폼
엔티티 익스텐션 메서드 SetLocalTransform 또는 SetGlobalTransform을 사용하여 엔티티의 로컬 또는 글로벌 트랜스폼을 직접 설정할 수 있습니다.
MyEntity:entity = entity{}
MyTransform:transform = transform{}
if (SimEntity := Entity.GetSimulationEntity[]):
SimEntity.AddEntities(array{MyEntity})
# Set the local transform
MyEntity.SetLocalTransform(MyTransform)
MyOtherEntity:entity = entity{}
Verse 코드로 씬 그래프 엔티티에 트랜스폼을 설정하는 데 이러한 익스텐션 메서드가 자주 사용되며, 이 메서드는 명시적으로 해당 엔티티의 로컬(엔티티의 부모 기준) 또는 글로벌(월드 원점 기준) 트랜스폼을 설정합니다. 이 함수 중 하나가 호출될 때 엔티티에 transform_component가 없으면 transform_component가 묵시적으로 생성되어 엔티티에 추가됩니다. 이러한 함수 중 하나가 호출되면 이제 엔티티에 transform_component가 생깁니다. GetComponent에 이어서 후속 호출로 이를 확인할 수 있습니다.
if (MyEntity.GetComponent[transform_component]):
# success, entity has a transform_component
else:
# failure, entity does not have a transform_component
익스텐션 메소드를 사용하여 엔티티의 연결된 transform_component의 로컬 트랜스폼 또는 글로벌 트랜스폼을 얻을 수 있습니다. GetLocalTransform은 해당 부모 엔티티 또는 지정된 원점(설정된 경우) 필드에 따라 엔티티의 트랜스폼을 반환합니다. 엔티티에 transform_component가 없으면 이 함수는 동일 상태 트랜스폼을 반환합니다.
# Entity object
MyEntity:entity = entity{}
if (SimEntity := Entity.GetSimulationEntity[]):
SimEntity.AddEntities(array{MyEntity})
# Obtain the local transform with respect to Parent or Origin (if set)
EntityLocalTransform := MyEntity.GetLocalTransform() # no transform component, returns identity
MyOtherEntity:entity = entity{}
GetGlobalTransform은 월드 원점에 따라 엔티티의 트랜스폼을 반환합니다. 엔티티에 transform_component가 없으면 이 함수는 transform_component가 있는 가장 가까운 조상의 글로벌 트랜스폼을 반환합니다.
# Entity object
MyEntity:entity
if (SimEntity := Entity.GetSimulationEntity[]):
SimEntity.AddEntities(array{MyEntity})
# Obtain the global transform
EntityGlobalTransform := MyEntity.GetGlobalTransform() # returns global transform of Simulation Entity
원점
transform_component 원점 필드를 사용하는 작업에서도 엔티티 익스텐션 메서드를 사용할 수 있습니다. 엔티티 익스텐션 메서드 SetOrigin을 사용하여 엔티티 transform_component의 원점 필드를 직접 설정할 수 있습니다.
MyEntity:entity = entity{}
MyOtherEntity:entity = entity{}
if (SimEntity := Entity.GetSimulationEntity[]):
SimEntity.AddEntities(array{MyEntity, MyOtherEntity})
MyEntity.SetLocalTransform(transform{Translation := vector3{Left := 100.0}})
# Construct an entity_origin object and set the new origin of MyEntity to MyOtherEntity
NewOrigin:entity_origin = entity_origin{Entity := MyOtherEntity}
Verse 코드에서 엔티티의 원점을 가져오려면 GetOrigin을 사용합니다.
MyEntity:entity = entity{}
if (SimEntity := Entity.GetSimulationEntity[]):
SimEntity.AddEntities(array{MyEntity})
if (OriginValue := MyEntity.GetOrigin[]):
# should not succeed
else:
# should fail, no transform_component on entity MyEntity
GetOrigin은 엔티티의 원점 필드가 설정되어 있는지 확인하고, 설정되어 있는 경우 해당 필드의 값을 반환합니다. 설정되어 있지 않으면 호출이 실패합니다. 성공 시 GetOrigin의 반환 타입은 origin 인터페이스를 구현하는 Verse 클래스인 origin 오브젝트입니다. 이 인터페이스는 엔티티에 지정된 원점의 트랜스폼을 가져오는 단일 함수 GetTransform을 제공합니다. 대체 원점 필드가 엔티티로 설정되어 있는지를 확인하고 엔티티의 원점으로 설정된 엔티티가 무엇인지 알아낼 수도 있습니다.
if:
OriginValue := MyOtherEntity.GetOrigin[] # get Origin object
OriginEntityCast := entity_origin[OriginValue] # cast to entity_origin
then:
# Obtain the entity that is set as MyOtherEntity's Origin field on its transform_component
MyOtherEntityOrigin := OriginEntityCast.Entity
# Obtain the origin's transform
TransformOfOrigin := OriginEntityCast.GetTransform()
마지막으로, ResetOrigin을 사용하여 엔티티 transform_component의 원점 필드를 리셋할 수 있습니다.
MyEntity.ResetOrigin()ResetOrigin을 호출하면 MyEntity의 transform_component에 있는 원점 필드가 리셋되고 MyEntity의 트랜스폼이 이제 씬 그래프 계층구조에서 MyEntity의 부모 엔티티에 따라 계산됩니다.
종속 컴포넌트
다른 몇 가지 씬 그래프 컴포넌트는 작동하는 데 transform_component에 의존합니다. 다음과 같은 에셋이 포함됩니다.
light_component 및 해당 자손 클래스
mesh_component
particle_system_component
아직 transform_component가 없는 씬 그래프 엔티티에 이 컴포넌트를 추가하면 기본적으로 transform_component가 엔티티에 추가됩니다.
XYZ 트랜스폼 관련 참고 사항
XYZ 좌표계를 사용하는 트랜스폼은 /UnrealEngine.com/Temporary/SpatialMath Verse 모듈에 그대로 있으며, 이러한 트랜스폼은 /Fortnite.com Verse 모듈의 포크리 장치 및 사물에서 계속해서 사용됩니다. 이러한 트랜스폼의 상태와 Verse에서의 여러 트랜스폼 타입 간 변환에 대한 자세한 내용은 왼쪽-위쪽-앞쪽 좌표계 페이지를 참고하세요.