MENU閉じる

HEXA BLOG

プログラム

HEXA BLOGプログラム2016.8.22

フォントのDistanceFieldTexture生成ツールをつくる

みなさんこんにちは。グリフォンです。

本日東京は台風に見舞われて服がびしょびしょです。

 

さて今回は真面目なお話です。

以前、デモプログラムの方で

【距離情報によるテクスチャ画像のベクトル化】-Distance Field Texture Vectorization-

というものを紹介しましたが、

つい先日、某プロジェクトで使うためにDistance Field Textureを作る必要が出てきました。

ただ用意するための期間があまり無かった為、今回はUnityを使用してDistance Field Texture生成ツールを作ってみました。

 

ゲームエンジンとして広く普及しているUnityですが、

色々なファイル読み込みに対応しているので、ちょっとしたツールを作るときも重宝します。

 

大まかな処理の流れは以下

フォントを1文字ずつ読み出してピクセル情報を取得

ピクセル情報からDistance Field情報を生成

CharacterInfoを生成

アトラステクスチャに書き込む

アトラステクスチャとFontSettingsを出力保存

 

 

今回はを説明していきます。

フォントを1文字ずつ読み出すために今回はUnity標準のuGUIを使用しました。

blog20160822_1

 

CanvasとTextとCameraが1つずつあるだけのシンプルなシーンです。

このTextに使用するフォントと文字サイズやスタイルなどを設定しておきます。

 

このシーンを再生して、Textに1文字ずつ文字を設定し、RenderTexture機能を使ってピクセル情報を取得します。

private IEnumerator GenerateCharacterTexture(string character)
{
  // 描画する文字を設定(1文字)
  _TextArea.text = character;

  // 文字の領域サイズを取得
  //  フォントによって正しくサイズが取得できない場合があるので、幅・高さの大きいほうで正方形にする。
  int width  = Mathf.CeilToInt(_TextArea.preferredWidth * _Param_QualityScale);
  int height = Mathf.Max(width, Mathf.CeilToInt(_TextArea.preferredHeight * _Param_QualityScale));
      width  = height;

  // 書き出しテクスチャ・レンダーテクスチャを領域サイズに合わせて生成
  _BufferTexture = new Texture2D(width, height, TextureFormat.ARGB32, false);
  _RenderTexture = new RenderTexture(width, height, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Default);
  _MainCamera.targetTexture = _RenderTexture;

  yield return 0;  // レンダーテクスチャが反映されるまでの待ち

  // キャンパスを強制更新
  Canvas.ForceUpdateCanvases();

  yield return 0;  // キャンバスを最新にするための待ち
    
  // レンダーテクスチャからピクセルを情報取得
  RenderTexture.active = _MainCamera.targetTexture;
  _BufferTexture.ReadPixels(new Rect(0, 0, width, height), 0, 0);
  _BufferTexture.Apply();
}

_TextArea が Textコンポーネントを設定したメンバ変数です。

_MainCamera も同じく Cameraコンポーネントを設定したメンバ変数。

_BufferTexture と _RenderTexture はそれぞれ Texture2D と RenderTexture 型のメンバ変数。

 

17行目では直前でCameraに設定したRenderTextureに描画するため次のフレームまで待ちます。

 

ここでuGUIの落とし穴がありました。

本来はこの時点でRenderTextureに描画されているハズですが、uGUIのコンポーネントは設定した内容が直ぐに反映されませんでした。

 

そこで20行目で Canvas.ForceUpdateCanvases() を呼んで明示的にCanvasを更新します。

その後、描画されるのを待ち次のフレームでようやくRenderTextureの内容が取得できるようになります。

これら2回の待ち時間は回避できないので120FPSなど高速処理することで対処するしかないです。

 

このあたりはuGUIの処理最適化などの影響だと思われますが、

通常のゲームでも即時でUIを更新する必要がある場合は参考にしてください。

 

 

今回はここまで。以降はまた次回をお楽しみに

RECRUIT

大阪・東京共にスタッフを募集しています。
特にキャリア採用のプログラマー・アーティストに興味がある方は下のボタンをクリックしてください

RECRUIT SITE