
언리얼엔진 교육과정을 마치고 현장실습을 위해 기업에 출근한 지 이틀차. 바쁘게 돌아가는 사내 분위기 속에 함께 실습을 온 우리는 각자 공부를 하고 있었다.
그러다 담당자님께서 회사에서 진행하고 있는 한 프로젝트를 유니티에서 언리얼로 바꾸는 작업을 부탁하셨다.
자연어처리(NLP) 기반으로 대화하는 인공지능 캐릭터를 제작하려고 하는데, 반실사 렌더링을 통해 현실적인 아바타를 만들 필요성이 있다고 설명하셨다.
192.168.0.XXX:XXXX/TTS?text="안녕?"
위와 같이 브라우저에 URL을 작성하고 접속하면 로컬 서버에서 TTS로 "안녕?"을 음성파일(.wav)로 변환해주었다. 우선 이를 언리얼로 불러올 수 있도록 요구하셨다.
추후 텍스트는 NLP API를 통해 생성할 수 있도록 만들 예정으로, 우선은 언리얼이 특정 이벤트가 발생 시 TTS 서버에서 원하는 문장을 음성으로 재생할 수 있도록 구현해야 했다.
이는 금방 구현할 수 있었다. 언리얼 내에 미디어 소스를 사용하고 재생할 수 있는 기능이 있었다.
[Unreal Engine: Stream Media Source] 기술문서
위의 문서는 영상을 기반으로 만든 것이고, 우리는 음성만 출력하면 되는 상황.
UI와 머터리얼 없이 미디어 사운드 컴포넌트 추가와 소스 열기를 하면 그만이었다.

문제는...
언리얼 엔진의 스트링 URL은 한국어가 포함된 문자열을 사용할 수 없다.
192.168.0.XXX:XXXX/TTS?text="안녕?"
위의 URL을 복사해서 붙여넣기를 하면 다음과 같이 변환된다.
192.168.0.XXX:XXXX/TTS?text=%22%EC%95%88%EB%85%95?%22
퍼센트 인코딩 : 위키백과
URL에 문자를 표현하는 문자 인코딩 방식인 퍼센트 코딩으로, 알파벳이나 숫자 등 몇몇 문자를 제외한 값은 옥텟 단위로 묶어서 16진수 값으로 인코딩한다. 한글도 이에 포함된다.
퍼센트 인코딩 된 URL로 접속하면 언리얼에서도 정상적으로 "안녕?" TTS가 재생되는 것을 확인하고, 언리얼에서 C++로 URL 인코딩만 구현하면 이 문제를 해결할 수 있었다.
URL 인코딩 C++ 코드를 언리얼 C++에 맞게 고쳤다.
코드 출처 : https://typemild.blogspot.com/2015/05/c-url.html
언리얼 환경에서 PlayerCharacter의 부모 클래스로 존재하는 C++ 클래스 ATtsTestCharacter.h의 코드는 다음과 같다.
/** Encode Url UTF-8 as percent encoding */
UFUNCTION(BlueprintCallable, BlueprintPure, Category = AI)
FString UrlEncode(FString input);
다음은 위 함수 선언을 리팩토링 후 ATtsTestCharacter.cpp에 작성한 코드다.
FString ATtsTestCharacter::UrlEncode(FString input)
{
const std::string unreserved = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.~";
std::string strInput = TCHAR_TO_UTF8(*input);
std::string escaped="";
for(size_t i=0; i<strInput.length(); i++)
{
if (unreserved.find_first_of(strInput[i]) != std::string::npos)
{
escaped.push_back(strInput[i]);
}
else
{
escaped.append("%");
char buf[3];
// char -> unsigned char
sprintf(buf, "%.2X", (unsigned char) strInput[i]);
escaped.append(buf);
}
}
return *FString(escaped.c_str());
}

TTS로 출력할 문자열을 Url Encode 함수를 통해 퍼센트 인코딩을 진행한 후, 이를 로컬 서버 주소와 연결하면 정상적으로 한국어 TTS가 언리얼엔진에서 재생된다.