개발 고수(가 되고 싶은) 블로그

엔진공부/언리얼 공부

[언리얼 공부] 언리얼 리플렉션 시스템

개발고수(가되고싶음) 2024. 8. 21. 01:39

 유니티를 다뤄봤다면 리플렉션 이라는 것을 들어본 적이 있을것이다.  모던 객체지향의 정수라고 불리며 런타임중 자기 자신을 검사하고 조작할 수 있는 기능을 말한다. 이런 리플렉션을 적절히 활용하면 런타임중 클래스, 메서드, 필드등의 메타데이터를 동적으로 조회가 가능하다. 하지만 C++ 은 이전 글에서 다뤘듯이 리플렉션 시스템을 지원하지 않는다. 따라서 언리얼에서 독자적으로(*온몸비틀기를 통해) 리플렉션 시스템을 구축하였는데 오늘은 그 내용을 다뤄보고자 한다. 

언리얼의 리플렉션 시스템이란?

  • C++은 원래 리플렉션 지원하지 않는다. 하지만 UBT(Unreal Build Tool)와 UHT(Unreal Header Tool)를 이용하여 리플렉션 시스템이 구축되어있어 사용자는 편하게 사용할 수 있다.
  • 언리얼의 에디터 패널, 직렬화, 가비지 콜렉션 등 모두 리플렉션을 기반으로 한다.
  • 만약 raw C++ 을 사용하여 리플렉션 되지 않은 프로퍼티는 가비지 콜렉터가 관리 할 수 없으므로 프로그래머가 직접 관리가 필요하다.
  • UENUM(), UCLASS(), USTRUCT(), UFUNCTION(), UPROPERTY()을 사용하여 기능 활성화 가능한 구조로 되어있다.

UHT(언리얼 헤더툴)

  • 실제 C++ 파서가 아니므로 너무 구조가 복잡하면 읽지 못한다. (이 역시 온몸 비틀기로 c++ 를 리플렉션하도록 만든 결과)
  • UCLASS 매크로가 붙은 클래스에 대해 엔진에서 사용할 수 있는 다양한 메타데이터를 포함한 코드가 생성된다. 이 메타데이터를 이용해서 블루프린트나 가비지 컬렉터에서 이용할 수 있게 해준다.
  • 언리얼 엔진에서 코드를 수정후 컴파일을 돌리게 되면 리플렉션을 위한 데이터 생성한다. (예: generated.h)
  • 리플렉션 데이터 사용 시 바이너리와 동기화 보장한다. (즉 안전하게 사용 가능하다)
  • 작동방식
    • 소스코드 분석 -> 메타데이터 생성-> 코드 자동생성

UBT(Unreal Build Tool)

  • 언리얼 프로젝트를 빌드하는데 사용되는 도구이다. 
  • 프로젝트 구성을 C# 으로 관리하며 Target.cs, Build.cs 를 통해 관리한다.
  • 멀티 플래폼을 지원하며 모듈 및 플러그인도 관리해주며 빌드 종속성을 관리하여 모듈에 대해 순서를 맞춰 빌드를 수행한다.
  • 빌드 설정에 따라 최적화 수준을 조정해준다. 최적화는 
    • Development 빌드 : 디버그가 가능한 정도로 최적화한 빌드, 디버깅 기능, 로그 활성화 등을 하기 때문이다. 하지만 덜된 최적화 대신 빌드는 빠르다. 
    • Shipping 빌드 : 릴리즈를 위해 성능을 극대화 한 빌드, 디버깅 정보, 로그 메시지 비활성화 한다. 또 최고 성능을 목표로 빌드를 하기 때문에 실행되지 않는 코드 제거, 메모리 배치 최적화등 극한의 최적화를 한다. 그래서 빌드시간은 Development 빌드보다 빌드 시간이 오래걸린다.
  • 작동 방식
    • 타겟파일, 빌드 파일 읽기 -> 컴파일 및 링크 -> 빌드 로그 & 오류 출력

언리얼 오브젝트의 구성

  • 언리얼 오브젝트에는 리플렉션을 위해 프로퍼티와 함수를 지정할 수 있다.
    • 에디터와 연동되는 메타데이터를 심을 수 있다. 또한 UPROPERTY 에서 사용 가능하도록 조정하면 블루프린트에서 변경도 가능하다.
    • 클래스를 사용해 프로퍼티와 함수 정보를 컴파일 타임 & 런타임에서 조회 가능
  • 이런 언리얼 오브젝트는 NewObject API를 사용하여 생성해야 함 (new가 아닌 newObject로 생성)
  • 언리얼 클래스 정보에 클래스 기본 오브젝트가 포함된다.
  • 언리얼 기본 클래스 오브젝트(CDO: class default object)를 왜 사용 해야하는가?
    • 일관성 있게 기본값 조정에 유용하다.
    • GetDefaultObject 함수를 통해 얻을 수 있다.
    • 엔진 초기화 과정에서 초기화되므로 안심하고 사용 가능
      • 생성자 코드는 엔진 초기화과정에 초기화가 되는데 수정하게 된다면 에디터를 끄고 빌드해야 적용이 된다.

가비지 컬렉션

  • 더 이상 참조되지 않은 UObject를 주기적으로 정리한다.
  • UObject의 상속을 받은 클래스가 UPROPERTY가  상단에 없는 오브젝트의 경우에는 가비지 컬렉터에서 래퍼런스가 없는줄 알고 냅다 회수해버리고 의문의 Nullptr 이 이상한데에서 날 수 있다.

요약

  • 언리얼 오브젝트를 멤버 변수로 사용시 반드시 UPROPERTY 를 넣어줘야한다.
  • 생성자가 변경되거나, UPROPERTY에 선언된 변수가 생긴다면 에디터를 끄고 컴파일후 에디터를 켜야한다.
반응형