HEXA BLOG
ヘキサブログ
プログラム
フォントのDistanceFieldTexture生成ツールをつくる その2
みなさんこんにちは。グリフォンです。![]()
最近いっきに冷え込んできて、先週の土日は風邪で家から一歩も出れませんでした![]()
さて今回は前回の続き「フォントのDistanceFieldTexture生成ツールをつくる」のその2です。
大まかな処理の流れは以下![]()
フォントを1文字ずつ読み出してピクセル情報を取得
ピクセル情報からDistance Field情報を生成
CharacterInfoを生成
アトラステクスチャに書き込む
アトラステクスチャとFontSettingsを出力保存
今回は
を説明していきます。
private bool GenerateDistanceFieldTexture()
{
// 有効領域を切り出す
if( !ClippingValidRect() ) {
return false;
}
// 入力テクスチャ情報をバッファ
var srcPixels = _BufferTexture.GetPixels32();
var srcWidth = _BufferTexture.width;
var srcHeight = _BufferTexture.height;
// 出力用のテクスチャを生成
var dstWidth = srcWidth / _Param_QualityScale;
var dstHeight = srcHeight / _Param_QualityScale;
var DFTexture = new Texture2D(dstWidth, dstHeight, TextureFormat.ARGB32, false, false);
// 距離テクスチャを生成
var dstPixels = DFTexture.GetPixels32();
for( int y=0; y<dstHeight; ++y ) {
for( int x=0; x<dstWidth; ++x ) {
var srcCenterX = (x * _Param_QualityScale) + (_Param_QualityScale / 2);
var srcCenterY = (y * _Param_QualityScale) + (_Param_QualityScale / 2);
var distance = FindSignedDistance(srcCenterX, srcCenterY, srcWidth, srcHeight, srcPixels);
dstPixels[(y * dstWidth) + x] = new Color32(255, 255, 255, CalcDistanceToAlpha32(distance / _Param_SpreadDist));
}
}
DFTexture.SetPixels32(dstPixels);
DFTexture.Apply();
// 生成した距離テクスチャでバッファに上書き
_BufferTexture = DFTexture;
// 有効ピクセル情報追加
_regularCharsWidthSum += dstWidth;
_regularCharsHeightSum += dstHeight;
return true;
}
4行目の ClippingValidRect() は、
の処理のときに少し大きめなテクスチャにフォントをキャプチャしたので、ピクセル情報を調べて余計な余白を削除しています。
また、フォントに存在しない文字など全て空白の場合などは false としてスキップしています。
次に各種外部パラメータの説明です。
_Param_QualityScale は、より綺麗に距離テクスチャを生成するため、
『拡大してキャプチャ → 距離情報計算 → 縮小して保存 』 という手順を踏んでいるので、そのためのスケール値です。
_Param_SpreadDist は、境界からどの程度の距離を 0.0 ~ 1.0 にするかという閾値です。詳しくはこちらを見てください。
続いて、24行目の FindSignedDistance() では指定のピクセル位置から最近傍境界点までの距離を計算しています。
private float FindSignedDistance(int srcCenterX, int srcCenterY, int srcWidth, int srcHeight, Color32[] srcPixels)
{
var delta = _Param_SpreadDist * _Param_QualityScale;
var srcMinX = Mathf.Max(0, srcCenterX - delta);
var srcMinY = Mathf.Max(0, srcCenterY - delta);
var srcMaxX = Mathf.Min(srcWidth - 1, srcCenterX + delta);
var srcMaxY = Mathf.Min(srcHeight - 1, srcCenterY + delta);
var curInside = srcPixels[(srcCenterY * srcWidth) + srcCenterX].r;
var closestDistSq = delta * delta;
// 最近傍境界点までの距離を取得
for( int y=srcMinY; y<srcMaxY; ++y ) {
for( int x=srcMinX; x<srcMaxX; ++x ) {
if( curInside != srcPixels[(y * srcWidth) + x].r ) {
var distSq = CalcDistSq(srcCenterX, srcCenterY, x, y);
if( distSq < closestDistSq ) {
closestDistSq = distSq;
}
}
}
}
// 二乗距離を変換して符号判定する
var closestDist = Mathf.Sqrt((float)closestDistSq) / _Param_QualityScale;
closestDist = Mathf.Min(closestDist, _Param_SpreadDist);
if( 0 == curInside ) {
// 白で描画しているので、検索ピクセルが黒の場合は符号を反転
closestDist = -closestDist;
}
return closestDist;
}
これらの処理で注意することは、ソーステクスチャより結果テクスチャのほうが _Param_QualityScale の分、小さくなるということです。
このスケール値が大きくなれば、より綺麗になりますが計算負荷が増し時間が掛かります。
スマホのゲームなどで使用する分には8倍くらいが費用対効果として妥協点かと思います。
※第2水準まで8000文字弱を処理したときは10分程度かかりました。
今回はここまで。
以降はまた次回をお楽しみに![]()
CATEGORY
- about ヘキサ (166)
- 部活動 (6)
- CG (18)
- プロジェクトマネジメント (1)
- 研修 (5)
- 美学 (1)
- いいモノづくり道 (227)
- 採用 -お役立ち情報も- (149)
- プログラム (189)
- デザイン (99)
- ゲーム (273)
- 日記 (1,104)
- 書籍紹介 (113)
- その他 (889)
- 就活アドバイス (20)
- ラーメン (3)
- ライフハック (25)
- イベント紹介 (10)
- 料理 (23)
- TIPS (7)
- 怖い話 (3)
- サウンド (6)
- 子育て (1)
- 筋トレ (1)
- NicO (3)
- MakeS (9)
- 商品紹介 (21)
- アプリ紹介 (31)
- ソフトウェア紹介 (33)
- ガジェット紹介 (12)
- サイト紹介 (10)
- 研究・開発 (35)
- 回路図 (4)
- アナログゲーム (40)
- 交流会 (21)
- 報告会 (3)
- インフラ (25)
- グリとブラン (6)
- カメラ (9)
- クラフト (27)
- 部活 (14)
- 画伯 (15)
- カレー (6)
- 音楽(洋楽) (6)
- 映画・舞台鑑賞 (43)
- 飼育 (5)
- いぬ (8)
- ねこ (19)
ARCHIVE
- 2025年
- 2024年
- 2023年
- 2022年
- 2021年
- 2020年
- 2019年
- 2018年
- 2017年
- 2016年
- 2015年
- 2014年
- 2013年
- 2012年
- 2011年
- 2010年
- 2009年
- 2008年
- 2007年




