うにてぃブログ

UnityやUnreal Engineの記事を書いていきます

【Unity】TextMeshPro の Font Material を外部からロードする

TextMeshPro を利用していると FontMaterial が大量にできてしまったりして、管理が面倒になってくるので
外部からロードできれば楽になることがあるのではと思い実装の調査をしてみました

TextMeshPro の Font Material

Font Material の 差し替えを行うことができればなんとかなりそう

public abstract class TMP_Text : MaskableGraphic
        public Material fontMaterial
        {
            // Return an Instance of the current material.
            get { return GetMaterial(m_sharedMaterial); }

            // Assign new font material
            set
            {
                if (m_sharedMaterial != null && m_sharedMaterial.GetInstanceID() == value.GetInstanceID()) return;

                m_sharedMaterial = value;

                m_padding = GetPaddingForMaterial();
                m_havePropertiesChanged = true;
                m_isInputParsingRequired = true;

                SetVerticesDirty();
                SetMaterialDirty();
            }
        }

ということで 今回は Resources からのロードになりますがロードテストを行ってみる

public static class TextMeshProUtil
{
    public static void SetMaterial(TextMeshProUGUI target, string path)
    {
        // ここのロード処理は変える必要がある
        var material = new Material(Resources.Load<Material>(path));
        target.fontMaterial = material;
    }
}

特に何事もなく動作した

がこれはテスト用なのでキャッシュや削除処理等を記述しないと
メモリリークしてしまう可能性があるので注意してください

f:id:hacchi_man:20200602014406g:plain

アセットのサイズ

今回は Resources からのロードだから問題は無いが、これをアセットバンドル対応した場合
フォントのテクスチャがアセットに含まれてしまうため、サイズが大きくなってしまう

そのため、フォントのテクスチャの参照を外す

Shader を見てみると フォントのテクスチャは _MainText に紐付いているためこれの参照を外してロードしてみる

_MainTex            ("Font Atlas", 2D) = "white" {}

Inspector を Debug にすると手動で外せます

f:id:hacchi_man:20200602012314p:plain:h300f:id:hacchi_man:20200602012339p:plain:h300

先ほどの処理の間に MainTexture の差し込み処理を追加しました
こちらでも問題なく動作しています

public static class TextMeshProUtil
{
    public static void SetMaterial(TextMeshProUGUI target, string path)
    {
        // ここのロード処理は変える必要がある
        var material = new Material(Resources.Load<Material>(path));
        material.mainTexture = target.fontMaterial.mainTexture;
        target.fontMaterial = material;
    }
}

複数のフォント対応

今回フォントを差し替えることで、同じ Font Material を他のフォントに対しても適応する
ことができるため、複数のフォントを利用している場合はマテリアルの数を減らせるかもしれません f:id:hacchi_man:20200602015709g:plain

問題点

マテリアルからフォントの参照を外したため
TextMeshPro の Inspector 上で Material Preset 一覧に外したマテリアルが出てこなくなります
f:id:hacchi_man:20200602015159p:plain

そのため、見た目をチェックするのが面倒になるので、アセットバンドルにする場合は
ビルド時に参照を外す対応を入れるといいかもしれません