안녕하세요~ Halcy  입니다. 


오늘은 Detail Customization 의 마지막 튜토리얼로, 저번시간에 말씀드렸듯이 SComboBox를 이용하여 언리얼 공식문서와 비슷하게 Dynamic, Static 등을 선택 할 수 있게 만들어 보겠습니다!


일단 시작은 SComboBox가 무엇인가에 대해 알아보겠습니다 !


(사진 1-1) SComboBox


(사진 1-2) UMG ComboBox


ComboBox란 위 사진 처럼 클릭 했을 때 목록이 나오고 그 목록을 눌렀을 때 어떠한 이벤트등이 발생하는 Widget입니다.


(사진 1-3) 오늘의 목표!


오늘은 저 SComboBox를 이용하여 사진 1-3 을 Lighting 탭에 추가해 볼 것입니다.


(사진 1-4) CustomizeDetails 처음추가


일단 해당 콤보박스가 들어갈 곳의 이름을 MyCustomComboBox로 지정하였습니다. 그리고 SComboBox안에 저희는 String을 넣을 것이므로 TSharedPtr<FString>을 넣어주었습니다. 


그리고 실행을 해보면..!


(사진 1-5) 실패 1


위 사진 1-5 처럼 제공된 콘텐츠가 없다고 나올 것입니다. 실제로 저희는 FString을 넣을 것이라고만 명시한 뒤 그 string이 무엇인지에 대해서는 정하지 않았습니다.



(사진 1-6) 헤더에 Options 추가

(사진 1-7) Options 추가


SComboBox에서는 안에 들어갈 내용을 Option 이라고 합니다. 우리는 FString 을 넣을 것이기 때문에 FString의 배열을 Options라는 이름으로 하나 선언해 주었습니다. 그리고 그 내부에 Dynamic과 Static을 하나씩 넣어준뒤 SComboBox 클래스에 옵션을 설정해주는 OptionsSource 로 전달해 줍니다. 


이제 다시 컴파일을 해보면.. !


(사진 1-8) 실패 2


이번에도 역시 제공된 콘텐츠가 없다고 나오지만 눌러보면 안의 내용이 OnGenerateWidget() 핸들러를 제공해 주세요. 로 바뀌어 있을 것입니다..!


이제 OnGenerateWidget()을 해야하는 것을 알았으니 이게 무엇인지 알아보겠습니다.


(사진 1-9) OnGenrateWidget은 무엇인가 출처(언리얼 공식문서)


번역하면


"옵션을 나타내는 위젯을 생성하는데 사용하는 델리게이트" 


정도로 번역 할 수 있을 것입니다. 한마디로 우리가 SComboBox를 눌렀을 때 아래에 나올 리스트 위젯을 만들때 사용하는 델리게이트 정도로 알 수 있을 것입니다. 


이제 이것을 어떻게 사용하는 것인지 알아보겠습니다.


일단 OnGenerateWidget()이 어떠한 형태의 델리게이트인지 알아보기위하여 엔진내부를 살펴봤습니다.


(사진 1-10) FOnGenerateWidget 선언부


FOnGenerateWidget이 OnGenerateWidget의 델리게이트 이름입니다. 이것을 기반으로 찾아보니 사진 1-10와 같이 선언부가 나왔는데요. 델리게이트 선언 매크로를 기반으로 언리얼 문서에서 다시 찾아보았습니다.


(사진 1-11) 델리게이트 설명 출처(언리얼 공식문서)


사진 1-11 에서 보시는 바와 같이 저러한 형태가 될 것이고, RetValType은 사진 1-10에서 보시면 TSharedRef<SWidget>이 될것이며, Param1Type은 ArgumentType이 되는데 저희는 ArgumentType을 TSharedPtr<FString> 으로 사진 1-7에서 정했습니다. 


그러므로 바인딩 되어야 할 함수의 구조는 


TSharedRef<SWidget> FunctionName(TSharedPtr<FString>)


이 되어야 할 것입니다. 이제 이러한 함수 하나를 헤더에 선언해보겠습니다.


(사진 1-12) 함수 추가


그리고 다시 CPP에 이 함수의 몸통을 만들어 보겠습니다.


(사진 1-13) 함수 몸통 추가


저희는 FString 을 인자로 받을 것이기 때문에 FString을 보여주기 가장 쉬운 방법인 STextBlock을 이용하여 반환 할 것입니다. 또한 OnGenerateWidget에 바인딩된 함수는 이 SComboBox가 가지고 있는 Option의 갯수만큼 실행될 것이고 InOption은 실행 횟수마다의 배열인자가 들어갈 것이므로 이렇게 설정해주면 SComboBox를 클릭하였을 때, 


Dynamic

Static


순으로 배치 될 것입니다.


(사진 1-14) 함수 바인딩


함수가 완성 되었으므로 OnGenerateWidget에 이 함수를 바인딩 하겠습니다. 첫 번째 인자는 바인딩 할 함수가 위치하는 클래스이고, 저희는 같은 클래스 내에서 처리할 것이기 때문에 this를 넣어줍니다. 그 후 바인딩 할 함수를 넣어주면 되겠습니다.


이제 다시 컴파일 해보겠습니다.


(사진 1-15) 실패.... 반만 성공


확인을 해보면 역시 아직 제공된 콘텐츠가 없다고 나오지만 클릭을 했을 때는 저희가 원하던 결과가 나오는 것을 확인 할 수 있습니다..! 


자 그럼 왜 처음 켜졌을 때 값은 안나오면 다른 걸 클릭해도 변하지 않는가... 고민을 해보면... 


Slate는 처음부터 끝까지 프로그래머가 모든 것을 지정해야만 하는 특성이 있습니다. 특성이라기 보다는 원래 코딩이라는게 그런거지만 언리얼이 워낙 프로그래머에게 편하도록 구성이 되어있어 하다보면 당연한 것을 잊게 되곤 하지요.. ㅎㅎ


그럼 우리가 안한건 

1. 초기에 무슨 옵션으로 초기화 할지를 정하지 않았다... 

2. 다른 인자를 클릭 했을 때 그 값이 현재의 값이 되도록 변화시키지 않았다.. 


두 가지 정도로 생각 할 수 있을 것입니다.


(사진 1-16) 현재 옵션을 결정할 변수추가 


(사진 1-17) 초기화를 해줄 아규먼트 전달

현재 옵션을 결정할 변수를 하나 만들어줍니다. 그리고 그 변수를 Options배열의 0번째 인자로 초기화 해준뒤 InitiallySelectedItem로 전달해 줍니다.


이제 초기화까지 했으니 보이겠지..!!


(사진 1-18) 여전히 안보인다..


여전히 제공된 콘텐츠가 없다고 하네요... 왜 일까 고민을 해보면...


말이 이상하다는 것을 알 수 있습니다. 제공된 "콘텐츠" 가없다. SComboBox에서는 Option이라는 이름을 사용하는데 여기에선 Contents가 없다니 이상합니다.


네 Slate는 처음부터 끝까지 프로그래머가 지정해줘야하죠. 저희는 저 SComboBox안에 무엇을 보여줄지 정하지 않았습니다. 버튼을 눌렀을 때 생성될 위젯은 따로 만들어줬는데 그냥 메인으로 보여질 것이 무엇인지 정하지 않았죠. 그래서 엔진은 "너가 정한 SWidget 이 없어서 나는 보여줄게 없어" 라고 말하는 것입니다.


(사진 1-19) 보..보여랏..!


이제 저희는 현재 옵션을 보여줄 STextBlock을 SComboBox의 콘텐츠로 제공할 것이라는 코드를 넣었습니다.


(사진 1-20) 보.. 보인닷....!


이제 이렇게 하고 컴파일을 하면 드디어 정상적으로 보이는 것을 확인 할 수 있습니다. 


하지만 아직도 다른 인자를 클릭해도 바뀌지않죠..!


이제 마지막으로 다른인자를 클릭해서 바꾸는 것만 하면됩니다.

(사진 1-21) 완성 헤더


(사진 1-22) 완성 몸통


OnSelectionChanged 라는 델리게이트가 인자가 바뀔 때마다 실행될 델리게이트입니다. OnGenrateWidget과 마찬가지의 방법으로 따라가서 사용법을 알아내고 위와 같이 선언하였습니다.


한가지 달라진 점이 보일 것입니다. 바로 STextBlock의 .Text부분이 기존에 변수를 바로 넘기는 것에서 델리게이트 바인딩 형식으로 바뀌었다는 것을 알 수 있을 것입니다.


이것은 단순히 변수로만 넘겨주고 박아버리면 CurrentOption이 아무리 변경된다 하여도 STextBlock은 맨 처음 박아둔 초기값만 가지고 있을 것이나 이것을 델리게이트로 선언하면 CurrentOption 이 바뀔 때마다 정상적으로 값을 표시해 줄 것입니다.


이렇게 한 후 확인해보면!


드디어 모든 것이 정상적으로 작동하는 것을 확인 할 수 있을 것입니다.. !


여기까지가 제가 준비한 DetailCustomization의 마무리 입니다.


어떻게 많은 도움이 되셨는지 모르겠습니다.. ㅠㅠ


저도 아직 많이 부족하므로 설명이 미흡할 수 있습니다. 언제든지 피드백 주시면 반영 하도록 하겠습니다.


여기까지 무사히 따라오셨다면..!! 이제 나도 언리얼엔진 슬레이트 할 줄알아!! 라고 하실수 있지않을까요.. ㅎㅎ


감사합니다.


다음에는 SDockTab에 대해 가볍게 설명한 뒤 날씨 툴 만들기로 찾아오겠습니다.



안녕하세요~ Halcy 입니다.


저번시간에는 디테일 커스텀을 하기전에 필요한 에디터 모듈을 제작하여 추가하는 것 까지 하였습니다!


오늘은 본격적으로 디테일 커스텀을 해볼 예정입니다. 


본 튜토리얼은 언리얼 문서의 디테일 패널 커스터마이징을 기본적으로 따라하며, 거기에 + - 가 있을 예정입니다!


그럼 본격적으로 시작해 보겠습니다.


(사진 1-1) 셋업 절차


언리얼 문서의 디테일 패널 커스터마이징을 보면 가장 먼저 나오는 것이 프로퍼티를 커스터마이징해 넣을 클래스를 생성합니다. ILayoutDetails 를 상속해야 합니다. 라고 합니다. 


그럼 여기서 ILayoutDetails 가 무엇일까요? 

저희가 코딩할때 항상 하듯이 저것이 무슨 역할의 클래스인지를 먼저 찾아보겠습니다. 언리얼 API에서 말이죠!


(사진 1-2) ILayoutDetails 검색결과


두둥..! ILayoutDetails라는 클래스는 존재하지도 않네요...? 접두사로 I가 붙었으니 인터페이스 인것은 알겠는데 언리얼 공식 다큐먼트에서 사용하라고 하는 클래스가 엔진내부에 존재하지조차 않는다...!! 


이것이 과거에 존재 했다가 없어진 것인지... 아니면 처음부터 존재하지 않은 것인지... 저희는 알 길이없습니다.. 하지만 저희는 디테일 탭을 커스텀하고 싶다구요... ! 


그래서 제가 찾아본 결과 그리고 언리얼 엔진 내부를 뜯어본 결과..!


(사진 1-3) StaticMeshComponentDetails.h 파일내부


스태틱 메쉬 컴폰넌트의 디테일탭을 구성하는 헤더파일을 뜯어보니 IDetailCustomization 이라는 클래스를 사용하더군요..! 


네 맞습니다. 이게 과거 언젠가 업데이트에 바뀐 것인지 모르지만 저 다큐먼트에서 말하는 클래스는 ILayoutDetails가 아닌 IDetailCustomization 입니다. 


자! 이제 IDetailCustomization 클래스가 무슨 클래스인지 알아보겠습니다.


(사진 1-4) IDetailCustomization 출처( http://api.unrealengine.com/INT/API/Editor/PropertyEditor/IDetailCustomization/index.html )언리얼엔진 공식문서


언리얼엔진 API에서 찾아보면 위 사진처럼 나옵니다. 위 클래스의 설명을 번역해보면


"특정 클래스에 대한 세부 정보를 배치하는 모든 클래스의 인터페이스"


라고 합니다. 한마디로 특정 클래스의 디테일탭의 배치를 담당하는 클래스 인터페이스 정도로 이해 할 수 있을 것입니다.


또한 이 인터페이스가 가지고있는 함수의 설명을 보면 디테일들을 커스텀 할때 불러야만 하는 함수라고 정의 되어있습니다.


이러한 설명들을 보았을 때 현재 저희가 딱 필요로 하는 클래스라는 것을 알 수 있을 것입니다.


이제 이것을 상속하는 클래스를 하나 만들겠습니다.


(사진 1-5) IDetailCustomization 상속하는 클래스 생성(DetailCustomization)


사진 1-5와 같이 IDetailCustomization 을 상속하는 클래스 DetailCustomization을 생성 하였습니다.


(사진 1-6) IDetailCustomization 헤더파일


헤더파일은 사진 1-4에서 나온 CustomizeDetails 함수를 오버라이드 해줍니다. 저희는 디테일을 커스텀 할것이기 때문에 디테일을 커스텀 할때 쓰라는 함수를 안쓰면 안되겠죠!?


그리고 Static 함수로 공유 레퍼런스(TSaredRef) 로 IDetailCustomization 을 반환하는 MakeInstance함수를 하나 정의 해줍니다. 이것은 추후에 모듈에 추가할때 필요한 부분입니다. 스마트 포인터 또한 Slate 튜토리얼이 끝나고 다룰 수 있으면 다뤄 보겠습니다....


(사진 1-7) IDetailCustomization CPP 파일


그 후 CPP 파일에서는 헤더에서 선언한 함수들을 구현해 줍니다. MakeInstance함수는 이름에서 알 수 있듯이 MakeShareable 매크로를 이용하여 C++의 포인터로 초기화한 해당 클래스를 공유 포인터로 초기화 시켜 반환합니다.


그리고 이제 CustomizeDetails 함수에서 본격적으로 디테일 탭을 커스텀 할 것 입니다.


(사진 1-8) 언리얼 공식문서 출처(http://api.unrealengine.com/KOR/Programming/Slate/DetailsCustomization/ )언리얼엔진 공식문서


언리얼 공식문서에서 Lighting탭을 커스텀하였으므로 저희도 그대로 따라 해보도록 하겠습니다.

아니나 다를까 IDetailCategory 라는 클래스는 없군요...

그래서 제가 또 찾아보았습니다.


(사진 1-9) IDetailCategoryBuilder 출처( 언리얼 공식문서)


찾아보니 IDetailCategoryBuilder 라는 것이 나오더군요. 일단 이름은 비슷해 보이는데 맞는지는 모르겠습니다.


그래서 고민을 하다가 DetailBuilder.EditCategory 의 반환자가 IDetailCategoryBuilder라는 것을 알고 이것이 맞다는 것을 깨달았습니다. 이것 역시 과거 어느 순간에 바뀐것 같군요.. ㅠㅠ


(사진 1-10) DetailCustomization.cpp에 추가


공식문서를 그대로 가져다 쓰면 위의 TEXT("OptionalLocalizedDisplayName")에서 에러가 나더라구요. 그래서 해당 부분을 직접 FText로 변환해주니 에러가 없어졌습니다.


(사진 1-11) 언리얼 공식문서 출처(http://api.unrealengine.com/KOR/Programming/Slate/DetailsCustomization/ )언리얼엔진 공식문서


언리얼 공식문서 튜토리얼을 따라하면서 가장 큰 문제가 되는부분이 여기였습니다. 공식문서 튜토리얼에선 AddProperty 를 저런식으로 사용하였는데..!


(사진 1-12) AddProperty 출처(언리얼공식문서)


네... 보시는 바와 같이 단순 스트링이 두개 들어가는 AddProperty는 없습니다... 그래서 저 형식에 맞추어 만들어 보려했는데 제 역량이 부족하여 만족스러운 결과가 나오지 않아... 저희는 여기서 슬레이트형식으로 만들어 보겠습니다. 그리고... !


(사진 1-13) 프로퍼티를 추가하는 방법 2가지


언리얼 공식문서에서 보면 프로퍼티를 추가하는 방법은 두 가지가 있는데 그 중 AddProperty 를 사용 하는것은 멀티박스 스타일 레이아웃을 사용하는 방법으로, 프로퍼티 재배치에 빠르다고 합니다. 한 마디로 이것은 기존의 만들어둔 프로퍼티를 '재배치' 하는 것 이라고 이해 할 수 있을 것입니다... !!( 저는 그렇게 이해했는데 아닐 수도.. ) 다른 한가지 방법은 Slate 문법을 사용하는 방법으로, 가장 '확실한' 커스터마이징 옵션이 제공됩니다. 라고 하니 저희는 역시 가장 '확실한' 방법으로 커스텀해보겠습니다..! (절대 제가 AddProperty를 사용못해서 그런건 아닙니다...!)


그럼 이제 Slate를 사용해서 프로퍼티를 추가하려면 어떻게 해야하는가..! 에 대하여 알아보도록 하겠습니다.


멀티 박스 스타일은 AddProperty 를 사용 하는데 Slate를 사용하기 위해선 무슨 함수를 써야 하는가 찾아보았습니다.


(사진 1-14) AddCustomRow 출처(언리얼공식문서)


찾아보면 Slate를 사용할 수있는 방법이 2가지 정도 있습니다. 위 AddCustomRow함수를 사용하는 방법과 HeaderContent 함수를 사용 하는 방법입니다. 


두 가지 방법의 차이는 AddCustomRow는 FDetailWidgetRow라는 클래스를 반환하는데 여기에 NameContent라는 함수가 있습니다. 이 함수는 컨텐츠를 이름 슬롯에 배정하는 함수로 이것을 활용하여 Slate를 사용하여 만든 컨텐츠를 슬롯에 배정할 수 있습니다. 


이름 슬롯이란 기본적으로 디테일탭은 SSplitter를 이용하여 두가지 영역으로 구분되어있습니다. 한쪽이 NameSlot 다른쪽이 ValueSlot입니다. NameSlot에 배치하기위해선 NameContent()함수를, ValueSlot에 배치하기위해선 ValueContent()를 이용하면 됩니다.


HeaderCotent 는 직접 SWidget을 상속하는 클래스를 만들어 이것을 통째로 카테고리에 추가 할 수 있는 함수 입니다. 


저희는 현재 매우 큰 Slate판을 만드는 것이 아닌 간단한 수정만 할 것이므로 AddCustomRow를 활용하여 만들어 보도록 하겠습니다.


(사진 1-15) Slate첫 추가


가장 기본적인 STextBlock을 이용하여 MyCustom이라는 스트링을 Lighting 탭에 추가 하여보겠습니다. 사진 1-15처럼 추가 해주시면 됩니다. AddCustomRow의 첫 인자는 저희가 디테일탭에서 검색을 할때 사용할 필터를 입력해주시면 됩니다.


이렇게 작성하시고 컴파일을 하고 확인을 하려 했으나.... 그 어느 디테일 탭의 Lighting탭에도 MyCustom이라는 글자는 없습니다.... 


네 아직 끝난게 아닙니다.


저희는 현재 변경할 디테일탭이 어느 디테일탭인지 정하지 않았습니다..! Lighting디테일 탭은 스켈레톤에도 스태틱 메쉬에도 여러군데에 존재하는데 저희는 그 어떤것인지 정하지 않았죠..!! 


좀 더 컴퓨터 처럼 생각해보자면..! 지금 저희가 만든 FDetailCustomization 이라는 클래스가 어느 타이밍에 만들어지고 어느 타이밍에 작동을 시작하는지 조차 모르겠습니다... !!


이제 모듈을 따로 만든 목적이 나옵니다. 해당 클래스를 모듈에서 작동을 시작시켜야죠!!


(사진 1-16) 저번에 추가한 모듈의 헤더


저번 시간에 추가한 모듈의 헤더에 위와 같이 함수 두개를 오버라이드 해줍니다.


해당 함수는 모듈이 시작할 때와 모듈이 끝날때 실행되는 함수 들입니다. 


디테일 탭을 커스텀 하려면 엔진이 켜질때 한마디로 모듈이 불려와 질때 디테일탭에 관한 함수들도 다 불려와 있어야 엔진이 진짜 디테일탭을 생성할 때 바로바로 불려올 수 있을 것입니다.


(사진 1-17) 모듈 cpp파일


이제 모듈이 시작할 때 우리가 만든 FDetailCustomization 클래스도 같이 불러와있어!! 라는 명령을 지정해야 할 것입니다. 


사진 1-17을 보시면 PropertyModule 이라는 변수를 만들고 그 변수를 LoadModuleChecked로 FPropertyEditorModule인 "PropertyEditor" 모듈을 불러왔나 체크하고 불러왔으면 이것을 PropertyModule에 넣어주도록 되어있습니다.


말이 어려운데 간단히 말하면 FPropertyEditorModule 클래스의 이름이 PropertyEidtor인 모듈이 불려왔냐를 물어보는 것이고 불려 왔다면 변수에 넣어라 입니다.


그 후 PropertyModule에 저희가 만든 클래스의 인스턴스도 지정해줍니다. 그리고 저는 UStaticMeshComponent의 Lighting 탭을 커스텀 할 것이므로 위 처럼 구성하여 주었습니다. 


마찬가지로 모듈에 등록을 했으면 해제도 해주어야겠지요. ShutdownModule에 위와 같이 구성하였습니다.


이제 다된 것 같습니다 !! 다시 실행해보죠!!


..... 역시나 안되죠..? 분명 스태틱메쉬 컴포넌트의 라이팅 탭을 조절하라고 했는데 여전히 그대로일 것입니다... 왜일까요... 고민을 한참 해보다 문득 이 모듈(MyEditorModule)이 로드되는 타이밍의 문제가 아닐까.. 생각했습니다.



(사진 1-18) uproject변경



그리고 Uproject파일에서 모듈 부분의 LoadingPhase 부분을 엔진 초기화 후로 바꾸어주었습니다. 생각해보면 저희가 커스텀한 디테일탭이 엔진 초기화 전에 있었다면, 그 후 다시 엔진은 원래의 상태로 디테일 탭을 다시 재 초기화 할 것입니다. 그러면 저희가 커스텀한 디테일탭은 원래의 것으로 덮어씌워지고 저희가 확인 할 수 없을 것 입니다. 그러므로 디테일탭을 커스텀 하기위해선 엔진 이후에 모듈을 불러와야 합니다..!


그리고 확인해보면...!


(사진 1-19) 좌측은 스켈레톤의 Lighting 탭 우측은 스태틱메쉬컴포넌트의 라이팅탭


위와 같이 저희가 원하던 결과가 나오는 것을 알 수 있습니다..!!


여기까지가 이번시간에 준비한 튜토리얼입니다. 


다쓰고 보니 설명이 조금 복잡한 감이 있지만.... 이해 안가시는 부분은 언제든 알려주시면 최대한 도움드리도록 하겠습니다.. ㅠㅠ


그럼 여기까지 읽어주셔서 감사하고 다음시간엔 Slate 중 하나인 SComboBox 를 사용하여 언리얼 공식문서에 나오는 것과는 조금다르지만 Dynamic과 Static등을 선택할 수 있도록 해보겠습니다!!


감사합니다!





안녕하세요. Halcy 입니다~


오늘은 본격적으로 Slate에 대해 알아보고 언리얼엔진 다큐먼트에서 제공하고 있는 Detail Customization 을 해보겠습니다!


Detail Customization 이란, 언리얼엔진을 사용하면서 많이 보는 어떠한 인스턴스의 디테일 탭을 자신이 필요한 방향으로 커스텀 하는 것입니다. 


(사진 1-1) Static Mesh Component의 기본 Lighting 디테일 탭


바로 위의 사진 과 같은 탭들을 디테일 탭이라고 하는데요. 언리얼엔진 다큐먼트에서 제공하는 예제도 Lighting탭을 수정하므로 저희도 처음으로 Lighting 탭을 수정해 보겠습니다.


언리얼엔진 다큐먼트는 4.9버전을 기준으로 작성되어 있기 때문에 현재와 코드가 조금 다른 부분도 있고, 제가 테스트하며 만들었을 때, 비효율적이라 판단되는 부분은 변형하여 작성하였습니다.


본 튜토리얼의 엔진 버전은 4.21.2 버전입니다.


(사진 1-2) Static Mesh Component의 기본 Lighting 디테일탭 수정 버전


이 튜토리얼에서는 사진 1-1 의 기본 Lighting Detail 을 사진 1-2 의 변형된 Lighting Detail로 변경 해보겠습니다.




[기본 세팅]


언리얼엔진의 가장 큰 특징은 언리얼엔진 자체가 여러개의 크고작은 모듈들이 합쳐져서 이루어져 있다는 것입니다. 


우리가 언리얼엔진의 프로젝트를 만들면 기본적으로 게임 런타임 모듈이 하나 생성되고 대부분의 게임플레이를 이 모듈에서 만들게 됩니다. 


하지만 저희가 하려는 디테일 커스텀은 에디터 타임에서 동작해야 하므로, 프로젝트에 Editor 모듈을 하나 추가해 주셔야 합니다. 



(사진 1-3) 모듈 추가전 클래스 생성


위 사진을 보시면 모듈을 추가하기전 cpp 클래스를 생성 하면 위사진처럼 Runtime 모듈 하나만 있은 것을 확인 할 수 있습니다. 


그러면 이제 모듈을 추가해보도록 하겠습니다.


가장 먼저 프로젝트를 하나 만들고 CPP가 동작하도록 구성 하겠습니다. 




(사진 1-4) 언리얼엔진 기본 프로젝트 구성


템플릿은 어떤것으로 하든 상관없지만, 저는 1인칭 템플릿으로 구성하였습니다. 


엔진에 모듈을 추가 하기 위해선 가장먼저 "ProjectPath/Source/" 에 새로운 모듈이름이 될 폴더 하나를 구성하는 것입니다. 


(사진 1-5) 새로운 에디터 모듈을 위한 폴더 생성


처음 프로젝트를 생성하고 Source에 들어가면 본래 자신의 프로젝트 이름을 가진 폴더 하나와 두개의 Target.cs파일만 있을 것입니다.


여기에 위 사진 1-4 처럼 자신의 새로운 에디터 모듈이 될 폴더하나를 구성해줍니다.


(사진 1-6) MyEditorModule 내부


Private폴더와 Public 폴더 하나를 구성해주고 폴더명과 같은 build.cs파일을 하나 만들어줍니다.

그 후 Private 에는 MyEditorModule.cpp를 만들어주고, Pubilc 에는 MyEditorModule.h를 만들어 줍니다.


(사진 1-7) Private 폴더 내부

(사진 1-8) Public 폴더 내부


이제 프로젝트의 Uproject 파일을 오른쪽 마우스 클릭으로 눌러 Generate visual studio project files를 눌러 비주얼 스튜디오를 재생성 해줍니다. 


그리고 이제 비주얼 스튜디오를 열면 다음과 같이 보일 것입니다.


(사진 1-9) 비주얼 스튜디오 솔루션 탐색기


그리고 이제 파일내부를 구성해 보도록 하겠습니다.


가장먼저 build.cs파일을 구성하도록 하겠습니다. build.cs파일에는 이 모듈에서 사용할 다른 엔진 모듈이나 플러그인 모듈등 다양한 패스설정을 해주는 영역입니다.


(사진 1-10) MyEditorModule.build.cs 파일 내부


위 사진에서 PubilcDependencyModuleNames 안에 저희가 디테일 커스텀을 할때 사용할 3가지 모듈을 더 추가할 것입니다.


처음으로 PropertyEditor 모듈을 추가하여 디테일 탭의 프로퍼티에 접근 가능하도록 만들고 그 디테일 탭의 프로퍼티를 수정하는데 사용할 Slate모듈과 SlateCore모듈을 추가해줍니다.


다음으로 .h파일과 .cpp파일을 구성 할 것인데 현재는 단순히 모듈만 추가 하는 것이므로 내부 구성이 복잡하지 않습니다. 


(사진 1-11) MyEditorModule.h


(사진 1-12) MyEditorModule.cpp


여기 까지 하셨다면 이제 저희만의 모듈이 완성 되었습니다!

IMPLEMENT_MODULE 매크로는 첫 번째 인자에는 이 모듈을 관리할 클래스를 설정하는 것이고, 두 번째 인자는 이 모듈의 이름을 입력해 주시면됩니다. 


저희는 디테일탭을 커스텀하는 모듈을 제작할 예정이므로 .h파일에 class하나를 구성하여 이 클래스를 모듈의 관리자로 지정하였습니다.


그리고 빌드를 하고 다시한번 모듈이 추가가 되었나 확인해봐도 사진 1-3 처럼 아직 하나의 모듈만 나올 것입니다. 


그 이유는 이 프로젝트에서 새로운 모듈을 만들었지만 사용하겠다고 지정을 해주지 않아 발생하는 현상입니다.


이제 이 새로운 모듈을 프로젝트에서 에디터 모듈로 사용하겠다! 지정해보록 하겠습니다.


(사진 1-13) .uproject 파일 내부 


uproject파일 내부에 Modules 항목 내부에 위와 같이 추가해주면 이제 이 모듈을 프로젝트에서 사용하겠다! 입니다.

 

하지만 이대로 컴파일을 해도 오류가 날 수 있습니다. 아마 위에 만든 MyEditorModule.h 파일을 찾을 수 없다는 에러가 날 것입니다. 혹은 컴파일이 완료되고 엔진이 실행하기 직전에 MyEditorModule의 버전이 변경되어 다시 컴파일 하라는데 예를 누르면 실패라고 뜰 것입니다.


이것은 새로운 모듈의 패스가 제대로 잡혀있지 않아서 발생하는 에러입니다. 기본 프로젝트를 생성하면 .target.cs파일이 두개 생성 될 것입니다. 여기에 저희 모듈을 추가해 주셔야 패스설정을 제대로 하고 프로젝트에서 모듈을 제대로 인식 할 수 있을것입니다.


(사진 1-14) Target.cs



(사진 1-15) Editor.Target.cs



(사진 1-16) .Target.cs


위와 같이 모듈 이름을 추가해주고 컴파일을 누르면 이제 모듈이 정상 인식 될 것입니다.


(사진 1-17) 모듈추가 확인


이제 정상적으로 모듈이 추가되었다면 위 사진처럼 나올 것입니다.


오늘은 디테일 커스텀을 하기 위해 가장먼저 해야하는 모듈추가를 해보았습니다. 플러그인으로 만들까도 생각해봤지만, 엔진내부에 있는 디테일 탭을 수정하는것인데 플러그인으로 한다는 것이 조금 껄끄러워서 그냥 에디터 모듈추가로 해보았습니다.


처음 쓰는 튜토리얼이고 글 재주도 워낙에 없어서 잘 이해가지 않은 부분은 언제든 문의주시면 최대한 알려드리도록 노력하겠습니다. ㅎㅎ


다음 시간에는 본격적으로 디테일탭을 커스텀 해보록 하겠습니다! 


다음시간에 만나요 ~


감사합니다. ㅎㅎ


안녕하세요. Halcy 입니다. 


오늘은 드디어 미루고미루고 미뤄왔던 바쁘고 귀찮음을 이기지 못해 계속 밀렸던, UE4 엔진의 Slate를 정리하려 합니다.


본 게시글은 혼자 공부해온 Slate에 대한 정리와 Slate를 처음 접하게 되는 프로그래머 분들에게 작게나마 도움이 되시길 바라며 작성합니다.(저도 많이 부족하므로... 피드백도 환영합니다!!)


Slate Tutorial 그 첫 시간으로 Slate란 무엇인가에 대하여 알아보도록 하겠습니다.



(사진 1-1) 출처 언리얼엔진 공식문서 중 발최 http://api.unrealengine.com/KOR/Programming/Slate/



언리얼 엔진 공식문서에서 정의 중인 슬레이트란, 언리얼의 커스텀 UI 프로그래밍 프레임워크의 이름 이랍니다. 가장 중요한 것은! 에디터 인터페이스의 대부분을 슬레이트로 제작된다는 것이지요. 


엔진을 사용 할 때 가장 많이 접하고 가장많이 볼 수 있는 Contents Browser 부터 시작하여 블루프린트 에디터, 애니메이션 에디터, 머테리얼 에디터 등등 엔진의 대부분을 차지하는 부분이며, 개인적으로 생각하였을 때, 엔진을 커스텀하여 사용할 때 가장 중요한 부분 중 하나라고 생각합니다. 


그래서, 이 좋은 슬레이트로 무엇을 할 수 있을까요. 


할 수 있는 것을 찾아보면 결국 언리얼엔진의 외부에 보이는 대부분의 레이아웃을 다만들었으니, 언리얼엔진도 만들 수 있습니다! 라고 할 수 있을 것같네요. 


인게임 UI제작도 Slate를 사용하여 가능 한 것으로 알고 있으나, 위 사진 1-1 에 써있는 것처럼 인게임 제작용으로는 더욱 적합한 UMG가 있습니다. 


하지만 이 UMG도 뜯고 뜯고 들어가면, Slate가 나온다는 사실! 한 가지 예를 보여드리겠습니다.


(사진 1-2) 출처 언리얼 엔진 내부 코드


위 사진 1-2 는 언리얼엔진 내부의 UMG 버튼인 UButton의 내부를 본 것입니다. 보시는 바와 같이 SButton을 만들고 이것을 캐스팅하여 사용 하는 것을 볼 수 있습니다.


대부분의 UMG가 이렇게 Slate에 구현되어 있는 것을 가지고 사용하는 경우가 많습니다.


슬레이트를 완벽하게 공부하겠어! 모든 것을 만들어보겠어! 라는 마음으로 공부를 했지만, 저도 아직 많이 부족하고 슬레이트가 워낙에 많은 내용이 있기도 해서 이 튜토리얼에서는 크게 5가지정도의 챕터로만 다뤄 보겠습니다. 


첫 번째 챕터로 현재 작성중인 슬레이트란 무엇인가 부터 시작하여 아래 와 같은 순서로 진행 해보겠습니다. 


1. Slate란 무엇인가.


2. Detail Customization


3. SDockTab


4. 날씨툴 만들기


5. 자신만의 툴 만들기


Detail Customization 은 언리얼엔진 공식 문서에서 제공하고 있는 Detail Customization 을 따라하며 슬레이트의 기초에 대해 알아보도록 하겠습니다.


SDockTab은 슬레이트의 부유 탭입니다. Contents Browser를 만든 기능 중 하나이며, 제가 가장 많이 사용하고 좋아하는 슬레이트의 기능 이므로 따로 챕터를 나누어 봤습니다. 


날씨툴 만들기에서 본격적으로 자신만의 툴만들기에 도전해 보겠습니다. 이전에 만들었던 제 날씨툴을 기반으로하여 튜토리얼을 작성할 예정입니다. 


마지막으로 그 동안의 공부했던 슬레이트의 기능들을 모아 또 다른 간단한 툴을 하나 만들어볼 예정입니다. 아직 무엇으로 만들지는 정해지지않았고 튜토리얼을 지속적으로 작성하며 생각해볼 예정입니다.



참고로 제 튜토리얼은 거의 대부분 Plugin으로 진행하겠습니다. Plugin이 들고 다니기도 편하고 저에겐 좀 더 작업하기 익숙 한 느낌이 들어서입니다. ㅎㅎ;



첫 번째 챕터는 이렇게 마무리 하겠습니다~


다음 챕터 부터 본격적으로 달려보겠습니다!



감사합니다!

반갑습니다~ 테스트겸 Happy New Year 입니다.



+ Recent posts