UniText 는 TextMeshPro 가 못 그리는 글을 그리고, 그 대신 잃은 것이 있다
label.text = "I said مرحبا to him"; // 영어 문장 가운데에 아랍어 단어 하나
이 한 줄을 TextMeshPro 에 넣으면 아랍어 글자가 서로 떨어진 낱자로 나오고 순서도 뒤집힙니다. UniText 에 넣으면 제대로 나옵니다.
그렇다고 UniText 가 TextMeshPro 를 그대로 대신하는 물건은 아닙니다. UniText 는 TextMeshPro 가 구조상 못 하는 일을 풀었고, 그 대신 TextMeshPro 에서는 신경 쓰지 않아도 되던 것을 떠안았습니다. 무엇을 잃는지는 무료판과 유료판이 크게 다릅니다.
UniText 는 판이 둘이다
비교하기 전에 어느 UniText 인지부터 정해야 합니다. 공식 사이트는 둘을 “관련은 있지만 다른 제품” 이라고 적습니다.
| 무료판 | 유료판 (Folio) | |
|---|---|---|
| 버전 | 1.0.0 | 2.x, 3.x (2026년 9월 기준 3.12.1) |
| 라이선스 | MIT | 회사 매출 구간별 영구 라이선스 |
| 들어 있는 것 | 셰이핑, 양방향, 줄바꿈, SDF 굽기, 이모지, 태그 | 무료판에 더해 입력과 선택, 월드 공간 텍스트, 드롭다운, MSDF, 가변 폰트, 효과, 폰트 압축, TextMeshPro 이전 도구 |
| 갱신 | 1.0.0 에서 멈춤 | 거의 매주 새 버전 |
이 시리즈가 소스를 읽은 것은 무료판 1.0.0 입니다. 공식 사이트의 비교표와 측정값은 유료판 3.x 기준입니다.
얻은 것 1. 앞뒤 글자를 보고 글리프를 고른다
TextMeshPro 도 폰트의 규칙을 조금은 씁니다. 폰트 에셋을 만들 때 뽑아 둔 표를 찾아보는 방식입니다.
// TextMeshProUGUI.cs: 글리프 하나를 열쇠로 표를 찾는다
if (ligature && m_currentFontAsset.fontFeatureTable.m_LigatureSubstitutionRecordLookup
.TryGetValue(character.glyphIndex, out List<LigatureSubstitutionRecord> records))
{
// 합자: 이 글리프로 시작하는 묶음이 있으면 글리프 하나로 바꾼다
}
if (m_currentFontAsset.m_FontFeatureTable.m_GlyphPairAdjustmentRecordLookup
.TryGetValue(key, out adjustmentPair))
{
// 커닝: 이 글리프 쌍의 간격을 조정한다
}
표는 넷입니다. 합자, 글리프 쌍 간격(커닝), 기준 글자에 기호 붙이기, 기호에 기호 붙이기입니다. 모두 “이 글리프(또는 이 쌍)가 나오면 이렇게 한다” 는 조회입니다.
없는 것은 앞뒤 글자에 따라 글리프 자체를 바꾸는 일입니다. 아랍어 글자는 단어의 처음, 가운데, 끝, 단독일 때 모양이 다른데, 그것을 고르는 코드가 TextMeshPro 소스에 없습니다. 힌디어처럼 글자의 화면 순서를 바꾸는 일도 없습니다.
UniText 는 이 일을 HarfBuzz 에 맡깁니다. HarfBuzz 는 폰트 안의 규칙 표(GSUB, GPOS) 전체를 문자 체계에 맞는 순서로 실행합니다.
| TextMeshPro | UniText | |
|---|---|---|
| 기본 | 코드포인트 하나에 글리프 하나 | HarfBuzz 가 정함 |
| 합자, 커닝, 기호 붙이기 | 에셋에 뽑아 둔 표 조회 | 폰트의 규칙 표 전체 실행 |
| 아랍 문자의 이어 쓰기 | 플러그인이 필요 | 됨 |
| 히브리 문자 | 플러그인이 필요 | 됨 |
| 복잡한 OpenType 셰이핑 | 기본 수준 | HarfBuzz |
| 유니코드 버전 | 14.0 | 17.0 |
공식 사이트는 TextMeshPro 쪽 칸에 이렇게 주석을 답니다. 양방향과 복잡한 문자 체계는 바깥 구현이 있어야 하고, 오른쪽에서 왼쪽 플래그 하나로는 그 알고리즘이 생기지 않는다는 것입니다.
얻은 것 2. 한 줄에 방향이 섞여도 된다
TextMeshPro 의 방향은 불리언 하나입니다.
// TMP_Text.cs
public bool isRightToLeftText
{
get { return m_isRightToLeft; }
set { if (m_isRightToLeft == value) return; m_isRightToLeft = value; ... }
}
protected bool m_isRightToLeft = false;
텍스트를 보고 정하는 값이 아니라 사용자가 켜는 값이고, 컴포넌트 전체에 걸립니다. 전체가 왼쪽에서 오른쪽이거나 전체가 오른쪽에서 왼쪽입니다. 맨 위 문장처럼 둘이 섞이면 켜도 꺼도 한쪽이 틀립니다.
UniText 는 유니코드 양방향 알고리즘(UAX #9)을 C# 으로 구현했습니다(BidiEngine.cs, 2,302줄). 글자마다 방향을 판정하고, 방향이 없는 공백과 구두점은 주변을 보고 정하고, 아랍어 문장 안의 숫자는 왼쪽에서 오른쪽으로 남깁니다.
| TextMeshPro | UniText | |
|---|---|---|
| 방향을 정하는 쪽 | 사용자가 켜는 불리언 | 텍스트를 보고 자동 판정 (강제도 가능) |
| 단위 | 컴포넌트 전체 | 글자마다 |
| 섞인 방향 | 표현할 수 없음 | 가능 |
| 유니코드 시험 파일 | 해당 없음 | 양방향 시험 91,707줄 통과 |
얻은 것 1 과 2 가 UniText 를 쓰는 이유의 중심입니다. 아랍어, 히브리어, 힌디어, 섞인 방향이 필요하면 TextMeshPro 만으로는 길이 없고, 문자열을 미리 바꿔 넣어 주는 플러그인을 붙여야 합니다.
얻은 것 3. 바뀐 층만 다시 돈다
TextMeshPro 는 글자를 도는 루프 하나가 폰트 조회, 커닝, 줄바꿈, 정렬, 정점 생성을 한꺼번에 합니다. TextMeshProUGUI.GenerateTextMesh 한 메서드가 약 2,900줄입니다. 무엇이 바뀌든 이 메서드가 처음부터 다시 돕니다.
UniText 는 같은 일을 단계로 나눴고, 결과를 세 층으로 따로 붙잡아 둡니다.
| 바꾼 것 | TextMeshPro | UniText |
|---|---|---|
| 텍스트 | 전부 다시 | 전부 다시 |
| 폰트 크기 | 전부 다시 | 줄나누기부터 다시. 셰이핑은 그대로 |
| 정렬 | 전부 다시 | 배치만 다시 |
단계가 나뉘어 있어서 여러 컴포넌트를 워커 스레드에 나눠 줄 수도 있습니다. TextMeshPro 의 텍스트 처리에는 스레드를 쓰는 코드가 없습니다. 다만 UniText 의 병렬은 조건이 까다로워 보통의 UI 에서는 대부분 메인 스레드에서 돕니다.
얻은 것 4. 폰트와 이모지를 덜 싣는다
| TextMeshPro | UniText | |
|---|---|---|
| 이모지 | 스프라이트 에셋이나 이모지 폰트 에셋을 만들어 등록 | 기기의 OS 에 깔린 이모지 폰트를 찾아 씀 |
| 이어 붙인 이모지 (가족, 피부색, 국기) | 스프라이트 치환으로는 일반적인 처리가 안 됨 | 묶음 전체를 한 글자로 판정 |
| 없는 글자의 폴백 | 제한적 | OS 폰트로 자동 폴백 |
| 빌드에 넣는 폰트 크기 | 그대로 | 압축해서 넣음 (12 MB 가 4.4 MB) |
사이트에 실린 사례 하나는 프로젝트를 이틀에 옮기고 폰트를 하나도 더하지 않은 채 11개 언어를 늘렸다고 적습니다. 기기의 OS 폰트로 폴백하기 때문에 가능한 일입니다.
공식 사이트가 내세우는 속도
공식 사이트는 TextMeshPro 와 견준 측정값을 싣습니다.
| 항목 | UniText | TextMeshPro |
|---|---|---|
| 오브젝트 생성 | 166 ms | 572 ms |
| 전체 재구성 | 136 ms | 398 ms |
| 레이아웃 | 71 ms | 1,468 ms |
| 메시 재구성 | 60 ms | 424 ms |
| 생성 중 GC 횟수 | 3 | 147 |
| 생성 중 할당 | 292 MB | 2,249 MB |
| 동작 한 번의 할당 | 90 KB | 13.8 MB |
이 숫자는 조건을 같이 읽어야 합니다.
- 안드로이드 출하 빌드에서, 오브젝트 100개에 오브젝트마다 약 2,300자를 넣은 값입니다.
- 텍스트는 라틴, 아랍어, 히브리어를 섞은 것입니다. TextMeshPro 가 제대로 그리지 못하는 글이라, 두 엔진이 같은 일을 한 비교가 아닙니다.
- 기기와 유니티 버전은 적혀 있지 않습니다.
- 유료판 3.x 의 값입니다.
한국어와 영어만 쓰는 화면에서 어느 쪽이 빠른지는 이 표로 알 수 없습니다. 이 시리즈에서도 두 엔진을 같은 조건으로 재지 않았습니다.
잃은 것 1. 입력, 3D 텍스트, 드롭다운
TextMeshPro 는 텍스트 컴포넌트만이 아닙니다. TMP_InputField, TMP_Dropdown 이 함께 오고, 캔버스 밖 월드 공간용 TextMeshPro 컴포넌트도 있습니다.
| TextMeshPro | UniText 무료판 | UniText 유료판 | |
|---|---|---|---|
| 입력 필드 | TMP_InputField |
없음 | 있음 (3.0 부터) |
| 월드 공간 텍스트 | TextMeshPro |
없음 | UniTextWorld |
| 드롭다운 | TMP_Dropdown |
없음 | UniTextDropdown (3.8.0 부터) |
| TextMeshPro 에서 옮기는 도구 | 해당 없음 | 없음 | 있음 |
무료판에는 표시용 컴포넌트 UniText 하나뿐입니다. 클릭 위치를 알려 주는 이벤트와 선택 영역을 칠하는 코드는 있지만 입력 필드 컴포넌트는 없습니다. 무료판으로 닉네임 입력이나 채팅 입력창을 만들려면 직접 짜거나 TextMeshPro 를 함께 써야 합니다.
유료판은 이 자리를 채웠고, 사이트는 오히려 입력 쪽을 강점으로 내세웁니다. 오른쪽에서 왼쪽 글의 캐럿과 선택, 실행 취소, 서식을 보면서 편집하기 같은 것들입니다.
잃은 것 2. 미리 구운 아틀라스가 없다
TextMeshPro 의 폰트 에셋은 글리프를 구운 아틀라스를 에셋에 저장해 둘 수 있습니다(AtlasPopulationMode.Static). 빌드에 픽셀이 들어 있어서 첫 프레임에 굽는 일이 없습니다.
UniText 의 아틀라스는 저장되지 않습니다. 공식 문서도 글리프 아틀라스는 런타임에 만든다고 적습니다. 글리프는 화면에 처음 나오는 순간에 구워져 GPU 로 올라갑니다. 빌드는 작아지지만, 새 글자가 한꺼번에 처음 나오는 프레임에 굽는 비용이 몰립니다. 한글처럼 글자 수가 많은 언어에서 더 두드러집니다.
잃은 것 3. 태그가 기본으로 켜져 있지 않다
TextMeshPro 는 <b>, <color>, <size> 같은 태그를 처음부터 읽습니다.
UniText 에는 기본으로 켜진 태그가 없습니다. 규칙과 모디파이어를 등록해야 읽히고, 등록하지 않으면 <b>world</b> 가 글자 그대로 나옵니다. TextMeshPro 에서 옮길 때 가장 먼저 걸리는 자리입니다.
유료판은 TextMeshPro 에 있던 태그 몇 가지를 태그가 아닌 다른 방식으로 바꿨습니다. 외곽선과 그림자는 태그가 아니라 텍스트 전체에 거는 스타일이고, <alpha> 는 TextMeshPro 와 동작이 달라 이전 도구가 경고를 냅니다.
잃은 것 4. 네이티브 바이너리가 따라온다
TextMeshPro 는 전부 C# 입니다. 유니티가 도는 곳이면 돕니다.
UniText 는 HarfBuzz, FreeType, Blend2D 를 묶은 네이티브 라이브러리가 플랫폼마다 따로 들어 있습니다. 무료판은 하나의 크기가 2 ~ 5 MB 입니다(Android arm64 가 약 2.4 MB).
| TextMeshPro | UniText | |
|---|---|---|
| 지원 플랫폼 | 유니티가 도는 모든 곳 | Windows, macOS, Linux, Android, iOS, tvOS, WebGL (유료판은 UWP 와 visionOS 도) |
| 콘솔 | 됨 | 목록에 없음 |
| WebGL | 다른 플랫폼과 같음 | OS 폰트에 접근할 수 없어 폰트를 직접 넣어야 하고, 컬러 이모지 폰트를 굽지 못함 |
| 문제를 들여다볼 때 | C# 디버거 | 네이티브 쪽은 C# 디버거로 볼 수 없음 |
잃은 것 5. 어느 기기에서나 같은 이모지
UniText 는 기기의 OS 에 깔린 이모지 폰트를 빌려 씁니다. 빌드는 작아지지만, 기기마다 깔린 폰트가 달라 이모지 모양이 기기마다 다릅니다. TextMeshPro 는 이모지 그림을 직접 등록해 빌드에 넣으므로 어느 기기에서나 같은 그림이 나옵니다.
| TextMeshPro | UniText | |
|---|---|---|
| 이모지 모양 | 등록한 그림이라 어느 기기에서나 같음 | 기기의 OS 폰트라 기기마다 다름 |
| 이모지가 안 나올 가능성 | 등록했으면 나옴 | 기기에서 이모지 폰트를 못 찾으면 통째로 안 나옴 |
바뀌지 않은 것
uGUI 에 붙는 방식은 거의 같습니다. 무료판 소스로 확인한 것입니다.
- 둘 다
MaskableGraphic을 상속합니다. - 둘 다
OnPopulateMesh를 쓰지 않고CanvasRenderer에 메시를 직접 넘깁니다. - 둘 다 폰트가 여럿이면 숨은 자식 오브젝트를 만들어 나눠 그립니다.
Graphic 하나가 CanvasRenderer 하나와 머티리얼 하나를 전제하기 때문에, 두 엔진이 같은 제약에서 같은 답에 닿았습니다. 그래서 캔버스 배칭, 마스크, 레이아웃 그룹 안에서의 동작은 TextMeshPro 를 쓰던 감각 그대로 다뤄도 됩니다.
정리
UniText 는 TextMeshPro 가 구조상 못 하는 문맥 셰이핑과 양방향 처리를 얻고, TextMeshPro 에서는 신경 쓰지 않아도 되던 것을 떠안은 엔진입니다.
- 얻은 것은 앞뒤 글자를 본 글리프 선택, 섞인 방향, 바뀐 층만 다시 도는 캐시, 덜 싣는 폰트와 이모지입니다.
- 잃은 것은 미리 구운 아틀라스, 기본으로 켜진 태그, 순수 C# 이라는 단순함, 기기마다 같은 이모지입니다.
- 입력 필드, 월드 공간 텍스트, 드롭다운은 무료판에만 없고 유료판에는 있습니다.
- 공식 사이트의 속도 비교는 TextMeshPro 가 제대로 그리지 못하는 섞인 글로 잰 값입니다.