Unity小优化之美术字贴图合并以合批

Unity中的UV坐标系

Unity采用OpenGL的UV坐标系,原点在左下角。了解这点,帮助我们后续重新算合并贴图后字体的每个CharacterInfo中的UV坐标。
Unity小优化之美术字贴图合并以合批_第1张图片

重算每个CharacterInfo的UV

List CreateMergedTexture(List 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 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合成一个!

你可能感兴趣的:(Unity3D)