TextMeshProに指定したフォントのプロパティを操作したい

# はじめに
　TextMeshProのInspectorウィンドウに表示されていたフォントマテリアルをスクリプトによって操作するのに苦労したため，この記事を書きました．同じようなことをしようとしている人の助けになれたらと思います．また，今回使用したフォントは以下リンク先からダウンロードできます．
 [Liberation Sans](https://www.fontsquirrel.com/fonts/liberation-sans)
 
# 1. なぜTextMeshProのプロパティを操作したいのか
　文字が消えるエフェクトをどうするか考えていると，TextMeshProのInspectorウィンドウの **Liberation Sans SDF MaterialのFace** の値を変えると文字が自然な形で消えることに気づいた．そして，この動作をスクリプトから操作する方法が必要だった．

![スクリーンショット (229).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3759393/e87b7073-4217-cf9b-4ea1-43336e70bd0e.png)
操作したい値
![bandicam 2024-03-30 16-43-38-687.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3759393/a6d6fd1d-e9fc-1202-361d-0e8516340ace.gif)
求めている動作

# 2. GetComponentによる取得
　まず，Inspectorウィンドウの値を変更するため，GetComponent<>()によって操作しようと考えた．つまり，変更したい値がInspectorウィンドウに表示されているため，当然GetComponent<>()によって値を取得できるものと考えていた．しかし，Liberation Sans SDF MaterialをGetComponentで探したがうまくいかなかった．

```c#: erase_text.cs

Libration text_mesh

Start(){
    this.text_mesh = this.getComponent<Libration>();
    //これに近いものも多々試してみたがうまくいかなかった
}
```

:::note warn
Shader型，TextMesh型でもGetComponent<>()を行ったが取得できなかった
:::

　いろいろと試したがGetComponentによって，直接Inspectorウィンドウの値を得ることは難しいと考えて諦めた．そのため，シェーダマテリアルを直接編集することを考えた．しかし，そのためにはまず，シェーダマテリアルを取得する必要がある．

# 3. シェーダマテリアルを取得し，その値を編集することを考えた．
　調べているとTextMeshProを操作するためにはTextMeshProUGUIが必要だということが分かった．そのため，まずはTextMeshProUGUIをスクリプトに追加した．そして，そのTextMeshProUGUIからシェーダマテリアルの現在の値を取得することを考えた．
```c#: erase_text.cs
using UnityEngine;
using TMPro; //TextMeshProUGUIを使うために必要

TextMeshProUGUI text_mesh; //TextMeshProUGUIを格納

Start(){
    text_mesh = this.getComponent<TextMeshProUGUI>()
    Material material = text_mesh.material;
    Debug.Log(material.name)
}
```
#### 結果
```
    Default UI Material
```
　ここで編集を行いたい **Liberation Sans SDF Material** が表示されればよかったが，表示されたのは **Default UI Material** だった．これは **textmesh.material** がTextMeshProのゲームオブジェクトとしてのシェーダマテリアルを取得しているためと考えられる．しかし，今欲しいシェーダマテリアルはTextMeshProのフォントのシェーダアテリアルであるため，別の方法を考える必要があった．

# 4. fontSharedMaterial()メソッドによるマテリアル取得
　別のマテリアル取得方法を探しているとTextMeshProのfontShareMaterialメソッドを見つけた．すると以下のように求めていたシェーダマテリアルが取得できた．

```c#: erase_text.cs
using UnityEngine;
using TMPro; 

TextMeshProUGUI text_mesh;

Start(){
    text_mesh = this.getComponent<TextMeshProUGUI>()
    Material material = text_mesh.fontSharedMaterial;
    Debug.Log(material.name)
}
```
#### 結果
```
    Liberation Sans SDF Material
```
　ここまでで，操作を行いたいシェーダマテリアルを取得できた．これにより，実際に操作を行うことが出来る．

# 5.シェーダマテリアルを操作する
　シェーダマテリアルの操作(シェーダのプロパティの編集)には，GetFloat(), SetFloat()を使う．その構文は以下のようになっている．
```
GetFloat("変数名")
```
```
SetFloat("変数名", 代入したい値)
```

　そして，操作する変数名はシェーダのスクリプトから **_FaceDilate** であることが分かっているため，操作を行うスクリプトは以下のようになる．

```c#: erase_text.cs
using UnityEngine;
using TMPro;

TextMeshProUGUI text_mesh;

Start(){
    text_mesh = this.getComponent<TextMeshProUGUI>()
    float dilate = text_mesh.fontSharedMaterial.GetFloat("_FaceDilate")
    //プロパティの取得
    Material material = text_mesh.fontSharedMaterial.SetFloat("_FaceDilate", dilate - 0.1);
    //プロパティの設定
}
```

　このスクリプトにより，文字の太さが **0.1** だけ細くなる動作が実装できた．そして，最後に実際の実装を行う．

# 6. だんだん字が消えていく動作の実装
```c#: erase_test.cs
using UnityEngine;
using TMPro;

public class start_text : MonoBehaviour
{
    TextMeshProUGUI text_mesh_pro;
    float time = 0;

    // Start is called before the first frame update
    void Start()
    {
        this.text_mesh_pro = this.GetComponent<TextMeshProUGUI>();
        this.text_mesh_pro.fontSharedMaterial.SetFloat("_FaceDilate", 0);
    }

    void eraseTextRepeating()
    {
        float dilate = this.text_mesh_pro.fontSharedMaterial.GetFloat("_FaceDilate");
        this.time += Time.deltaTime;

        if (this.time > 0.1)
        {
            this.time = 0;
            if(dilate > -1)
            {
                this.text_mesh_pro.fontSharedMaterial.SetFloat("_FaceDilate", dilate - 0.05f);
            }
            else
            {
                CancelInvoke();
            }
        }
    }

    public void eraseText()
    {
        float interval = 0.01f;
        InvokeRepeating("eraseTextRepeating", 0f, interval);
    }
}
```
　これにより，だんだんと字が消える動作が実装できる．また，このスクリプトでは解説した動作以外にインターバル処理を行っている．

# 7.まとめ
ポイント
+ TextMeshProを編集する場合はTextMeshProUGUIを用いる
+ シェーダマテリアルの取得にはTextMeshProUGUIのfontShareMaterialメソッドを用いる
+ シェーダマテリアルのプロパティの取得にはgetFloatメソッド，設定にはsetFloatメソッドを用いる

注意点
+ フォントのシェーダマテリアルはGetComponentによっては取得できない
+ TextMeshProUGUIのmaterialはフォントのマテリアルではないため気を付ける
+ 変数名はシェーダスクリプトから探す