ビルドサイズ、フォント、グリフアトラス、ランタイムパフォーマンスに関する率直な回答 — 実際の開発者からの質問をもとにまとめました。
いいえ。UniText はフォントごとのテクスチャアトラスをビルドに焼き込むことはありません。グリフはランタイムに共有アトラス(Texture2DArray ベース)へラスタライズされ、グリフごとの参照カウントと LRU による退避で管理されます。ビルドに含まれるのはフォントデータのみで — アトラスが含まれることはありません。さらに、組み込みのフォント圧縮(Zstd、レベル22)により、ラテン文字/アラビア語ではフォントデータを最大 ~2.7× まで縮小できます(CJK はより控えめで ~1.3×)。
いいえ。UniTextFont アセットはフォントのバイトデータを自身の内部に埋め込みます。ソースフォントへの参照は Editor 専用(#if UNITY_EDITOR で囲まれています) — プレイヤービルドにはそもそも存在しないため、ランタイムの依存関係にはならず、依存関係の解決によって AssetBundle に取り込まれることもありません。アセットを作成した後は .ttf を削除できます。
いいえ。UniText のツールウィンドウから、ディスク上のどこにある .ttf でも UniTextFont を作成できます(ファイルダイアログがバイトデータを直接読み取ります)。フォントをプロジェクトにインポートするかどうかは任意です。
• WebGL: 空のビルドは ≈ 6–10 MB です(Unity のバージョンやインストール済みパッケージによって変動します)。UniText はネイティブライブラリ(HarfBuzz、FreeType)を追加します。これらは Unity 自身の UI Toolkit Advanced Text Generator が同梱しているのと同じ業界標準のライブラリで、特別なものではありません(UniText は自前のコピーを持っているだけです)。 • Android: 2つのアーキテクチャを含む APK は両方を抱えます — アーキテクチャあたり約 +4 MB です。しかし AAB で公開すれば、Google Play がデバイス固有のバンドルを配信するため、ユーザーは両方ではなく自分のアーキテクチャ(~4 MB)だけをダウンロードします。
グリフは3つのサイズ — 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 をラスタライズします。2つ目の H は何もせず、a は a だけをラスタライズします。
コストは、そのフレームでラスタライズされる、初めて登場するユニークなグリフの数に比例します — テキストの長さにではありません。当社のベンチマークでは、最初のフレームで ~2000 個のユニークなグリフは、一般的な Android デバイスで ≈ 1 秒です。TMP と UI Toolkit は同じシナリオで 10+ 秒かかります。キャッシュ済みのグリフの再利用は無料です。
UniText はホットパスで Unity の Job System にほとんど依存していません — これは設計上の意図です。グリフのラスタライズ(独自の lpSDF / lpMSDF)は、デフォルトでコンピュートシェーダーを介して GPU 上で実行されます。Burst ジョブは、コンピュートが利用できない場合の CPU フォールバックにすぎません。主要なマルチスレッド処理 — シェーピング、レイアウト、メッシュ生成 — は、UniText 独自の OS スレッドプール上で実行されます(Unity Jobs ではないため、Jobs プロファイラーには表示されません)。つまり「UniText のジョブがない」ことは「スレッドがオフ」であることを意味しません。処理が GPU に回されたか、アトラスがすでにウォームであるか、あるいはテキストが並列化のしきい値を下回っているか(短いラベルや単一のラベルは順次処理されます — その方が安価だからです)のいずれかです。
「Update() は遅い」というのは、リリースビルドにおいては俗説です。ネイティブコードからのマジックメソッド呼び出しのオーバーヘッドは実在しますが、無視できるほど小さく(~1000 回の呼び出しで ≈ 0.16 ms) — ボトルネックではありません。素朴なコードにおける本当のコストは、コールバック自体ではなく AoS のメモリレイアウトです。UniText は重要な箇所で SoA を適用します(Unicode 属性、メトリクス、ピクセルごとのバッファ)。(ECS が高速なのもこれと同じ理由です — 「ECS の魔法」ではなく SoA のおかげです。)そして UniText はいずれにせよ集中管理されています — ただし MonoBehaviour のマネージャーとしてではありません。Update() 自体はほぼ空で、重い処理は Canvas のレンダーコールバックで単一のバッチ処理にまとめられます(これがコンポーネント間の並列化をもたらすものでもあります)。
Discord でお尋ねください — このページは、まさにこうした質問から形づくられました。たいてい迅速に返信します。