{{ label!='' ? 'Label : ' : (q!='' ? '검색 : ' : '전체 게시글') }} {{ label }} {{ q }} {{ ('('+(pubs|date:'yyyy-MM')+')') }}

[Unreal Engine] 상호작용 하이라이트 구현

이미지
상호작용 하이라이트 상호작용이 가능한 버튼이 강조되고 있습니다.    Phil in the Mirror는 1인칭 게임으로, 각종 물체와 상호작용할 수 있는데요. 플레이어가 특정 물체와 상호작용할 수 있는 상태임을 알리기 위해, 해당 물체를 바라보면 물체가 강조되는 연출이 필요했습니다. 이는 다양한 방법으로 구현될 수 있는데, 제가 구현한 방법을 말씀 드리려고 합니다. 무슨 방법으로 구현할 수 있을까요?   특히, 저는 강조될 때 각 물체가 자연스럽게 fade-in, fade-out되는 효과를 원했습니다. 여러 개가 동시에 강조될 수도 있고, 마우스가 스치는 시점에 따라서 각자가 서로 다른 주기로 fade-in, fade-out이 되었으면 했죠. 이런 효과를 구현하기 위해서는 크게 두 가지 방법으로 구현할 수 있을 것 같습니다: 마스터 머티리얼 이용하기   모든 상호작용 가능한 물체는 마스터 머티리얼을 사용하고, 해당 머티리얼에서는 머티리얼 파라미터를 통해 강조의 정도를 조절할 수 있게 만드는 것입니다. 만약 Interactable한 객체가 앞에 있다면, 해당 객체의 머티리얼 파라미터를 0에서 1로 점진적으로 조절하는 것이죠. 제가 구현한 방법은 이것이 아니기 때문에, 자세한 코드 내용을 담기는 어렵습니다만 아마 다음과 같은 형태로 이루어질 것입니다: APlayerCharacter::CheckHighlight() { if (CanInteract() == false) { return ; } AActor* InteractableActor = GetInteractableActor(); ... InteractableActorDynamicMaterial ->SetScalarParameterValue(FName( "HighlightIntensity" ), FadeValue); }   그리고 마스터 머티리얼에서는 HighlightIntensity를 가...

[Unreal Engine] AI 기반 10개국어 현지화 사례

이미지
번역을 맡길 돈이 없어요!  Phil in the Mirror는 7000+ 단어의 텍스트 분량을 가진 게임이었는데요. AI를 기반으로 한국어를 포함한 10개국어의 번역을 목표로 했습니다. 특히, 서사 기반의 퍼즐 게임이었던 만큼 번역 검수에는 신경을 많이 썼던 것 같습니다. 은유적인 표현들로 퍼즐들이 구성되기도 했기 때문에, 약간의 뉘앙스 차이만으로도 퍼즐의 난이도가 완전히 달라질 염려가 있었기 때문입니다.   언리얼 엔진에서는 프로젝트의 텍스트들을 수집하여 *.po 파일로 export하는 것을 지원합니다. po 파일의 구성은 대략적으로 다음과 같은 항목들의 나열입니다: #. Key: Content_Init_030 #. SourceLocation: /Game/StringTable/ST_Computer.ST_Computer #: /Game/StringTable/ST_Computer.ST_Computer msgctxt "ST_Computer,Content_Init_030" msgid "모듈 로딩 중: 입원, 진단, 청구..." msgstr ""   msgctxt의 경우 언리얼 엔진에서 StringTable의 namespace이고, msgid는 원어, msgstr은 번역본이 됩니다. 구조 자체는 굉장히 단순하므로, 사실 이것만으로도 충분히 CLI 기반 AI가 번역할 수 있다고 생각했습니다. msgstr의 내용을 채우라고 시키는 것이죠. Gemini CLI를 이용하여 번역을 시도했습니다. 결과는 쓸만하긴 했으나 여러 문제들이 있었습니다. 문장부호 처리   po 파일은 msgctxt, msgid, msgstr와 같은 key가 있고, 그 뒤에 큰따옴표와 함께 내용이 나오는 구조를 갖고 있습니다. 만약 번역 내용 안에 큰따옴표가 있다면, \"와 같은 형태로 작성해야 합니다. 문제는 AI가 이런 형태에서 잦은 실수를 한다는 것이었습니다. 파일의 구조를 무시하고 큰따옴표 없이 번역을 수행한다든가, \...

[Unreal Engine] 오디오 시각화를 이용한 대화 연출

이미지
   Phil in the Mirror에서는 전화를 통해 대화하는 장면들이 있는데요. 규모가 작아 더빙을 할 수도 없는데 단순히 대사만 떠있는 것이 조금 허전해, 목소리가 들리는 느낌을 연출하고자 소리의 시각화를 함께 해주면 좋을 것 같다는 생각을 했습니다. 다음처럼요: 가운데의 원형 표시는 음성이 시각화되어 보여집니다.   이를 수행하기 위해서, 다음과 같은 작업들이 필요했습니다: 음성 데이터가 필요합니다. 음성 데이터를 시간에 따라 분석하여, 각 주파수 영역의 크기가 어느정도 되는지 알아야 합니다. 이렇게 분석된 크기를 텍스처로 구성하여 머티리얼 파라미터로 전달해야 합니다. 머티리얼은 해당 파라미터를 기반으로 시각화를 하여 유저에게 보여줍니다. 음성 데이터   상술하였듯, 이 게임에는 더빙 등을 하지 않았기 때문에 직접적으로 활용할 수 있는 음성 데이터는 없었습니다. 처음에는 대사 자체를 분석해서 절차적인 정보를 얻어낼 수 있는 방법이 있을까 고민하였으나, 소 잡는 칼을 쓰는 느낌이 들어 다른 방법을 고민하기로 했습니다. 여기서 필요한 음성은 플레이어가 들을 수 있는 것이 아니었기 때문에, 단순히 무료 TTS 서비스를 이용하여 대사들을 말하는 음성들을 얻어내 활용하기로 하였습니다.    이렇게 얻은 TTS 음원을 사용하기 위해서는 분석이 필요한데요. 푸리에 변환을 통해 각 음역대의 진폭을 얻은 뒤 이들을 이용해서 그려내야 할 것입니다. 이는 언리얼 엔진에서 제공하는 AudioSynesthesia 플러그인을 활용하기로 했습니다. 해당 플러그인에서는 ConstantQNRT 에셋 등을 지원하며, 이를 통해서 음원의 특정 시간에서 각 주파수 영역의 크기가 어느정도인지 분석할 수 있습니다.   따라서 다음과 같은 에디터 스크립트를 작성하여 주어진 TTS 음원들을 자동으로 ConstantQNRT 에셋으로 생성하도록 하였습니다: import unreal def safe_update_or_create_nr...

[Unreal Engine] Custom Slate Widget 도입 사례

이미지
Custom Slate Widget   Phil in the Mirror에서는 언리얼 엔진 5에서 기본적으로 제공하지 않는 UI 요소 몇몇가지가 필요했는데요. 그러한 요소들을 어떻게 만들어서 해결했는지에 대해서 기술해볼까 합니다. 단순히 유저 위젯 블루프린트를 이용한 에디터 수준에서 해결할 수도 있었지만 코드 수준에서 이들을 적절히 구현해서, 유연함과 성능적 이점 및 사용성을 챙긴 사례를 공유합니다. 1) Redact Decorator   Phil in the Mirror에서 플레이어는 다양한 문서들을 읽고 사건들의 관계를 파악하여 숨겨진 날짜들을 추리해야 합니다. 따라서 중요한 정보들은 가려놓고, 이들을 추리할 수 있게 해야 했습니다. 다만 여기서 고려되어야 할 사항이 있었는데요. 바로 로컬라이제이션입니다. 텍스트 상에서 가려질 부분들은 어떤 언어이느냐에 따라서 위치가 달라지고, 길이도 달라지게 됩니다. 이를 자연스럽게 해결할 필요가 있었습니다. 텍스트의 일부가 검정색으로 가려져 있습니다.   단순히 U+2588(█) 문자를 이용할 수도 있었지만, 다음과 같은 문제가 있었습니다: 1) 언어마다 글자의 개수가 상이한데, 정말로 문맥 상의 단어가 자연스럽게 가려지는 느낌을 연출하기 어려웠습니다. 가령 "손가락 절단 사고"와 "finger amputation accident"는 글자수의 차이가 커서, 어느 한쪽 언어에서 어색하게 보이는 측면이 있습니다. 2) 사이에 공백이 없이 이어지는 느낌이 필요했습니다. (███처럼 이어서 써보면 사이에 애매한 공백이 보입니다)   따라서 텍스트가 렌더링될 때, 해당 영역 위에 검정색 박스를 그려낼 필요가 있었습니다. 이는 RichTextBlock의 기능을 확장하여 구현할 수 있었습니다. 정확히는, Decorator를 만드는 것이죠. RichTextBlock은 Decorator를 추가할 수 있는데, 이러한 Decorator들은 RichTextBlock의 내용에 접근하여 본인이 꾸밀 수 있는 ...