반응형

언리얼엔진하면은 다룬다고 하면 알아야할 몇가지들이 있다. 그 중에서 언리얼엔진에서 베이스가 되는 프로퍼티 시스템인 리플렉션 이 있다.

 

 리플렉션이라는 것은 자바나 C#등에선 지원하지만, 언리얼엔진에서 사용되는 C++ 언어에서는 지원하지 않아 언리얼엔진에서 구현되어 있는 시스템이라고 했다.

 

하지만 난 리플렉션이라는게 뭐길래 엔진에서 구현해서 지원해주는것일까??  처음들어봐서 자바에서 어떻게 사용되는지 먼저 찾아보았다.

 

 

 

 

자바에서의 리플렉션 개념

자바에서의 리플렉션이란 객체를 통해 클래스의 정보를 분석해 내는 프로그램 기법을 말한다. 
(투영, 반사 라는 사전적인 의미를 지니고 있다.)

자바의 Reflection은 JVM에서 실행되는 애플리케이션의 런타임 동작을 검사하거나 수정할 수 있는 기능이 필요한 프로그램에서 사용됩니다. 쉽게 말하자면, 클래스의 구조를 개발자가 확인할 수 있고, 값을 가져오거나 메소드를 호출하는데 사용됩니다.

 

간단히 요약하자면, 컴파일 시간이 아니라 런타임시간에 동적으로 특정 클래스의 정보 객체화를 통해 분석 및 추출해낼수 있는 프로그래밍 기법이라고 표현할수 있다. (개발 과정에서 개발자에게 조금 더 도움이 되는 시스템이라고 다가왔다.)

 

 

 

 

 

언리얼 엔진에서의 리플렉션 

이런 좋은 시스템이 C++에는 지원하지 않아, 언리얼 엔진에서 구현되어 있는데, 우선  관련 설명을 찾아보면

리플렉션(Reflection)은 프로그램이 실행시간에 자기 자신을 조사하는 기능입니다.

이는 엄청나게 유용한 데다 언리얼 엔진 테크놀로지의 근간을 이루는 것으로, 에디터의 디테일 패널, 시리얼라이제이션, 가비지 콜렉션, 네트워크 리플리케이션, 블루프린트/C++ 커뮤니케이션 등 다수의 시스템에 탑재된 것입니다.


언리얼엔진 홈페이지 중...

위에서 '자기 자신'은 클래스, 구조체, 함수, 멤버 변수, 열거형 등을 의미하고 있다.

수집 된 정보는 UClass에 보관된다. 런타임에는 GetClass() 함수를 통해 접근하고, 컴파일 타임에서는 StaticClass()를 사용해 접근한다. 해당 함수들은 언리얼 헤더 툴에 의해 자동으로 생성된다.

 

 

 

 

 

잠깐, 왜 언리얼에서는 프로퍼티 시스템 이라고도 하는가?

전형적으로 이러한 리플렉션은 '프로퍼티 시스템'이라고 부르는데,그 이유로는 아마도 '리플렉션(Reflection/반사)'은 그래픽 용어라서 혼돈을 빚을 수 있기 때문인것 같다.(개인적인 추측)

 

 

리플렉션을 알려주는 방법?

 Unreal Header Tool (UHT)가 그 프로젝트를 컴파일할 때 해당 정보를 수집한다.

헤더(.h)에 리플렉션이 있는 유형으로 알려주려면, 헤더 파일 상단에 특수한 include 를 추가해 줘야 하야한다.

 그러면 리플렉션이 있는 유형은 이 파일을 고려해야 한다는것 그리고 시스템 구현에도 필요함을 UHT 에 알려줍니다.

그 #include는 아래와 같다.

#include "FileName.generated.h"

 

위와 같은 헤더가 추가 된다면, 이제 열겨형/UENUM(), 클래스/UCLASS(), 구조체/USTRUCT(), 함수/UFUNCTION(), 멤버변수/UPROPERTY() 를 사용하여 헤더의 다양한 유형과 멤버 변수 주석을 달 수 있다.

이 매크로 각각은 유형 및 멤버 선언 전에 오며, 추가적인 지정자 키워드를 담을 수 있습니다. 

 

 

 

 

 

리플렉션작동 원리

UBT(Unreal Build Tool) 는 그 역할을 위해 헤더를 스캔한 다음 리플렉션된 유형이 최소 하나 있는 헤더가 들어있는 모듈을 기억.

그 헤더 중 어떤 것이든 지난 번 컴파일 이후 변경되었다면, UHT 를 실행하여 리플렉션 데이터를 수집하고 업데이트.

UHT 는 헤더를 파싱하고, 리플렉션 데이터 세트를 빌드한 다음, (모듈별.generated.inl 에 기여하는) 리플렉션 데이터가 들어있는 C++ 코드를 생성할 뿐만 아니라, (헤더별 .generated.h 인) 다양한 헬퍼 및 thunk 함수도 생성.

 

요약 : 

1. UBT가 리플렉션 키워드 탐색

2. UHT가 해당 .cpp를 파싱

3. 리플렉션 데이터 정보를 수집

4. 수집된 정보는 별개의 C++ 코드 .generated.h / .cpp로 저장

5. 빌드 시 기존 코드에 .generated.h 코드를 추가해 컴파일

 

 

이렇게 UHT에 수집된 리플렉션 데이터는 별개의 코드로 저장되고 클래스이름.generated가 붙는다.

언리얼 실행환경은 이를 사용해 언리얼 오브젝트를 관리하고 에디터에서는 에디터에서 편집할 수 있는 인터페이스를 제공한다.

해당 파일들을 프로젝트 폴더에서 \Intermediate 폴더에 저장 된다. 클래스.h의 내용이 변경될때마다 자동 생성, 기존 파일을 덮어 쓴다.

 

 

 

generated 함수에는 StaticClass() / StaticStruct() 같은 것이 포함되어 있어, 유형에 대한 리플렉션 데이터를 구하는 것이 쉬워질 뿐만 아니라, 블루프린트나 네트워크 리플리케이션에서 C++ 함수를 호출하는 데 사용되는 thunk 를 구하는 것도 쉬워집니다.  이는 클래스나 구조체의 일부로 선언되어야 하며, GENERATED_UCLASS_BODY() 또는 GENERATED_USTRUCT_BODY() 매크로가 리플렉션된 유형에 포함되어야 하는지에 대한 이유가 됩니다.

이 매크로를 정의하는 #include 'TypeName.generated.h' 는 물론입니다.

 

 

 

ref : https://hyo-ue4study.tistory.com/182

 

반응형

+ Recent posts