首页 > 其他分享 >使用图集Atlas创建Fnt文件的工具

使用图集Atlas创建Fnt文件的工具

时间:2024-04-29 22:22:05浏览次数:28  
标签:Fnt Sprite int var fnt Atlas EditorGUILayout public 图集

fnt文件生成unity字体的原理其实就是渲染图集Atlas上的Sprite,这边直接利用Unity自带的图集工具生成fnt文件

注意:这里生成的fnt文件还没发直接用,因为没有关联字符,这个工具只是第1步,要配合Fnt编辑工具一起使用

 

public class SpriteToFntTool : EditorWindow
{

    [MenuItem("MyTools/Sprite To Fnt", false, 100)]
    private static void ShowWindow()
    {
        var wnd = GetWindow<SpriteToFntTool>(false, "SpriteToFnt");
    }

    private Vector2 m_ScrollPos = new Vector2(0, 0);
    private GUIContent m_TempLabelContent = new GUIContent();
    private Sprite m_Sprite;

    private void OnGUI()
    {
        GUILayout.Space(6);
        float labelWidthBak = EditorGUIUtility.labelWidth;

        if (null == m_Sprite)
            EditorGUILayout.HelpBox($"请先选择一个设置了Packing Tag的Sprite", MessageType.Warning);
        
        EditorGUILayout.BeginHorizontal();
        m_TempLabelContent.text = "Sprite: ";
        EditorGUIUtility.labelWidth = GUI.skin.label.CalcSize(m_TempLabelContent).x + 2;
        EditorGUILayout.PrefixLabel("Sprite:");

        m_Sprite = EditorGUILayout.ObjectField(m_Sprite, typeof(Sprite), false) as Sprite;
        EditorGUILayout.EndHorizontal();

        if (null != m_Sprite)
        {
            if (GUILayout.Button("刷新Packer图集"))
            {
                EditorUtility.DisplayProgressBar("RebuildAtlasCacheIfNeeded...", "RebuildAtlasCacheIfNeeded...", 0);
                Packer.RebuildAtlasCacheIfNeeded(EditorUserBuildSettings.activeBuildTarget, true, Packer.Execution.ForceRegroup);
                EditorUtility.ClearProgressBar();
            }
            Packer.GetAtlasDataForSprite(m_Sprite, out var packTag, out var atlasTex);

            var spFilePath = AssetDatabase.GetAssetPath(m_Sprite);
            var spFolderPath = Path.GetDirectoryName(spFilePath);
            if (null != atlasTex)
            {
                EditorGUILayout.LabelField($"所选Sprite的Packing Tag: {packTag}");
                EditorGUILayout.LabelField($"Sprite所在文件夹:{spFolderPath}");
                EditorGUILayout.LabelField("图集贴图:");
                GUILayout.Label(atlasTex, GUILayout.MaxHeight(120));
                GUILayout.Space(10);
                if (!EditorApplication.isPlaying)
                {
                    EditorGUILayout.HelpBox("请先运行Editor, 非运行状态无法获取到Packer图集的精灵信息", MessageType.Warning);
                    GUI.enabled = false;
                }

                EditorGUILayout.BeginHorizontal();
                if (GUILayout.Button($"  生成{packTag}.fnt  "))
                {
                    CreateFntFile(packTag, atlasTex, spFolderPath);
                }
                GUI.enabled = true;
                GUILayout.Space(10);

                if (GUILayout.Button($"  生成{packTag}.png  "))
                {
                    var pngFileName = $"{packTag}.png";
                    var pngFilePath = Path.Combine(spFolderPath, pngFileName);
                    ExportTexture(pngFilePath, atlasTex);
                    AssetDatabase.ImportAsset(pngFilePath); //不存在则不需要导入
                    AssetDatabase.Refresh();
                }

                GUILayout.FlexibleSpace();
                EditorGUILayout.EndHorizontal();
            }
        }

        EditorGUIUtility.labelWidth = labelWidthBak;
        GUILayout.Space(6);
    }

    private static void CreateFntFile(string packingTag, Texture2D fntTex, string spFolderPath)
    {
        var fntFilePath = Path.Combine(spFolderPath, $"{packingTag}.fnt");
        if (File.Exists(fntFilePath))
        {
            if (!EditorUtility.DisplayDialog("文件已存在", $"是否覆盖{fntFilePath}?", "Yes", "No"))
                return;
        }

        Fnt fnt = new Fnt();
        fnt.texWidth = fntTex.width;
        fnt.texHeight = fntTex.height;
        fnt.file = $"{packingTag}.png";

        var pngFiles = Directory.GetFiles(spFolderPath, "*.png", SearchOption.TopDirectoryOnly);
        int charCnt = 0;
        int maxHeight = 0;
        foreach (var pngFile in pngFiles)
        {
            var pngIMP = AssetImporter.GetAtPath(pngFile) as TextureImporter;
            if (pngIMP.spritePackingTag != packingTag)
                continue;

            var sp = AssetDatabase.LoadAssetAtPath<Sprite>(pngFile);
            FntChar fntChar = new FntChar();
            fnt.charsList.Add(fntChar);

            var texRect = sp.textureRect;
            fntChar.w = (int)texRect.width;
            fntChar.h = (int)texRect.height;
            fntChar.x = (int)texRect.x;
            fntChar.y = fntTex.height - (int)texRect.y - fntChar.h; //fnt中的x, y为左上角, 以贴图左上角为(0, 0)
            maxHeight = Mathf.Max(maxHeight, fntChar.h);
            fntChar.xadv = fntChar.w;
            charCnt++;
        }

        fnt.fontSize = maxHeight;
        fnt.lineHeight = maxHeight;
        fnt.baseLine = (int)(maxHeight * 0.9f);

        using (StreamWriter sw = new StreamWriter(fntFilePath, false, Encoding.UTF8))
        {
            sw.WriteLine($"info face=\"Art\" size={fnt.fontSize}");
            sw.WriteLine($"common lineHeight={fnt.lineHeight} base={fnt.baseLine} scaleW={fnt.texWidth} scaleH={fnt.texHeight} pages=1");
            sw.WriteLine($"page id=0 file=\"{fnt.file}\"");
            sw.WriteLine($"chars count={fnt.charsList.Count}");
            foreach (var c in fnt.charsList)
            {
                sw.WriteLine($"char id={c.id} x={c.x} y={c.y} width={c.w} height={c.h} xoffset={c.xoff} yoffset={c.yoff} xadvance={c.xadv}");
            }
        }

        AssetDatabase.ImportAsset(fntFilePath);
        AssetDatabase.Refresh();
    }

    static void ExportTexture(string outFilePath, Texture tex)
    {
        var tempRT = RenderTexture.GetTemporary(tex.width, tex.height, 0, RenderTextureFormat.ARGB32);
        Graphics.SetRenderTarget(tempRT);
        Graphics.Blit(tex, tempRT);

        var resultTex = new Texture2D(tex.width, tex.height, TextureFormat.RGBA32, false);
        resultTex.ReadPixels(new Rect(0, 0, tex.width, tex.height), 0, 0);
        resultTex.Apply();

        var bytes = resultTex.EncodeToPNG();

        Graphics.SetRenderTarget(null);
        RenderTexture.ReleaseTemporary(tempRT);

        File.WriteAllBytes(outFilePath, bytes);
    }

}

 

public class Fnt
{
    public int fontSize = 22; //字体大小
    public int lineHeight = 22; //行高
    public int baseLine = 20; //基线位置
    public int texWidth = 512; //贴图宽度
    public int texHeight = 256; //贴图高度
    public string file = ""; //贴图名字

    public List<FntChar> charsList = new List<FntChar>();
}

public class FntChar
{
    public string ch = ""; //对应字符
    //unicode码
    public int id;

    //在贴图上的坐标(左上角), 相对贴图左上角
    public int x;
    public int y;
    //在贴图上的宽高
    public int w;
    public int h;

    //排版修正
    public int xoff;
    public int yoff;
    //排版宽度
    public int xadv;
}

 

标签:Fnt,Sprite,int,var,fnt,Atlas,EditorGUILayout,public,图集
From: https://www.cnblogs.com/sailJs/p/18166751

相关文章

  • SpriteAtlas图集导出工具
      publicclassSpriteAtlasExportTool:EditorWindow{conststringMenuItemPath_ExportSelectSpriteAtlas="MyTools/ExportSelectSpriteAtlas";[MenuItem(MenuItemPath_ExportSelectSpriteAtlas,true)]privatestaticboolMenuItemV......
  • drf : 通用视图类和(GenericAPIView)5个视图扩展类,九个视图子类,视图集。
    视图RESTframework提供了众多的通用视图基类与扩展类,以简化视图的编写。APIViewrest_framework.views.APIViewAPIView是RESTframework提供的所有视图的基类,继承自Django的View父类。GenericAPIView使用[通用视图类]继承自APIVIew,主要增加了操作序列化器和数据库查询的方......
  • 国产AI训练卡,对标美国NVIDIA公司的A100,华为昇腾Atlas 300T A2(Ascend 910B4)高性能GPU/N
    ChinahassuccessfullyachievedthelocalizationofAIchips,breakingthroughthetechnologicalrestrictionsimposedbytheU.S.governmentandrealizingindependentdesignandproductionofdomesticAIchips.Huawei'sAscend910modelAIchiphass......
  • 华为Atlas 200DK环境搭建&推理测试
    引子前文已经有一篇,华为服务器Atlas芯片的文章(https://www.cnblogs.com/nick-algorithmer/p/17943216)。熟悉AI的同学们一定知道,除了服务器端端训练推理。AI推理还有一部分是边端推理,各大芯片厂商都有推出边端推理芯片,凑巧,拿到一个一块很老的华为Atlas200DK板子,那就倒腾下这......
  • ue4.26 CurveLinearColorAtlas支持非正方形尺寸
    默认CurveAtlas只能是正方形 改代码可以让它支持非正方形: 改法如下:CurveLinearColorAtlas.h//CopyrightEpicGames,Inc.AllRightsReserved.#pragmaonce#include"CoreMinimal.h"#include"UObject/ObjectMacros.h"#include"UObject/Object.h"#in......
  • Atlassian 停服 Bitbucket?三步快速迁移至极狐GitLab
    之前的文章Jira母公司全面停服Server产品,用户如何迁移至极狐GitLab提到了Atlassian将在2月15日以后停止对Server端产品的服务支持,此后用户将无法像之前一样继续使用Jira、Bitbucket、Bamboo、Confluence这些产品了。如果用户想要继续使用这些产品,就需要迁移到Atlass......
  • Atlassian 停服 Bamboo,CI/CD 用不了了?教你快速迁移到极狐GitLab CI
    Atlassian表示,将在2024年2月,终止对于旗下所有服务器端产品(Serverproducts)的支持。随着这个时间节点的逐渐临近。那些依赖于私有化部署了Atlassian服务端产品的用户来说,面临着抉择:要么升级到Atliassian的数据中心或者云产品来继续使用Atliasian的产品,要么寻找替代产品......
  • Atlas初步调研
    简介Atlas是Hadoop生态的元数据管理框架,有以下功能特性:元数据类型:支持多种Hadoop和非Hadoop元数据的预定义类型,提供元数据定义新类型的能力,类型可以具有原始属性、复杂属性、对象引用,可以从其他类型继承。分类:提供动态创建分类的能力,元数据实体可以与多个分类相关联,具有分类传......
  • 视图集ModelViewSet drf之路由 认证组件
    视图集ModelViewSetModelViewSet-视图类:GenericAPIView(继承)-路由映射:listcreateretrieveupdatedestroy继承5个视图扩展类:CreateModelMixin,ListModelMixin,UpdateModelMixin,DestroyModelMixin,RetrieveModelMixin-路由写法改变:ViewSetMixin只要继承它,路由写法就......
  • drf之视图集类、5个视图扩展类、9个视图子类、视图集
    两个视图基类#APIView--->之前一直在用---》drf提供的最顶层的父类---》以后所有视图类,都继承自它#GenericAPIView--》继承自APIView--》封装继承APIView+序列化类+Response写接口APIView是RESTframework提供的所有视图的基类,继承自Django的View父类。APIView与View的不......