【Unity编辑器扩展】SpriteAltas资源一键转换为TMP_SpriteAsset或Sprite图集

【Unity编辑器扩展】艺术字/自定义图片字体/TextMeshPro艺术字生成工具_unity 艺术字-CSDN博客

 博文工具源码见GF_X自动化游戏开发框架:GitHub - sunsvip/GF_X: Unity GameFramework + HybridCLR,Includes several automated editor extension tools, an efficient automated development workflow.(大量自动化编辑器扩展工具, 高效的自动化开发工作流)

 前面博文中介绍过把Sprite图集转换为艺术字的工具,但是通过Unity的Sprite Editor自动划分子Sprite的Rect会有偏差,就需要手动调整Rect,用户体验很差。如果能支持SpriteAtlas,就可以直接把艺术字碎图打成SpriteAtlas,这样就能更好的划分Sprite Rect。

而Text Mesh Pro创建TMP_SpriteAsset资源也很鸡肋(如下图),自己的SpriteAtlas图集功能不用,非要依赖第三方Texture Packer图集。

为了解决上述痛点,需要实现两个编辑器扩展功能:

1. 把SpriteAtlas资源直接转换为TMP_SpriteAsset;

2. 把SpriteAtlas资源转换为普通的Sprite图集(Sprite Multiple);

功能实现:

首先通过右键Create->2D->Sprite Atlas创建一个SpriteAtlas资源,然后把碎图拖到SpriteAtlas中:

一,SpriteAtlas转换为TMP_SpriteAsset:

 首先看看TMP_SpriteAsset需要哪些信息:

①. 需要一张图集Texture2D和一个材质;

②. Sprite Character Table,也就是图片映射的字符Unicode、name。TextMeshPro输入字符的Unicode在Sprite Character Table中存在时就会显示对应的Sprite。 而name的作用就是可以通过服富文本标签显示name对应的Sprite:<sprite="sprite_name">

③. Sprite Glyph Table, 也就是Sprite在图集Texture2D中的像素rect区域。

1. SpriteAtlas资源转Texture2D: 

首先要把SpriteAtlas资源生成为一张贴图给TMP_SpriteAsset的材质使用,从SpriteAtlas的Inspector面板可以看到Pack Preview按钮就可以生成图集贴图,所以Unity内部应该是提供了现成接口的。

 通过Unity开源代码就可以快速查到UnityEditor.U2D.SpriteAtlasExtensions有个非公开的静态扩展方法GetPreviewTextures,返回值为Texture2D[],即SpriteAltas每个子图集作为一张Texture。

用法:

var getPreviewFunc = typeof(UnityEditor.U2D.SpriteAtlasExtensions).GetMethod("GetPreviewTextures", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
Texture2D[] previews = getPreviewFunc.Invoke(null, new object[] { atlas }) as Texture2D[];

 但是这里有个问题,通过SpriteAtlasExtensions.GetPreviewTextures拿到的都是压缩过的贴图,并且贴图数据是在一片不可读内存上,不能直接使用EncodeToPNG解码保存为png文件。所以我们需要通过Graphics接口把贴图复制出来:

var atlasTex2d = previews[0];
RenderTexture rt = new RenderTexture(atlasTex2d.width, atlasTex2d.height, 0);
Graphics.Blit(atlasTex2d, rt);
RenderTexture.active = rt;

Texture2D readableAtlasTex = new Texture2D(rt.width, rt.height);
readableAtlasTex.alphaIsTransparency = true;
readableAtlasTex.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0);
readableAtlasTex.Apply();
RenderTexture.active = null;

2. 解析SpriteAltas的碎图并映射到TMP_SpriteAsset的spriteGlyphTable:

Sprite[] sprites = new Sprite[atlas.spriteCount];
atlas.GetSprites(sprites);
TMP_SpriteAsset spriteAsset;
if (File.Exists(tmpSpriteAssetName))
{
    spriteAsset = AssetDatabase.LoadAssetAtPath<TMP_SpriteAsset>(tmpSpriteAssetName);
}
else
{
    spriteAsset = ScriptableObject.CreateInstance<TMP_SpriteAsset>();
    AssetDatabase.CreateAsset(spriteAsset, tmpSpriteAssetName);
}
spriteAsset.spriteSheet = AssetDatabase.LoadAssetAtPath<Texture2D>(textureFileName);
spriteAsset.spriteCharacterTable.Clear();
spriteAsset.spriteGlyphTable.Clear();
if (spriteAsset.material == null)
{
    Material material = new Material(Shader.Find("TextMeshPro/Sprite"));
    material.mainTexture = spriteAsset.spriteSheet;
    AssetDatabase.AddObjectToAsset(material, spriteAsset);
    AssetDatabase.SaveAssetIfDirty(spriteAsset);
    spriteAsset.material = material;
}

for (int i = 0; i < sprites.Length; i++)
{
    var sp = sprites[i];
    var spUVRect = sp.textureRect;
    var glyph = new TMP_SpriteGlyph((uint)i, new UnityEngine.TextCore.GlyphMetrics(spUVRect.width, spUVRect.height, 0, spUVRect.height, spUVRect.width),
    new UnityEngine.TextCore.GlyphRect(spUVRect), 1, 0);
    spriteAsset.spriteGlyphTable.Add(glyph);
    var spChar = new TMP_SpriteCharacter(0xFFFE, glyph);
    spChar.name = sp.name;
    spriteAsset.spriteCharacterTable.Add(spChar);
}
AssetDatabase.SaveAssetIfDirty(spriteAsset);

 SpriteAltas一键转换为TMP_SpriteAsset功能预览:

二, SpriteAltas转换为Sprite Multiple:

也就是通过程序一键把SpriteAltas转换为图集贴图,并自动分割好碎图区域,如下图:

 而我们的艺术字生成工具正好依赖这种分割好的图集,也就间接实现了对碎图的支持,不用依赖Texture Packer等三方图集工具;

功能实现:

前面已经示例了SpriteAltas转为Texture,剩下只需要把Texture类型改成Sprite,Sprite Mode改为Multiple,然后把SpriteAltas碎图Rect映射过来即可:

1. 获取SpriteAtlas所有碎图的Rect信息:

static SpriteRect[] GetSpriteRects(SpriteAtlas atlas)
{
    if (atlas == null || atlas.spriteCount == 0) return null;

    Sprite[] sprites = new Sprite[atlas.spriteCount];
    atlas.GetSprites(sprites);

    SpriteRect[] spriteRects = new SpriteRect[sprites.Length];
    var spNameTrim = "(Clone)".ToCharArray();
    for (int i = 0; i < sprites.Length; i++)
    {
        var sp = sprites[i];
        spriteRects[i] = new SpriteRect()
        {
            name = sp.name.Trim(spNameTrim),
            rect = sp.textureRect
        };
    }
    return spriteRects;
}

2. 根据碎图的Rect信息自动划分:

TextureImporter texImporter = TextureImporter.GetAtPath(textureFileName) as TextureImporter;
var factory = new SpriteDataProviderFactories();
factory.Init();
var dataProvider = factory.GetSpriteEditorDataProviderFromObject(texImporter);
dataProvider.InitSpriteEditorDataProvider();
dataProvider.SetSpriteRects(GetSpriteRects(atlas));
dataProvider.Apply();
texImporter.SaveAndReimport();

 SpriteAltas一键转为Sprite Multiple功能预览:

源码获取:GF_X/Assets/AAAGame/ScriptsBuiltin/Editor/Common/RightClickMemus/RightClickMenuExtension.SpriteAtlasTools.cs at master · sunsvip/GF_X · GitHub 

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值