文字のアウトライン処理と、その高速化シェーダー


Unityのアウトライン処理の基本

アウトラインとは「縁取り」のことです。
UnityのUIの基本コンポーネントとして、「Outline」というものが既にあります。公式ドキュメント
これは、黒など色違いのものを上下左右4方向にコピーして、背後に表示するというものです。
仕組みとしては単純ですが、4方向だけですと、縁取りを太くした場合に若干不格好になるという問題があります。

宴のアウトライン処理

宴では、Outlineを改造した「UguiRichOutuine」という専用のコンポーネントを用意して、ある程度太い縁取りも可能にしています。

アウトラインコンポーネントのデメリット

UguiRichOutuineはその名の通り「Rich(リッチ)」で、負荷のかかる贅沢な使い方です。
Unityの基本のOutLineにしても、UguiRichOutuineにしても、描画するためのポリゴンの頂点数がとても増えるというデメリットがあります。
そして、Unityが用意しているUIの頂点をカスタムする仕組みの構造上、頂点数が増えた場合にとてもCPU負荷が高くなってしまいます。
(内部的な細かい話としては、大サイズのstructのListを扱う構造になっているため、値を変更するためには参照ではなく必ず大サイズstructのコピーが発生してしまうのが原因。C#のバージョンによっては回避できない)
さらに、ノベルゲームでは文字送り(1文字ずつ表示する)のために、毎回テキストの頂点編集を行う必要があるため、文字送りの最中ずっと重いCPU負荷がかかります。
通常の使い方であれば文字数は多くても200程度なのであまり問題ないのですが、英語圏の場合文字数が増えるため1ページに500以上の文字の表示が必要なケースもあります。
ここまでの状況になると、FPSが10近くに落ち込むなど、ゲームとしては致命的な状態になります。

アウトラインシェーダー

上記のアウトラインコンポーネントのCPU負荷の高さは、Unityの構造上問題があるため、宴で解決することは困難です。
対策としてシェーダーを作成することで、CPUではなくGPU上でアウトラインを描画をするようにして、負荷を軽減できるようにしました。

アウトラインシェーダーの適用方法

アウトラインシェーダーはデフォルトでは設定されないため、必要に応じて手動で設定する必要があります。
ProjectWindowで「Material」を新規作成する。

作成したマテリアルのシェーダーに「Utage>UI>OutLine9Pass」を設定する。

作成したマテリアルをテキストコンポーネントに設定する。

UguiRichOutuineコンポーネントは削除する。

アウトラインの色や太さはマテリアルから設定する

アウトラインシェーダーの注意点

アウトラインシェーダーは、一度に描画される文字数が多い場合には有効ですが、UIのボタンのテキストなど細かいテキストがあちこちのオブジェクトにある場合、
バッチ処理が効かなくなる可能性があるので、かえって負荷が高くなる可能性があります。
また、内部で9パスを使って描画しているため、(あるのかわからないですが)マルチパス描画に制限があるデバイスがもしあった場合は、危険かもしれません。
そして、UguiRichOutlineと違って、コピーカウントは制御できません。
UguiRichOutlineでいうと、CopyCount=8に相当します。つまり、あまり太いアウトラインは描画できないということです。
シェーダーのパスを増やさないとコピーカウントは増やせないため、どうしても太いアウトラインが必要な場合は、シェーダーをコピーして新たに16パスや32パスのシェーダーを書くなどして対応してみてください。

TextMeshPro

Unityは、TextMeshProというのテキスト描画の拡張機能を用意しています。
これを使えば、上記のアウトラインや文字送りの問題もほぼ解決すると思われます。
一応、実験的にTextMeshProを表示するためのコンポーネントを用意しました。ダウンロード
通常の「AdvUguiMessageWindow」コンポーネントと入れ替えて使う形になります。

ただ、これは未完成で、いろいろと問題が残っています。
一応はTextMeshProでテキスト表示だけは可能になるのですが、宴の独自のタグ(ルビやダーシ)などは使えなくなってしまいます。
また、逆にTextMeshPro独自のタグが含まれしまった場合には、文字数のカウントができずに、文字送りなどで動作がおかしくなると思います。

そして、TextMeshProの根本的な問題として、あらかじめ決められた種類の文字のフォントデータを事前に作っておく必要があり、特に文字の種類が多いアジア圏では使いづらいという問題があります。
そのため、ノベルゲームのようなたくさんの文字を使うジャンルではまだ使いづらいと思われます。
この問題は、2019年以降に改善が計画されているようですが、まだ詳細は未定です。
そのため、正式に採用するかは検討中です。ほかにも多くの問題を解決する必要があるため、将来的にも採用が可能かは保証ができません。
採用するとしても、タグなど一部の機能の互換性はとれないかもしれません。