[unity2019.LTS] Text Mesh Proで日本語マスター

unity 2018.LTS、unity 2019.LTS ではほぼ標準とも言うべき Text Mesh Pro で日本語フォントを作成するまでの手順を紹介します。

なお、日本語フォントとしましたが、英語や数字だけでも手軽に高品質の表示が可能なので、

  • フォントは重いし、信用ならない
  • スコア表示やタイトルセレクトなど、面倒だけど毎回絵を作っている

こんな方も、試しに使ってみることをお勧めします。

下準備

Open Type Font (拡張子 otf)、もしくは True Type Font (拡張子 ttf) を用意してください。
とりあえず…であれば Noto Sans / Noto Serif などはライセンス緩めで、良さそうです。

フォントライセンスには注意しましょう。
フリーではなかったり、GPL ライセンスだったりで市販の(しかも結構著名な)ゲームですら過去大きな問題になったこともあります。

Font Asset Creator でフォントを作成

Window – TextMeshPro – Font Asset Creator

Source Font File
作成したい otf、または ttf ファイルをドラッグします。
ドラッグする otf / ttf ファイルは Assets フォルダに含めないとドラッグできません。

Sampling Point Size
Custom Size で、大きさは 20~45 くらいにしておくと普通の文字であれば充分な品質が得られます。
数字が大きいほど、大サイズのフォントでも綺麗に表示されますが、その分ファイルサイズも巨大化します。

Padding
デフォルトのまま(4)

Packing Method
Fast .. パッキング時間が早い、サイズが少し大きい
Optimum .. パッキング時間が激遅、サイズが少し小さい
日本語のような大量の文字数の場合、Optimum を設定するとパッキングに数時間かかる割にたいしてサイズが小さくならないので、Fast でいいと思います。

Atlas Resolution
4096 x 4096 がファイルサイズ的にも適当だと思いますが、お好みで。
ただし、Sampling Point Size が大きすぎたり、Character Set が多すぎると 4096 x 4096 に収まらないかもしれません。その場合は Sampling Point Size を小さくするなどして対応します。

Character Set
Characters from file を選択し、Character file は次の項にあるファイルをプロジェクトに含め、ドラッグしてください。

Render Mode
SDFAA を選択しておけば大体問題ありません。
最初に選択されている SMOOTH_HINTED はパッキングが高速ですが解像度が粗く、シェーダーの Outline Underlay が使えないので注意してください。

上から SMOOTH_HINTED / SMOOTH / SDFAA_HINTED / SDFAA

Generate Font Atlas
このボタンを押すと、パッキングフォントを作成します。
完了したら、Save / Save as… で作成したフォントを保存します。

保存した後、otf /ttf ファイル、Character Set のテキストは不要になります。
プロジェクトから消しても大丈夫です。

Character Set の文字列

配置してみる

ヒエラルキーで 右クリック > UI > Text – Text Mesh Pro を選択

Font AssetFont Asset Creator で作成したファイルを指定します 。
とりあえず一行表示でよければ Wrapping Disabled にします。
Width、Height、Font SizeAlignment などをお好みに調整します。
文字をクリックされたくない場合は、Extra Settings – Raycast Target のチェックを外します。

便利な Auto Size

横一行に入る文字数がわからず、表示エリアをはみ出してしまうことがよくあります。

AutoSize にチェックを入れるとこのように、黄色の枠に収まるよう自動的にフォントサイズが変化します。

  • 黄色い枠は Width, Height で調整します
  • Auto Size OptionsMin が最小フォントサイズ、Max が最大フォントサイズ

フォントに影や境界線をつける

通常のテキストと異なり、軽量、かつ高品質な効果をかける事ができます。

  • シェーダーの Face – DilateOutline – Thickness を同じ値で上げていくと境界線
    境界線のある状態で Face – Softness を上げていくと境界線がぼやける
  • シェーダーの Underlay にチェックを入れて、Offset X を 1、Offset Y を -1 にすると文字の右下に影
    影のある状態で Underlay – Softness を上げると影がぼやける

ただし、作成したフォントの Render Mode が SMOOTH(_HINTED) の場合適用されませんので注意してください。

この場合、シェーダーで選択することができない

全ての文字が同じ効果になってしまう問題

上の例のように別々の効果がかかったテキストを目指したのに、全て最後に設定した効果になってしまったかもしれません。

全て境界線に…

フォント効果の内容は、Object Component ではなく Material が記憶しています。
初期状態では、1フォント1マテリアルのため、テキストが5つあっても、全て1つのマテリアルを参照しているので、全部同じ効果になってしまいます。

テキストごとに別フォント(表示するフォントは同じでも…)を作って割り当てる、とすることもできますが、容量やロード時間が爆発的に増えるためお勧めできません。
それより1フォント複数マテリアルとし、それぞれのテキストにマテリアルを割り当てれば狙った通り別々の効果を割り当てることができます。

マテリアルを複数にする方法

フォントの中にある ???? Material を選択します。

Inspector の右上、歯車アイコンをクリック > Create Material Preset

新しく作成されたマテリアルは、分かりやすいように名前を変更してください。

テキストオブジェクトを選択し、Inspector の Material Preset を作成したものに変更します。

こうすることで、マテリアルごとに変化をつけることができます。

テキストにタグを書く事で、表示にバリエーションをもたせる

かなり色々なことができる!
参考サイト様は英語での記述ですが、パッと見でわかるようになっていて、便利です。

GCスパイクしまくりの適当コーディングですが、こんな事もできます。

以下のコードを TextMeshPro と同じ GameObject にアタッチする事で、テキストが自動的に波打ちます。

using TMPro;
using UnityEngine;

public class TextTest : MonoBehaviour
{
    public TextMeshProUGUI text;
    
    string plaintext;
    float time;

    // Start is called before the first frame update
    void Start()
    {
        plaintext = text.text;
        time = 0;
    }

    // Update is called once per frame
    void Update()
    {
        time += Time.deltaTime;
        while (time > 1.0f) time -= 1.0f;
        if (time < 0) time = 0;

        float t = time;
        string txt = "";
        for (int i = 0; i < plaintext.Length; i++)
        {
            float val = Mathf.Sin(Mathf.Deg2Rad * t * 360.0f);
            txt += $"<voffset={val}em>{plaintext[i]}</voffset>";

            t += 0.125f;
            if (t > 1) t -= 1.0f;
        }

        text.SetText(txt);
    }
}