Прямые ответы о размере билда, шрифтах, атласе глифов и производительности в рантайме — собранные из реальных вопросов разработчиков.
Нет. UniText не запекает текстурные атласы под каждый шрифт в билд. Глифы растеризуются в рантайме в общий атлас (на базе Texture2DArray) с подсчётом ссылок на каждый глиф и вытеснением по LRU. В билд попадают только данные шрифта — атласы никогда. Вдобавок встроенное сжатие шрифтов (Zstd, уровень 22) уменьшает данные шрифта до ~2.7× для латиницы и арабского (для CJK скромнее, ~1.3×).
Нет. Ассет UniTextFont встраивает байты шрифта внутрь себя. Ссылка на исходный шрифт существует только в редакторе (обёрнута в #if UNITY_EDITOR) — в сборке плеера её попросту нет, поэтому это не рантайм-зависимость и она не попадёт в AssetBundle через разрешение зависимостей. Файл .ttf можно удалить сразу после создания ассета.
Нет. UniTextFont можно собрать из .ttf, лежащего в любом месте на диске, через окно инструментов UniText (диалог выбора файла читает байты напрямую). Импорт шрифта в проект — опционален.
• WebGL: пустой билд занимает ≈ 6–10 MB (зависит от версии Unity и установленных пакетов); UniText добавляет свои нативные библиотеки (HarfBuzz, FreeType). Это те же индустриально-стандартные библиотеки, что поставляет собственный Advanced Text Generator из UI Toolkit в Unity — ничего экзотического (UniText просто везёт собственные копии). • Android: APK с двумя архитектурами несёт обе — примерно +4 MB на архитектуру. Но при публикации AAB Google Play доставляет бандл под конкретное устройство, поэтому пользователь скачивает только свою архитектуру (~4 MB), а не обе.
У TMP в режиме Static (заполнение атласа) запекание полного набора глифов типичного CJK-шрифта раздувает билд на десятки-сотни MB (несколько атласов 4096²/8192²; ожидайте ~80–250 MB в зависимости от количества глифов и разрешения). Ключевой момент: накладные расходы UniText не растут с количеством глифов — это те же несколько MB, поставляете ли вы латиницу или полный CJK.
Да — это на стороне разработчика, и UniText не мешает. Скачайте байты шрифта своим кодом (UnityWebRequest) и соберите из них UniTextFont в рантайме через CreateFontAsset(byte[]). Чтобы урезать шрифт до нужных вам символов (сабсеттинг), используйте инструмент UniText на этапе сборки. Встроенного автозагрузчика с CDN в пакете нет — это намеренно ответственность проекта, а не движка.
Да — SystemFont читает файл шрифта напрямую из ОС в рантайме, поэтому на размер билда это никак не влияет (ничего не запекается). Разрешение шрифта ленивое (при первом использовании), поэтому запуск приложения не замедляется.
Глифы живут в плитках трёх размеров — 64, 128, 256 — и размер выбирается по сложности контура (много сегментов → 128/256, простой контур → 64). • SDF Detail — это множитель для оценки сложности. Поднимите его — и уже нетривиальный глиф с большей вероятностью перейдёт на плитку побольше. (По-настоящему простая форма остаётся на 64 — множитель влияет только на глифы выше порога.) • Tile Size Offset — это жёсткий шаг по лестнице размеров (выбрано 64 + смещение 1 → 128; диапазон −2..+2).
Ни один по отдельности — оба лишь определяют итоговый размер плитки, а стоимость задаётся только этим размером. Две комбинации, дающие один и тот же размер плитки, стоят ровно одинаково. Стремитесь к наименьшему размеру плитки, который всё ещё даёт приемлемое качество.
Только когда глифа ещё нет в атласе — никогда не каждый кадр. Для «Hello world» он растеризует уникальные глифы H e l o w r d. Второй H не делает ничего; a растеризует только a.
Стоимость пропорциональна числу уникальных, впервые встреченных глифов, растеризованных в этом кадре — а не длине текста. В нашем бенчмарке ~2000 уникальных глифов на первом кадре — это ≈ 1 секунда на типичном Android-устройстве; TMP и UI Toolkit в том же сценарии тратят 10+ секунд. Повторное использование закешированных глифов бесплатно.
UniText почти не полагается на Unity Job System на горячем пути — и это осознанно. Растеризация глифов (наши собственные lpSDF / lpMSDF) по умолчанию идёт на GPU через compute-шейдер; Burst-задачи — это лишь резервный путь на CPU, когда compute недоступен. Основная многопоточность — шейпинг, вёрстка, генерация меша — работает на собственном пуле OS-потоков UniText (не на Unity Jobs, поэтому они и не видны в профайлере Jobs). Так что «нет задачи UniText» не значит «потоки выключены»: либо работа ушла на GPU, либо атлас уже прогрет, либо текст ниже порога параллелизма (короткие или одиночные надписи обрабатываются последовательно — так дешевле).
«Update() медленный» — это миф для релизных билдов. Накладные расходы на вызов magic-метода из нативного кода реальны, но пренебрежимо малы (~1000 вызовов ≈ 0.16 ms) — это не узкое место. Настоящая цена в наивном коде — это раскладка памяти AoS, а не сам колбэк; UniText применяет SoA там, где это важно (атрибуты Unicode, метрики, буферы на каждый пиксель). (Именно поэтому ECS быстр — из-за SoA, а не «магии ECS».) И UniText в любом случае централизован — просто не как MonoBehaviour-менеджер: сам Update() почти пуст, а тяжёлая работа собирается в один пакетный проход на колбэках рендера Canvas (что заодно даёт параллелизм между компонентами).
Спросите в нашем Discord — именно такие вопросы и сформировали эту страницу, и мы обычно отвечаем быстро.