Chinese, Japanese and Korean Text in Unity Without Huge Font Files

Last reviewed

Short answer

Chinese, Japanese and Korean fonts contain tens of thousands of glyphs, so in TextMesh Pro they either fill large static atlases or ship the source font for dynamic atlases, often once per language. The same code points also need different glyph shapes for Chinese, Japanese and Korean, and TextMesh Pro picks glyphs by code point only, not by language.

On desktop and mobile UniText renders CJK from the operating system's fonts, so the build carries no CJK font and no baked atlas. When you do ship a font, it is compressed, can be subset, and is read from disk on demand, and the text's language selects the right Chinese, Japanese or Korean glyph forms.

The usual options

  • The size of the fonts. A full CJK font is large: Noto Sans CJK Simplified Chinese Regular is about 16 MB per weight, Source Han Sans about the same, and even the regional subsets run from about 4.5 to 8.4 MB.
  • TextMesh Pro static atlases. Thousands of characters are baked into Alpha8 textures, about 1 MB at 1024² and 4 MB at 2048², split across a main asset and fallbacks, from character lists the project has to maintain.
  • TextMesh Pro dynamic atlases. Dynamic font assets add glyphs at runtime but include their source font in the build. Dynamic OS font assets read a system font instead and are the way to avoid shipping one; they are added to fallback lists by hand.
  • One shape for all three languages. TextMesh Pro looks glyphs up by code point only and has no language setting, so the regional form depends on which font asset in the fallback chain holds the character. Users report Chinese text drawn with Japanese glyph shapes, and the usual workaround swaps font assets per locale.
  • Line breaking. TextMesh Pro breaks CJK text between characters, guided by the leading and following character lists in its settings, rather than the Unicode line-breaking algorithm.

How UniText handles CJK

Chinese, Japanese and Korean rendered by UniText from operating-system fonts, with no font files in the project.
Chinese, Japanese and Korean rendered by UniText from operating-system fonts, with no font files in the project.
  • System fonts first. Characters no font in the stack covers come from the operating system's font for that run's language, through DirectWrite, CoreText, AFontMatcher or fontconfig. Nothing ships for CJK on desktop and mobile.
  • Right glyphs for the language. The Language property or <lang=ja>, <lang=zh-Hans>, <lang=ko> ranges turn on the OpenType locl feature and prefer a font family declared for that language, so the same code point is drawn the Japanese, Chinese or Korean way.
  • No baked atlas. Glyphs are rasterized when text first shows them, so only the characters actually displayed take atlas space, and player names or chat never meet a missing glyph.
  • Smaller shipped fonts. Font bytes are Zstd-compressed into the font asset, the Font Subsetter keeps only the characters a text corpus or character set needs, and Font Memory Mapping reads large files on demand instead of loading them whole.
  • CJK line breaking. Chinese and Japanese break between characters by the Unicode rules; an optional CJK dictionary adds word selection and word-by-word animation.

WebGL has no access to system fonts, so a WebGL build assigns CJK fonts, ideally subset, or downloads font bytes at runtime with UniTextFont.CreateFontAsset(byte[]).

Questions

Which system fonts are used?

Whatever the platform's own font matcher picks for the run's language, the same fonts the operating system uses for its own interface.

Can I use my own CJK font for a consistent look?

Yes. Put it in the font stack and declare its language on the font family. It takes priority for that language, and the system covers anything it lacks.

Check it in your project

Run the browser demo, follow the setup guide, or compare the free version with the licenses.

Related problems