Unity uGUI の Text Component でカーニング

現状(2016/11 Unity5.4 と Unity5.5Beta)では uGUI の Text Component はカーニング処理が出来ません。 
NGUI は出来る見たいなので、それを理由に NGUI を選ぶという Web の情報もちらほら。 
しかし、同じ Unity なのに uGUI は出来ないなんて事はないでしょう、と言うことで作りました。  

#概要
やはり Script は書かないとダメです。 
UnityEditor や Inspector をゴニョゴニョしても出来ません。 
Unity の uGUI の処理は [Bitbucket](https://bitbucket.org/Unity-Technologies/ui/overview) にコードがあるので、邪悪な魔改造と言うわけではありません。 
Unity 側の処理を理解して作れます。 
(まぁ Unity なんで Unity 処理依存の Script な時点で魔改造って言われてしまうのかも、、)

Bitbucket の NAVIGATION からソースを選び、且つ自分の使用している Unity Version のブランチを見る様にしましょう。 
古い Version の処理は、新しい Version と メソッド名だったりが結構違います。 

#uGUI 側のコード解説
現時点(2016/11)での最新 Version である　5.4 で説明して行きます。 
(作成するカーニング処理の発想は全ての Version で同じですが) 

UI / UnityEngine.UI / UI / Core / VertexModifiers / [BaseMeshEffect.cs](https://bitbucket.org/Unity-Technologies/ui/src/f0b47d48183738c2eb00e90ede60c38448f359b5/UnityEngine.UI/UI/Core/VertexModifiers/BaseMeshEffect.cs?at=5.4&fileviewer=file-view-default) 

上記パスの Script を使用します。 
これはコードを見てもらえれば分かりますが、abstract class なので自分で継承した class を作成します。 
さらに BaseMeshEffect class の継承元が UIBehaviour(これはMonoBehaviourを継承している)なので、作成する class は Component になります。
(コードや Inspector で AddComponent 出来る様になる)
これを Text Component に Add して使用します。

下記のメソッドを実装する事でカーニングを実現します。
VertexHelper class って言う Mesh の頂点情報を取得したり、変更したり出来る class を処理出来る様になります。
```C#
public abstract void ModifyMesh(VertexHelper vh);
```

ちなみに同じ階層に Shadow.cs や　Outline.cs があり、同じ発想で影文字や袋文字の処理をしています。 
(Unity のデフォルトで入ってる Component です) 

#カーニング Script 処理
複雑なコードやメモリを汚す様な処理は好きではないので、シンプルを目指しました。
なので、文字列は複数行(改行入り)には対応していません。
(おそらく対応するには、Script 内の centerList の差分が X 方向マイナスなら改行したとかの処理を増やすば、、)

```C#:TextKerning.cs
using UnityEngine;
using UnityEngine.UI;

/// <summary>
/// Menuのどこに出すかは自由.
/// </summary>
[AddComponentMenu("UI/Effects/TextKerning", 0)]
public class TextKerning : BaseMeshEffect {
  private const int CharaVertexNum = 4;
  private const float CharaVertexNumF = 4.0f;

  /// <summary>
  /// 文字間の距離をどれだけ詰めるか.
  /// 0 で何もしない状態.
  /// 1 で100%詰め(全ての文字が重なる).
  /// </summary>
  [SerializeField]
  private float kerningRate = 0.0f;

  private Vector3[] centerList = null;

  protected TextKerning() {
  }

  public override void ModifyMesh(VertexHelper vh) {
    if (!IsActive() || kerningRate == 0.0f) {
      return;
    }

    int count = vh.currentVertCount;

    // 1文字は4頂点のはずなので、余があるならTextではない？.
    if ((count % CharaVertexNum) != 0) {
      return;
    }

    int centerNum = count / CharaVertexNum;

    if (centerList == null || centerList.Length != centerNum) {
      centerList = new Vector3[centerNum];
    }

    // 4頂点毎の座標の重心を計算する.
    UIVertex vert = new UIVertex();
    Vector3 vec3 = Vector3.zero;

    for (int i = 0, j = 0, cnt = 0; i < count; ++i) {
      vh.PopulateUIVertex(ref vert, i);

      vec3 += vert.position;

      ++cnt;
      if (cnt >= CharaVertexNum) {
        centerList[j] = vec3 / CharaVertexNumF;
        ++j;
        cnt = 0;
        vec3 = Vector3.zero;
      }
    }

    // 文字全体を左寄せする.
    // 右寄せやら中央寄せが欲しいなら別途処理を作るしかないが、Text のアライメント指定があるので基本不要なはず？.
    float kerning = 0.0f;

    for (int i = CharaVertexNum, j = 0, cnt = 1; i < count; i += CharaVertexNum) {
      vec3 = centerList[cnt - 1] - centerList[cnt];
      ++cnt;

      kerning += vec3.magnitude * kerningRate;

      for (j = 0; j < CharaVertexNum; ++j) {
        vh.PopulateUIVertex(ref vert, i + j);

        vec3 = vert.position;
        vec3.x -= kerning;
        vert.position = vec3;

        vh.SetUIVertex(vert, i + j);
      }
    }
  }
}
```

こんな感じで頂点をズラす処理を実装すればOKです。 
またまた、ちなみに ModifyMesh がコールされるのは、Unity　的に Mesh が変更されると認識した1回だけですので、文字を波形の様にウネウネアニメーションさせたい時などは、毎フレーム ModifyMesh をコールしたいですよね？ 
そんな時は、BaseMeshEffect class の基底メンバの 

```C#
graphic.SetVerticesDirty();
```

をコールしましょう。すると Unity 的に頂点がダーティであると判断され、毎フレーム ModifyMesh がコールされる様になりますよ。