Unity小优化之美术字贴图合并以合批
Unity中的UV坐标系
Unity采用OpenGL的UV坐标系,原点在左下角。了解这点,帮助我们后续重新算合并贴图后字体的每个CharacterInfo中的UV坐标。
重算每个CharacterInfo的UV
List<Font> CreateMergedTexture(List<Font> fontList){
var toMergedTexs = fontList.Select(x=>x.material,mainTexture as Texture2D).ToArray();
Texture2D mergedTex = new Texture2D(256, 1024, TextureFormat.RGBA32, false);
MakeSureSrcTexReadableAndUncompressed(toMergedTexs);
Rect[] resultRects = mergedTex.PackTextures(toMergedTexs, 1, 1024);
return fontList;
}
void MakeSureSrcTexReadableAndUncompressed(Texture2D[] srcTexs){
foreach(var tex in srcTexs){
var path = AssetDatabase.GetAssetPath(tex);
var ti = (TextureImporter)TextureImporter.GetAtPath(path);
if(!ti) continue;
ti.isReadable = true;//必须是可读的
var ts = ti.GetDefaultPlatformTextureSettings();
ts.overridden = true;
//必须无压缩,否则会报错:Unsupported texture format-Texture2D::Encode to functions do not supported compressed texure formats
ts.format = TextureImporterFormat.RGBA32;
ti.SetPlatformTextureSettings(ts);//再把平台贴图设置赋给Importer才会生效
ti.SaveAndReimport();
}
}
//创建新的字体文件,并算出合并贴图后的UV坐标
void CreateNewFonts(List<Font> fontInfoList)
int fontIndex = 0;
foreach(var fontInfo infontInfoList){
var srcFont = fontInfo;
Font destFont = new Font{ material = mat};
float scaleInX = srcFont.material.mainTexture.weight / mergedMaterial.mainTexture.width;
float scaleInY = srcFont.material.mainTexture.height / mergedMaterial.mainTexture.height;
for(int characterInfoIndex = 0; characterInfoIndex < ;characterInfoIndex ++){
var ci = srcFont.characterInfo[characterInfoIndex];
CharacterInfo mergedCI = new CharacterInfo (){
index = ci.index,
advance = ci.advance,
bearing = ci.bearing,
glyphWidth = ci.glyphWidth ,
glyphHeight = ci.glyphHeight ,
};
float uv_x = resultRects[fontIndex].x + scaleInX * ci.uv.x;
float uv_y = resultRects[fontIndex].y + scaleInY * ci.uv.y;
float uv_w = scaleInX * ci.uv.width;
float uv_h = scaleInY * ci.uv.height;
mergedCI.uv = new Rect(uv_x, uv_y, uv_w, uv_h);
}
AssetDatabase.CreateAsset(destFont, outputPath);
AssetDatabase.SaveAssets();
fontIndex ++;
}
AssetDatabase.Refresh();
}
Object[] toMergedFonts = new Object[7];
Object saveFolder;
string saveRelativePath;
void OnGUI(){
toMergedFonts = EditorGUILayout.ObjectField("Merged Save Folder", saveFolder, typeof(Object), true);
if(saveFolder){
saveRelativePath = AssetDatabase.GetAssetPath(saveFolder);
GUILabel(saveRelativePath);
}
if(GUILayout.Button(Do Font Texture Merge)){
if(!string.isNullOrEmpty(saveRelativePath)) {
var fontList = CreateMergedTexture(toMergedFonts .Select(x=>x).Where(x=>x != null).ToList())
CreateNewFonts(fontList )
}
}
}
实现的几个核心要点
- Font的ASCII Start Offset没有setter,代码改不了,需要从0开始,不然在新的字体创建时index要统一加上这个offset
- 待合并的字体的贴图需要是无压缩的,不然会报错
- CharacterInfo中的x,y,w,h分别代表在UV中的x坐标,y坐标,宽度,高度
- 计算字体UV在合并后的大贴图中值:rectByPacked.x + scaleInPacked * characterInfo.uv.x(重点要乘以小图占大图的比重,Y轴类似)
效果
理论上可以将多个Batch合成一个!