본문 바로가기
Unreal Engine 5

GetWorld와 GetLevel은 어떻게 구현되어 있을까?

by 니키티스 2024. 4. 25.

언리얼 엔진을 공부한 지 이제 몇 주 됐는데 아직도 기초 개념을 잘 모르겠다. 그래서 레퍼런스를 보고 공부한 내용을 한 번 정리해 보기로 했다.

오늘의 내용은 언리얼 엔진의 가장 기초가 되는 부분, 월드와 레벨에 대해 접근하는 GetWorld와 GetLevel 함수가 되겠다.

월드와 레벨이 어떤 것인지는 가볍게만 다뤄놨으니 필요하다면 언리얼 레퍼런스를 참고하는 것을 추천한다.

월드(UWorld)

맵 혹은 샌드박스를 표현하는 최상위 오브젝트로 액터와 컴포넌트가 존재하고 렌더링되는 공간이다.

멤버를 보면, ULevel 컴포넌트, BatchComponent, 레이어, NetworkManager, PhysicsCollisionHandler 등 게임에 필요한 상위 오브젝트를 소유하고 있음을 알 수 있다.

액터(AActor)

액터는 언리얼 엔진의 월드를 구성하는 가장 기본적인 단위가 되는 오브젝트이다.

GetWorld 함수와 GetLevel은 액터의 멤버 함수로 들어가 있다. 그 때문에 실제 액터에서 호출할 때 바로 GetWorld(), GetLevel() 같은 식으로 호출하게 되어 있다.

두 함수는 어떤 함수인 걸까?

UWorld* GetWorld()

언리얼 엔진에서 월드에 접근하는 방법. 해당 함수를 호출하여 액터가 소속된 월드에 접근할 수 있다.

내부적으로는 AActor::GetLevel() 함수로 현재 레벨에 대한 ULevel 포인터를 가져온 다음, 해당 레벨의 OwningWorld 변수를 통해 월드를 찾도록 한다.

ULevel* GetLevel()

GetLevel은 해당 액터가 소속된 레벨 객체 ULevel을 가리킨다.

ULevel?

ULevel은 레벨이다. 언리얼 엔진에서의 맵 개념이며 유니티로 비유하자면 Scene이다. 스트리밍되고 있는 ULevel이 바로 현재 유저가 보고 있는 맵이 된다.

스크립트적으로는, ULevel은 레벨의 액터 목록, BSP(Binary space partitioning), 브러시 리스트를 갖는다.

모든 레벨은 월드를 바깥 객체(Outer)로 가지며 Persistent Level로 사용할 수 있지만, Owning World에 의해 스트리밍된 경우 해당 레벨이 속한 월드를 나타낸다. 레벨은 액터(light, volumes, mesh 인스턴스 등) 모음이다. 여러 레벨을 World로 로드하고 해제하면서 streaming experience를 만들 수 있다.

BSP가 뭘까?

여기서 BSP란 binary space partitioning의 약자로 언리얼 엔진에서는 지오메트리 브러시를 예전에는 BSP 브러시라고 불렀다. 그래서 언리얼에서 BSP는 지오메트리 브러시를 의미하는 용어로 사용된다.

지금은 레벨에 지오메트리(기하(geometry). 여기서는 맵의 구조적인 구성을 의미함)를 채울 때 스태틱 메시가 주로 사용되지만, 예전에는 지오메트리 브러시를 사용했다(요즘도 가끔 사용함). 한마디로 요약하자면 레벨의 프로토타이핑 과정에서 많이 사용하는 도구이다.

보통 프로토타이핑에서 완성된 아트 에셋으로 레벨을 채우기 전에 레벨의 윤곽을 만드는 작업으로 전체적인 흐름을 파악하곤 한다. 이때 지오메트리 브러시를 사용하여 레벨의 윤곽을 잡고 테스트 및 반복 작업을 통해 최종 레이아웃을 결정하도록 한다. 레벨 디자인 프로세스의 이런 측면에서는 지오메트리 브러시가 가장 적합한데, 그 이유는 시간도 거의 들지 않고 아트 팀이 개입하지 않아도 되기 때문이다.

위에서 설명한 것처럼 하나의 게임에는 많은 레벨을 사용될 수 있는데, 만약 오픈 월드 식으로 맵을 구성하고 싶다면 UE5에서 제공되는 ‘월드 파티션’의 사용을 권장한다.

GetLevel의 내부적인 구현

GetLevel은 내부적으로는 GetTypedOuter()을 반환하는 것으로 구현된다.

이 GetTypedOuter(Target)는 UObject에서 부모에 해당하는 객체를 찾는 함수이다. 실제로 GetTypedOuter는 이름 그대로 GetOuter() 함수를 연속 호출하면서 타입이 Target인 UObject를 찾는 식으로 구현되어 있다.

쉽게 말해서 부모 객체를 따라 반복적으로 올라가면서 ULevel을 찾는 함수이다.

GetOuter()?

이 GetOuter() 함수는 대체 뭘까?

이를 이해하기 위해서는 이득우 님의 다음 글을 먼저 읽어오는 것이 좋다.

[1-7] 언리얼 오브젝트의 계층 구조

 

[1-7] 언리얼 오브젝트의 계층 구조

안녕하세요~ 이번 강좌에서는 언리얼 오브젝트의 계층 구조를 다뤄보겠습니다.  강좌에서 스크롤의 압...

blog.naver.com

내용을 간단히 정리하면 이러하다.

언리얼 오브젝트 간에는 위계 관계가 존재한다. 생성자에서 CreateDefaultSubobject를 호출하거나(인스턴스 생성과 동시에 생성됨), 런타임에 NewObject를 호출하여(런타임 중 생성) 하위 오브젝트를 생성할 수 있다.

부모 오브젝트에서는 GetDefaultSubobjects(TArray*)로 하위 오브젝트를 참조하고, 하위 오브젝트에서는 GetOuter()로 부모 오브젝트를 참조한다. 그래서 이 구조는 부모-자식 관계로 나타낼 수 있다.

언리얼에서 게임 콘텐츠 구조도 마찬가지로, 월드(World) 아래에 레벨(Level)이 존재하며 각 레벨에는 월드의 초기 설정값을 지정한 월드 세팅 언리얼 오브젝트와 액터들이 존재한다. 레벨 중 월드에 최소한 하나의 레벨이 지정되는데, 이를 퍼시스턴트 레벨(Persistent Level)이라 부른다. 이외에도 월드에 무관하게 추가/삭제가 가능하도록 설계된 레벨이 스트리밍 레벨이라 부른다.

원글에는 더 많은 내용이 있으니, 직접 읽어보는 것을 추천한다. 특히 언리얼 엔진에서 월드의 계층 구조와 오브젝트별 생성 방식에 대해 자세히 설명되어 있어 유익하다.

다만, 실제로는 AActor에서 계속해서 GetOuter 함수를 호출하면 Level, World, 그다음으로 Package까지 나오게 된다. 해당 내용은 아래 미누시 님의 글에서 자세히 정리되어 있으니 참고하자.

언리얼 오브젝트(Unreal Object) - Outer (tistory.com)

 

언리얼 오브젝트(Unreal Object) - Outer

언리얼 엔진에서 사용되는 함수들 중에서 Outer를 인자로 요구하는 함수들이 있습니다: NewObject, CreatePackage, SavePackage... 대부분의 경우, 해당 함수를 호출하는 클래스(this)를 인자로 집어넣으면 상

minusi.tistory.com

 

레퍼런스


UWorld::GetWorld | Epic Developer Community (epicgames.com)

ULevel | Unreal Engine Documentation

언리얼 엔진의 지오메트리 브러시 액터 (epicgames.com)

[1-7] 언리얼 오브젝트의 계층 구조

언리얼 오브젝트(Unreal Object) - Outer (tistory.com)

 

 

댓글