コラム:TextMeshProの落とし穴


投稿日:2023年12月23日 | 最終更新日:2024年4月26日

ここでは、TextMeshProを使う上での落とし穴をまとめました。
こういったことの原因や解決方法を調べるのはかなり労力が要ることなので、同じ苦労をする人が減ってほしいという目的でまとめていきます。
書いていることが間違っていたり古かったりして、すでに解決済みなことがあったらぜひこちらにご連絡いただくと助かります。
内容は随時更新予定です。
この記事はUnity Advent Calendar 2023 その2 25日目の記事でもあります。

バージョンの問題

TextMeshProは元々アセットストアで売っていたサードパーティ製のアセットだったのですが、Unity公式に採用されUnityEngine本体との統合が進んでいます。
ですが、そのせいか非常にバージョンごとの違いが複雑になっています。
2023年末現在の正規リリース版は3.0で、それ以外にプレビュー版として3.2と4.0があります。
メインは3.2系で、4.0系は基本的にはUIToolKitのためのもののようですが、将来的には全て統合されるようです。
以下、変遷をまとめてみました。

時期 説明
2014 アセットストアからリリース。Unity4.6以降をサポート
2017 Unity公式が買収。Unity5.3.4からは無料でインポート可能に
2018 Unity公式のUI機能の拡張として統合開始。
テキストの基盤機能がTextMeshProの機能を元にしたTextCoreとして統合し、「TextMeshProを統合したuGUI」、「UIToolKit」、「IMGUI」のすべてで利用する共通基盤として、Unityエンジン本体に組み込むのを目指す
2020 TextMeshPro3.0がリリース 
2021 TextMeshPro3.2がプレビュー版として公開
Unity2021.2ごろから従来のTextコンポーネントがLegacy化し、TextMeshProがあらたな標準テキスト表示コンポーネントに
2023末 Unity2023.2から、uGUI2.0パッケージに統合され、TextMeshProパッケージのインポートが不要に。
内容はTextMeshPro3.2のもの。4.0系を使っていた人は変換作業が必要らしい。
参考:TextMesh Pro - [2023.2] Latest Development on TextMesh Pro - Unity Forum
2024年~の予定 Unity2023LTS(Unity6?)からTextMeshPro3.2(プレビュー版)だったものがUGUI2.0の一部としてリリース版になる予定。
Unity2024.1(Unity7?)からはTextCoreと統合される。その部分はUntyEngine本体となるので、ソースコードアクセスに制限ができる。TextMeshProのソースコードやシェーダーを書き換えていた人は影響が出る可能性がある。
これら基盤機能の改修が済むまでは、TextCoreとTextMeshProには新しい機能を追加しない予定。
Unity2024(Unity7?)でも旧来のTextコンポーネント(LegacyText)はサポート予定。ただし、将来的には廃止予定(とはいっても相当先になりそう)
参考:Official - Future of Text at Unity - Unity Forum

ドキュメントはどこ?

TextMeshProとしてのドキュメントは次のようになっています。
TextMeshPro3.0のドキュメント。実質TextMeshProが個人製作だったころのサイトへのリンク集となる
TextMeshPro3.2のドキュメント。一部の機能が記載漏れがあったりするものの、実質これが基本?

日本語ドキュメントはどこ?

拡張パッケージとしてのTextMeshPro公式の日本語ドキュメントはないのですが、
Unity公式ドキュメントのUI ToolKitの方に、共通機能の日本語ドキュメントあったりします。
とはいえ、読みやすいかというとちょっと微妙です。
特に、UIToolKit限定の話なのか共通の話なのか、プレビュー版の機能なのか3.0以前でも使えるのか、などの区別がおおざっぱにでも予測できないと混乱するかもしれません。

サポートされるリッチテキストタグ - Unity マニュアル
Font Asset Creator プロパティリファレンス - Unity マニュアル
スプライトをテキストに加える - Unity マニュアル

ColorSpaceの問題

Unity2022.3前後から、UnityのデフォルトのColor SpaceがLinearに変更されたようです。

Edit > Project Settings> Player と選択していくと、 Other SettingsのRenderingにColor Spaceの設定項目があります。

Linearだと、UnityのUIの表示結果が異なってしまうらしいです。
TextMeshProで描かれるテキストと、UI画像のアルファブレンド(半透明表示)を使っている部分です。

サンプル:Gamma設定(2023.2で確認)

サンプル:Linear設定(2023.2で確認)

ただ、この挙動自体は何年も前からそのままなので、Linearで表示が変わってしまうのがバグなのか仕様なのかが今のところはっきりしません。
Unityに確認したところ、これは仕様のようです。

TextMeshProは、暗い色の文字ほど細くなっているようにみえてしまうのですが、細くなっているわけではなく拡大するとうっすらと薄く色がついています。
テキストの線の細かな濃淡はアルファブレンドによっても決まるので、結局のところアルファブレンド時の問題のようです。

UnityJapanから「UIだけアルファブレンドをガンマと同じ結果に近づける」という手法が発表されています。
少し試したところ一応解決したようにみえました。(ただし、URP使用限定でカスタムが必要。処理負荷などが実用的かは不明)
実装レベルとしては難易度が高い部類に入ると思いますが、気になる場合はこれを検討してみるとよいかもしれません。
参考:
Color SpaceがLinearのときUIの透明度が正しくならない | Unity | kido Tech Blog
CEDEC2022-URP: CEDEC2022 URP Presentation samples

ColorSpaceがLinearの場合は他にも不具合があるケースもあり

また、アルファブレンドの問題以外にもUnityやTextMeshProのバージョンによっては暗いVertextColorだと正確に表示されなくなることがあるようです。
Linearにする場合はなるべく新しいバージョンにしましょう。

LinearとGammaどっちにすべき?

ライティングを多用する3Dモデルを表示する際には、Color SpaceがLinear前提となっていることが多いのですが、2Dゲームやモバイルゲーム、その他UIが多くの描画を占めるゲームなどではColorSpaceを「Gamma」に設定するほうが従来通りに安定すると思います。
Unity2021まではデフォルトのColor SpaceはGammaになっていたので、TextMeshProの表示もGammaが基本となっていると思われます。
(Unity2022.3以降でもプロジェクト作成時のテンプレートがMobile2DなどだとGammaのままのようです)

フォントアセット作成時の落とし穴

SamplingPointSizeは固定値(Custom Size)が望ましい

TextMeshProでは、Padding/PointSizeがアウトラインの太さなどを決定する基準値になるため、
AutoSizingを使うとPointSizeが変わってしまう可能性があり、フォントアセットを更新するたびにアウトラインなどの見た目の太さが変わってしまうおそれがあるため、「Custom Size」のほうが安定します。
詳細:Paddingの与える影響

Atlas Resolutionは4096以下

理由は単純で、画像サイズ8192以上は一部のAndroid端末で動かないからです。
PCなど対象プラットフォームのスペック的に問題ないことがわかっているなら、8192以上を使ってもよいでしょう。
ただし8192くらい大きくなると、フォントアセットのUnityエディタ上のファイルサイズが100MBを超えてしまうので、Gitなどバージョン管理ツールの制限にひっかかるおそれもあります。

フォントアセットの名前は「フォント名 SDF」のままでつけない

フォントアセットの名前は、新規作成してファイル保存する時のデフォルトでは「フォント名 SDF」となっているのですが、
「プロジェクト名フォント名フォールバック名 SDF」のように、なるべく明確に区別がつくものしたほうが良いです。
見た目にわかりやすいというのもそうなのですが、もっと深刻な問題があります。
Unityエディタ上のみでの問題なのですが、TextMeshPro系コンポーネントはインスペクターの表示時などに、命名規則に従って「Material Preset」のためにその候補となるマテリアルをすべてロードするという挙動になっています。

これは、TMP_EditorUtility.FindMaterialReferences()のコードで書かれている部分です。
内部のコードを読むとわかりますが、実際にドロップダウンリスト表示されるもの以外に、Unityプロジェクト内にあるすべてのフォントマテリアルのうち検索キーに一致するマテリアルをすべてロードしています。
たとえば、ローカライズのために「NotoSans SDF」をメインに使用し、フォールバックで「NotoSansJP0 SDF」「NotoSansJP1 SDF」、「NotoSansKR0 SDF」「NotoSansKR1 SDF」...といったように、「フォント名 + ロケール記号+連番」などどしていると、「NotoSans」という名前を含んでいるため、全てが検索結果に一致してロードされてしまいます。
そして、マテリアルにはアトラス画像が付随しているため、このサイズが大きいとロードの負荷がかなり上がります。
通常はあまり問題になることはないかもしれませんが、実験的にフォントアセットをたくさん作っていたり、ローカライズのために名前が重複するようなフォントをたくさん作っているとかなりの負荷になります。
自分のケースでは90個くらいのアトラス画像がロードされる結果になってしまっていたため、テキストオブジェクトを選択するたびに何秒かUnityが固まってしまっていました。
検索キーとなるのは、「メインのフォントアセットの名前をスペース区切りにした最初の部分」です。
メインのフォントアセットを「ProjectNameNotoSans0 SDF」や「ProjectNameNotoSansMain SDF」のようにして検索キーの対象が絞られるようにしましょう。フォールバックフォントは「ProjectNameNotoSansJP0 SDF」のようにして、メインのフォントアセットの検索キーと重複を避けるようにしましょう。

フォントアセットの名前を変えるには

フォントアセット名自体は作成した後でも変えられるのですが、
そのサブアセットになるデフォルトマテリアルやアトラス画像の名前は、metaファイルを直接編集するかエディタ拡張を自作しないと変更できません。
検索のキーになるのは、フォントアセット名の方なので、サブアセットの名前は変えなくても一応問題ないのですが、
なるべくなら名前変更が必要ないように、フォントアセットの初回作成時に上記を意識した名前を付けたほうが良いでしょう。

「Line Metrics」の落とし穴

「Line Metrics」の落とし穴を参照してください。

SpriteAsset(スプライト絵文字)の落とし穴

TextMeshProのスプライトの機能が作成されたのが、UnityにSpriteAtlas機能ができる前だったという事情はあるとは思うのですが
Unity公式が採用し標準テキスト機能となっても未だにSpriteAtlasを使うことができません。
かといって、Sprite画像単体を使用することもできないです。
結果として、複数の絵文字が一つのテクスチャに統合された画像を自前で用意する必要があります。

Dynamicフォント

Dynamicフォントの注意点を参照してください。