複雑なアニメーション
一つ一つのテキストを動かすアニメーションを作成してみましょう。 TextMesh Pro では Transformの座標を中心に四角い平面のメッシュが並んでいます。 このメッシュの4頂点の情報を書き換えることで、1文字1文字に動きを付けることが出来ます。
ジオメトリ情報を取得する
TMP_Text クラス(TextMeshPro や TextMeshProUGUI クラスの継承元)には、 単語や行などのテキストに関する TMP_TextInfo を保持しており、その中に TMP_MeshInfo というメッシュの情報を持っています。 TMP_MeshInfo は頂点情報を持っており、この情報を元にメッシュを生成することができます。
ジオメトリを変更する(頂点カラー)
色の変更例
using UnityEngine;
using TMPro;
public class TextMeshProAnimator : MonoBehaviour
{
[SerializeField] private Gradient gradientColor;
private TMP_Text textComponent;
private void Update()
{
if (this.textComponent == null)
this.textComponent = GetComponent<TMP_Text>();
UpdateAnimation();
}
private void UpdateAnimation()
{
// ① メッシュを再生成する(リセット)
this.textComponent.ForceMeshUpdate(true);
this.textInfo = textComponent.textInfo;
// ②頂点データを編集した配列の作成
var count = Mathf.Min(this.textInfo.characterCount, this.textInfo.characterInfo.Length);
for (int i = 0; i < count; i++)
{
var charInfo = this.textInfo.characterInfo[i];
if (!charInfo.isVisible)
continue;
int materialIndex = charInfo.materialReferenceIndex;
int vertexIndex = charInfo.vertexIndex;
// Gradient
Color32[] colors = textInfo.meshInfo[materialIndex].colors32;
float timeOffset = -0.5f * i;
float time1 = Mathf.PingPong(timeOffset + Time.realtimeSinceStartup, 1.0f);
float time2 = Mathf.PingPong(timeOffset + Time.realtimeSinceStartup - 0.1f, 1.0f);
colors[vertexIndex + 0] = gradientColor.Evaluate(time1); // 左下
colors[vertexIndex + 1] = gradientColor.Evaluate(time1); // 左上
colors[vertexIndex + 2] = gradientColor.Evaluate(time2); // 右上
colors[vertexIndex + 3] = gradientColor.Evaluate(time2); // 右下
}
// ③ メッシュを更新
for (int i = 0; i < this.textInfo.materialCount; i++)
{
if (this.textInfo.meshInfo[i].mesh == null) { continue; }
this.textInfo.meshInfo[i].mesh.colors32 = this.textInfo.meshInfo[i].colors32;
textComponent.UpdateGeometry(this.textInfo.meshInfo[i].mesh, i);
}
}
}
実行すると下記のようになります
1.TMP_Text.ForceMeshUpdate() でテキストからメッシュ再生成(元の状態にリセット) 2.TMP_MeshInfo.vertices などの情報を更新 3.TMP_Text.UpdateGeometry() でメッシュを更新
meshInfo.color32 の配列の中身を直接書き換えて、UpdateGeometry() で渡してメッシュを再生成しています。
meshInfo.color32 を使うことは強引なやりかたで、ForceMeshUpdate() でメッシュを再生成しないとマズかったりします
・Gradient および gradientColorについて [SerializeField] は Unity のエディタ上でインスペクターでパラメータを調整できるようにする属性です。 Gradient は グラデーションカラーを設定できるクラスで、Evaluate(0.0f ~ 1.0)から滑らかな色を取得できます。
ジオメトリを変 更する(頂点座標)
using UnityEngine;
using TMPro;
public class TextMeshProAnimator : MonoBehaviour
{
private TMP_Text textComponent;
private TMP_TextInfo textInfo;
private void Update()
{
if (this.textComponent == null)
this.textComponent = GetComponent<TMP_Text>();
UpdateAnimation();
}
private void UpdateAnimation()
{
// ① メッシュを再生成する(現在のテキスト状態を取得し、メッシュをリセット)
this.textComponent.ForceMeshUpdate(true);//true を渡すことで、すべてのメッシュデータが更新されます。
this.textInfo = textComponent.textInfo;//テキストメッシュの詳細情報を保持する`TMP_TextInfo`を取得します。(各文字の位置や頂点データが含まれています。)
// ②頂点データを編集した配列の作成(テキスト内の各文字に ついて、頂点データを直接操作し、アニメーション(波状の動き)にする)
var count = Mathf.Min(this.textInfo.characterCount, this.textInfo.characterInfo.Length);
for (int i = 0; i < count; i++)
{
var charInfo = this.textInfo.characterInfo[i];//各文字の詳細情報(頂点のインデックスや位置など)を取得します。
if (!charInfo.isVisible)//非表示の文字は処理をスキップします。
continue;
//頂点データの取得:
int materialIndex = charInfo.materialReferenceIndex;//使用しているマテリアルのインデックス。
int vertexIndex = charInfo.vertexIndex;//文字に関連付けられた頂点データの開始インデックス
// Wave
Vector3[] verts = textInfo.meshInfo[materialIndex].vertices;//現在の頂点データを取得。
float sinWaveOffset = 0.5f * i;//各文字ごとに異なる位相を持たせるためのオフセット
float sinWave = Mathf.Sin(sinWaveOffset + Time.realtimeSinceStartup * Mathf.PI);//現在の時間 (Time.realtimeSinceStartup) を使用して波状の動きを計算。
//各頂点 (verts[vertexIndex + 0] 〜 verts[vertexIndex + 3]) に対して y 座標を変更し、波状に上下する動きを適用。
verts[vertexIndex + 0].y += sinWave;
verts[vertexIndex + 1].y += sinWave;
verts[vertexIndex + 2].y += sinWave;
verts[vertexIndex + 3].y += sinWave;
}
// ③ メッシュを更新(操作した頂点データを元にメッシュを更新し、画面上のテキストに反映します。)
for (int i = 0; i < this.textInfo.materialCount; i++)
{
if (this.textInfo.meshInfo[i].mesh == null) { continue; }
//変更した頂点データを現在のメッシュデータに反映。
textInfo.meshInfo[i].mesh.vertices = textInfo.meshInfo[i].vertices;
//実際の描画に変更を適用。
textComponent.UpdateGeometry(this.textInfo.meshInfo[i].mesh, i);
}
}
}
全体的な動作
-
頂点操作:
TMP_TextInfoに含まれる頂点データは、各文字の4つの頂点 (四角形) を直接操作可能です。- アニメーションは頂点の
y座標を周期的に変化させることで表現。
-
リアルタイム更新:
Update()メソッドを使用して毎フレームアニメーションを更新。
-
波状の動き:
Mathf.Sinを利用して自然な波の動きを再現。- 位相オフセット (
0.5f * i) により、文字ごとに波の位置をずらしています。
-
メッシュに適用:
- 最後にメッシュとして表示。